unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
@ 2019-03-27 15:38 Daniel Pittman
  2019-03-27 15:55 ` Michael Albinus
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Pittman @ 2019-03-27 15:38 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2918 bytes --]

G'day.  In HEAD, tramp-sh has some optimizations in place for the
`vc-registered` operation, intended to minimize the number of round trips.
Sadly, these don't seem to be safe in a single threaded Emacs world, and
even less safe in a threaded one.

The function `tramp-sh-handle-vc-registered` attempts to optimize the
process by emplacing a separate file-name-handler, running the
operation(s), then performing a single remote call to obtain all the data.

This is an optimization, no doubt, and would be great ... except that it
assumes a synchronous operation where no other code can run while the new
file handler is in effect.  This is, sadly, not the case.

The observable symptom is that we hit this error throw in
`tramp-dissect-file-name`:
(tramp-user-error nil "Not a Tramp file name: \"%s\"" name)

The most common place I observed this was during startup, when it
complained that the `nsm-settings-file`, which is the default value in my
case, was not a TRAMP filename.  It also happens for expanding `~`, and a
handful of other cases, when I was reverting tramp buffers, etc.

On debugging I discovered that the problems were springing from calls
something akin to this:
(let ((default-directory "/ssh:slippycheeze@example.com:/tmp"))
  (expand-file-name "~" default-directory))

That uses, via `tramp-vc-file-name-handler`,
`tramp-file-name-for-operation`, which in the case of `expand-file-name`
returns "~".  I believe that is correct, but if not, that may be the root
cause of the problem.

In any case, that is then passed to `tramp-dissect-file-name` by
`tramp-vc-file-name-handler`, and (definitely correctly) triggers the error
that a non-tramp filename is being parsed.

This triggered from an async lisp callback firing, while the current buffer
happened to be on tramp.  The previously mentioned `nsm-settings-file` is
referenced when an async update of ELPA package lists – triggered in my
init.el file – is running, and desktop.el is busy reloading my buffers,
including the ones via tramp.

So, basically, the optimization would work great if only we never called
any lisp code asynchronously to it – but we do, and that is probably made
more visible when I'm using an ssh-backed method to talk to a machine ~
250ms away from my Emacs instance than when it is ~ 25ms away.  A bigger
race, where TRAMP is waiting for data from an external process, and so
other external processes can also fire.

I don't have a patch, but I'll see if I can figure out how to improve
this.  I fear the situation is impossible, however, and that this attempt
to improve the performance of `vc-registered` is doomed to failure unless
an async protocol is defined to replace the current, synchronous, version.

I also cannot say if the problem extends beyond `expand-file-name`, but it
probably hits at minimum anything else that canonicalizes paths.

[-- Attachment #2: Type: text/html, Size: 3409 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
  2019-03-27 15:38 TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations Daniel Pittman
@ 2019-03-27 15:55 ` Michael Albinus
  2019-03-27 16:22   ` Daniel Pittman
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Albinus @ 2019-03-27 15:55 UTC (permalink / raw)
  To: Daniel Pittman; +Cc: emacs-devel

Daniel Pittman <slippycheeze@google.com> writes:

Hi Daniel,

> I don't have a patch, but I'll see if I can figure out how to improve
> this.  I fear the situation is impossible, however, and that this
> attempt to improve the performance of `vc-registered` is doomed to
> failure unless an async protocol is defined to replace the current,
> synchronous, version.

Thanks for the very thourogh report, much appreciated! I will check in
parallel to you what could be done.

There exists a branch in the git repo, "feature/tramp-thread-safe". This
could solve the issue, if "async", as you've said, means Emacs
threads. Tramp uses mutexes, which should protect its
asynchrosity. However, the work on this branch is stalled due to serious
problems I'm not able to solve myself.

If you mean something else with "async", then we need even another approach.

Best regards, Michael.



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
  2019-03-27 15:55 ` Michael Albinus
@ 2019-03-27 16:22   ` Daniel Pittman
  2019-03-27 17:49     ` Michael Albinus
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Pittman @ 2019-03-27 16:22 UTC (permalink / raw)
  To: Michael Albinus; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3361 bytes --]

On Wed, Mar 27, 2019 at 3:55 PM Michael Albinus <michael.albinus@gmx.de>
wrote:

> Daniel Pittman <slippycheeze@google.com> writes:
>
> > I don't have a patch, but I'll see if I can figure out how to improve
> > this.  I fear the situation is impossible, however, and that this
> > attempt to improve the performance of `vc-registered` is doomed to
> > failure unless an async protocol is defined to replace the current,
> > synchronous, version.
>
> Thanks for the very thourogh report, much appreciated! I will check in
> parallel to you what could be done.
>

No problem.


> There exists a branch in the git repo, "feature/tramp-thread-safe". This
> could solve the issue, if "async", as you've said, means Emacs
> threads. Tramp uses mutexes, which should protect its
> asynchrosity. However, the work on this branch is stalled due to serious
> problems I'm not able to solve myself.
>
> If you mean something else with "async", then we need even another
> approach.


Sorry, this response turned out long.  I'm afraid I haven't the time to
condense further, but a summary: threads are not necessary, I believe, and
so we should disable this optimization for now, then bring it back if it is
provably safe.

The long form with analysis and so forth:

I believe that threads are not necessary: Emacs can dispatch, for example,
any timer, network connection, or external process, callback when it enters
the main wait loop.  Since tramp is going there while it awaits feedback
from the remote system (as far as I understand both modern tramp, and the
event loop) then it can enter essentially arbitrary code.

So, if it blocked any other file operations that'd be a deadlock if the
code – for example, the buffer and network connection for `(url-retrieve "
http://example.com" (lambda (&rest uh-oh) ...))` could call into anything,
which in the case of, eg, the package.el system fetching an update to the
package list, anticipates being able to write the file locally.

I'm confident it was possible to have arbitrary callbacks like that trigger
while tramp was awaiting remote data a decade or so ago, when I was last
working on it.  I presume, but can't be certain, that this remains true
today, so most of my concrete analysis comes with "I believe, but could be
wrong" attached.  It doesn't seem to have changed, though.

My best guess is that we should disable that optimization for now, and if
desirable, reapproach it.

One possibly functional strategy, but that I have not considered all
possible angles of, might be to fetch the path and then if `(not
(tramp-file-name-p ...))` dispatch to the original file name handlers.  I
think that would absolutely work as long as none of those callbacks
interacted with a tramp path at all, and it .... might, but probably
wouldn't, if they did.

Historically, I attached a tramp operation to copy the generated
server(-start) key to a remote tramp path, since I used a TCP listener, ssh
forwarding, and that shared secret to allow remote emacsclient to work.
That could have triggered at any point after tramp reconnected, as it
advised a fairly low level tramp function.  I'm not sure how common (or
cared about) that sort of nastly hack is, but I'm not confident that more
legitimate ways to do the same could be in use in the wild.

[-- Attachment #2: Type: text/html, Size: 4249 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
  2019-03-27 16:22   ` Daniel Pittman
@ 2019-03-27 17:49     ` Michael Albinus
  2019-03-29 12:36       ` Daniel Pittman
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Albinus @ 2019-03-27 17:49 UTC (permalink / raw)
  To: Daniel Pittman; +Cc: emacs-devel

Daniel Pittman <slippycheeze@google.com> writes:

Hi Daniel,

> My best guess is that we should disable that optimization for now, and
> if desirable, reapproach it.

Before doing this, I'd like to check whether there is a simple solution.

> One possibly functional strategy, but that I have not considered all
> possible angles of, might be to fetch the path and then if `(not
> (tramp-file-name-p ...))` dispatch to the original file name handlers.
>  I think that would absolutely work as long as none of those callbacks
> interacted with a tramp path at all, and it .... might, but probably
> wouldn't, if they did.

In your initial message you've said, that the problem happened inside
tramp-vc-file-name-handler. Is this always the case? If yes, I could
simply catch errors inside this function, and in case of, throw away all
results. This would fall back to the non-optimized solution by default.

Since I cannot reproduce the problem (yet), do you have a backtrace?
Setting tramp-verbose to 10 would suffice, because with this verbosity,
any error triggers Tramp to write the backtrace into the debug buffer.

> Historically, I attached a tramp operation to copy the generated
> server(-start) key to a remote tramp path, since I used a TCP
> listener, ssh forwarding, and that shared secret to allow remote
> emacsclient to work.  That could have triggered at any point after
> tramp reconnected, as it advised a fairly low level tramp function.
> I'm not sure how common (or cared about) that sort of nastly hack is,
> but I'm not confident that more legitimate ways to do the same could
> be in use in the wild.

Sorry, I don't follow here :-( How is this related?

Best regards, Michael.



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
  2019-03-27 17:49     ` Michael Albinus
@ 2019-03-29 12:36       ` Daniel Pittman
  2019-03-29 17:03         ` Michael Albinus
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Pittman @ 2019-03-29 12:36 UTC (permalink / raw)
  To: Michael Albinus; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 59303 bytes --]

On Wed, Mar 27, 2019 at 5:49 PM Michael Albinus <michael.albinus@gmx.de>
wrote:

> Daniel Pittman <slippycheeze@google.com> writes:
>
> In your initial message you've said, that the problem happened inside
> tramp-vc-file-name-handler. Is this always the case? If yes, I could
> simply catch errors inside this function, and in case of, throw away all
> results. This would fall back to the non-optimized solution by default.
>

As far as I can tell, yes, that is correct.  In addition to caching errors,
testing if the filename returned is actually a tramp filename and aborting
on that would also work, as far as I can tell.


> Since I cannot reproduce the problem (yet), do you have a backtrace?
>

Sure, please see it follow.  I have censored the content of a small number
of strings, but this is replacing a standard ASCII letter with 'X' so
should have no semantic effect.  Sorry to have to do that.  Fair warning,
it is ... long.

This actually has multiple backtraces, because the error causing process
triggers while displaying the first error, but I included everything
because truth in advertising or something.

The most interesting part is at the very start, where my `revert-file`
operation on a remote file triggers a `vc-refresh-state`, which ends up
causing `tramp-send-string` to run `process-send-string`, and then a timer
fires that drives the "deferred" third party library [1] to move on to
running a background command, using the timeout(1) and p4(1) binaries to
grab some state information.

That p4 call is driven from some internal code here at Google, but I don't
think it is mandatory: as you know, if the timer fires, any code attached
to the timer could fire, and make the same calls.

Anyway, once you skip over the deferred code, you get to:

apply(start-process "*deferred:*/usr/bin/timeout*:41" "
*deferred:*/usr/bin/timeout*:41" "/usr/bin/timeout" ("1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info"))

That in term, a few steps later calls make-process, and that calls

  tramp-vc-file-name-handler(expand-file-name "~"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")

...and there we have our problem start.

[1] https://github.com/kiwanami/emacs-deferred

  backtrace()
  tramp-error(nil user-error "Not a Tramp file name: \"%s\"" "~")
  apply(tramp-error nil user-error "Not a Tramp file name: \"%s\"" "~")
  tramp-user-error(nil "Not a Tramp file name: \"%s\"" "~")
  (if (tramp-tramp-file-p name) nil (tramp-user-error nil "Not a Tramp file
name: \"%s\"" name))
  (unless (tramp-tramp-file-p name) (tramp-user-error nil "Not a Tramp file
name: \"%s\"" name))
  (progn (unless (tramp-tramp-file-p name) (tramp-user-error nil "Not a
Tramp file name: \"%s\"" name)) (if (not (string-match (nth 0
tramp-file-name-structure) name)) (error "`tramp-file-name-structure'
didn't match!") (let ((method (match-string (nth 1
tramp-file-name-structure) name)) (user (match-string (nth 2
tramp-file-name-structure) name)) (host (match-string (nth 3
tramp-file-name-structure) name)) (localname (match-string (nth 4
tramp-file-name-structure) name)) (hop (match-string (nth 5
tramp-file-name-structure) name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain
(match-string 2 user) user (match-string 1 user)))) (when host (when
(string-match tramp-host-with-port-regexp host) (setq port (match-string 2
host) host (match-string 1 host))) (when (string-match
tramp-prefix-ipv6-regexp host) (setq host (replace-match "" nil t host)))
(when (string-match tramp-postfix-ipv6-regexp host) (setq host
(replace-match "" nil t host)))) (unless nodefault (when hop (setq v
(tramp-dissect-hop-name hop) hop (and hop (tramp-make-tramp-hop-name v))))
(let ((tramp-default-host (or ... tramp-default-host))) (setq method
(tramp-find-method method user host) user (tramp-find-user method user
host) host (tramp-find-host method user host) hop (and hop (format-spec hop
...))))) (prog1 (setq v (make-tramp-file-name :method method :user user
:domain domain :host host :port port :localname localname :hop hop)) (when
(and hop (or (not ...) (tramp-get-method-parameter v ...)))
(tramp-user-error v "Method `%s' is not supported for multi-hops."
method))))))
  (unwind-protect (progn (unless (tramp-tramp-file-p name)
(tramp-user-error nil "Not a Tramp file name: \"%s\"" name)) (if (not
(string-match (nth 0 tramp-file-name-structure) name)) (error
"`tramp-file-name-structure' didn't match!") (let ((method (match-string
(nth 1 tramp-file-name-structure) name)) (user (match-string (nth 2
tramp-file-name-structure) name)) (host (match-string (nth 3
tramp-file-name-structure) name)) (localname (match-string (nth 4
tramp-file-name-structure) name)) (hop (match-string (nth 5
tramp-file-name-structure) name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain
(match-string 2 user) user (match-string 1 user)))) (when host (when
(string-match tramp-host-with-port-regexp host) (setq port (match-string 2
host) host (match-string 1 host))) (when (string-match
tramp-prefix-ipv6-regexp host) (setq host (replace-match "" nil t host)))
(when (string-match tramp-postfix-ipv6-regexp host) (setq host
(replace-match "" nil t host)))) (unless nodefault (when hop (setq v
(tramp-dissect-hop-name hop) hop (and hop ...))) (let ((tramp-default-host
...)) (setq method (tramp-find-method method user host) user
(tramp-find-user method user host) host (tramp-find-host method user host)
hop (and hop ...)))) (prog1 (setq v (make-tramp-file-name :method method
:user user :domain domain :host host :port port :localname localname :hop
hop)) (when (and hop (or ... ...)) (tramp-user-error v "Method `%s' is not
supported for multi-hops." method)))))) (set-match-data
save-match-data-internal 'evaporate))
  (let ((save-match-data-internal (match-data))) (unwind-protect (progn
(unless (tramp-tramp-file-p name) (tramp-user-error nil "Not a Tramp file
name: \"%s\"" name)) (if (not (string-match (nth 0
tramp-file-name-structure) name)) (error "`tramp-file-name-structure'
didn't match!") (let ((method (match-string ... name)) (user (match-string
... name)) (host (match-string ... name)) (localname (match-string ...
name)) (hop (match-string ... name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain ... user
...))) (when host (when (string-match tramp-host-with-port-regexp host)
(setq port ... host ...)) (when (string-match tramp-prefix-ipv6-regexp
host) (setq host ...)) (when (string-match tramp-postfix-ipv6-regexp host)
(setq host ...))) (unless nodefault (when hop (setq v ... hop ...)) (let
(...) (setq method ... user ... host ... hop ...))) (prog1 (setq v
(make-tramp-file-name :method method :user user :domain domain :host host
:port port :localname localname :hop hop)) (when (and hop ...)
(tramp-user-error v "Method `%s' is not supported for multi-hops."
method)))))) (set-match-data save-match-data-internal 'evaporate)))
  (save-match-data (unless (tramp-tramp-file-p name) (tramp-user-error nil
"Not a Tramp file name: \"%s\"" name)) (if (not (string-match (nth 0
tramp-file-name-structure) name)) (error "`tramp-file-name-structure'
didn't match!") (let ((method (match-string (nth 1
tramp-file-name-structure) name)) (user (match-string (nth 2
tramp-file-name-structure) name)) (host (match-string (nth 3
tramp-file-name-structure) name)) (localname (match-string (nth 4
tramp-file-name-structure) name)) (hop (match-string (nth 5
tramp-file-name-structure) name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain
(match-string 2 user) user (match-string 1 user)))) (when host (when
(string-match tramp-host-with-port-regexp host) (setq port (match-string 2
host) host (match-string 1 host))) (when (string-match
tramp-prefix-ipv6-regexp host) (setq host (replace-match "" nil t host)))
(when (string-match tramp-postfix-ipv6-regexp host) (setq host
(replace-match "" nil t host)))) (unless nodefault (when hop (setq v
(tramp-dissect-hop-name hop) hop (and hop (tramp-make-tramp-hop-name v))))
(let ((tramp-default-host (or ... tramp-default-host))) (setq method
(tramp-find-method method user host) user (tramp-find-user method user
host) host (tramp-find-host method user host) hop (and hop (format-spec hop
...))))) (prog1 (setq v (make-tramp-file-name :method method :user user
:domain domain :host host :port port :localname localname :hop hop)) (when
(and hop (or (not ...) (tramp-get-method-parameter v ...)))
(tramp-user-error v "Method `%s' is not supported for multi-hops."
method))))))
  tramp-dissect-file-name("~")
  (let* ((v (tramp-dissect-file-name filename)) (method
(tramp-file-name-method v)) (user (tramp-file-name-user v)) (domain
(tramp-file-name-domain v)) (host (tramp-file-name-host v)) (port
(tramp-file-name-port v)) (localname (tramp-file-name-localname v)) (hop
(tramp-file-name-hop v))) (ignore method user domain host port localname
hop) (cond ((and fn (memq operation '(file-exists-p file-readable-p)))
(add-to-list 'tramp-vc-registered-file-names localname 'append) nil) ((and
fn (eq operation 'process-file) 0)) ((and fn (eq operation
'start-file-process) nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))
  (with-parsed-tramp-file-name filename nil (cond ((and fn (memq operation
'(file-exists-p file-readable-p))) (add-to-list
'tramp-vc-registered-file-names localname 'append) nil) ((and fn (eq
operation 'process-file) 0)) ((and fn (eq operation 'start-file-process)
nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))
  (let ((filename (tramp-replace-environment-variables (apply
#'tramp-file-name-for-operation operation args))) (fn (assoc operation
tramp-sh-file-name-handler-alist))) (with-parsed-tramp-file-name filename
nil (cond ((and fn (memq operation '(file-exists-p file-readable-p)))
(add-to-list 'tramp-vc-registered-file-names localname 'append) nil) ((and
fn (eq operation 'process-file) 0)) ((and fn (eq operation
'start-file-process) nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args)))))
  (progn (let ((filename (tramp-replace-environment-variables (apply
#'tramp-file-name-for-operation operation args))) (fn (assoc operation
tramp-sh-file-name-handler-alist))) (with-parsed-tramp-file-name filename
nil (cond ((and fn (memq operation '...)) (add-to-list
'tramp-vc-registered-file-names localname 'append) nil) ((and fn (eq
operation 'process-file) 0)) ((and fn (eq operation 'start-file-process)
nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))))
  (unwind-protect (progn (let ((filename
(tramp-replace-environment-variables (apply #'tramp-file-name-for-operation
operation args))) (fn (assoc operation tramp-sh-file-name-handler-alist)))
(with-parsed-tramp-file-name filename nil (cond ((and fn (memq operation
...)) (add-to-list 'tramp-vc-registered-file-names localname 'append) nil)
((and fn (eq operation ...) 0)) ((and fn (eq operation ...) nil)) (fn
(save-match-data (apply ... args))) (t (tramp-run-real-handler operation
args)))))) (set-match-data save-match-data-internal 'evaporate))
  (let ((save-match-data-internal (match-data))) (unwind-protect (progn
(let ((filename (tramp-replace-environment-variables (apply ... operation
args))) (fn (assoc operation tramp-sh-file-name-handler-alist)))
(with-parsed-tramp-file-name filename nil (cond ((and fn ...) (add-to-list
... localname ...) nil) ((and fn ... 0)) ((and fn ... nil)) (fn
(save-match-data ...)) (t (tramp-run-real-handler operation args))))))
(set-match-data save-match-data-internal 'evaporate)))
  (save-match-data (let ((filename (tramp-replace-environment-variables
(apply #'tramp-file-name-for-operation operation args))) (fn (assoc
operation tramp-sh-file-name-handler-alist))) (with-parsed-tramp-file-name
filename nil (cond ((and fn (memq operation '...)) (add-to-list
'tramp-vc-registered-file-names localname 'append) nil) ((and fn (eq
operation 'process-file) 0)) ((and fn (eq operation 'start-file-process)
nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))))
  tramp-vc-file-name-handler(expand-file-name "~"
"/gssh:slippycheeze.X.XXXXXXXX.com:/XXXXXX/XXX/XXXX...")
  make-process(:name "*deferred:*/usr/bin/timeout*:42" :buffer "
*deferred:*/usr/bin/timeout*:42" :command ("/usr/bin/timeout" "5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n%change..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX..."))
  apply(make-process (:name "*deferred:*/usr/bin/timeout*:42" :buffer "
*deferred:*/usr/bin/timeout*:42" :command ("/usr/bin/timeout" "5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n%change..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")))
  start-process("*deferred:*/usr/bin/timeout*:42" "
*deferred:*/usr/bin/timeout*:42" "/usr/bin/timeout" "5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n%change..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  apply(start-process "*deferred:*/usr/bin/timeout*:42" "
*deferred:*/usr/bin/timeout*:42" "/usr/bin/timeout" ("5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n%change..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX..."))
  (if (null (car args)) (apply f proc-name buf-name command nil) (apply f
proc-name buf-name command args))
  (setq proc (if (null (car args)) (apply f proc-name buf-name command nil)
(apply f proc-name buf-name command args)))
  (let ((default-directory pwd) (process-environment env)
(process-connection-type con-type)) (setq proc (if (null (car args)) (apply
f proc-name buf-name command nil) (apply f proc-name buf-name command
args))) (set-process-sentinel proc #'(lambda (_proc event) (cond
((string-match "exited abnormally" event) (let (...) (kill-buffer proc-buf)
(deferred:post-task nd ... msg))) ((equal event "finished\n")
(deferred:post-task nd 'ok proc-buf))))) (progn (or (and (memq (type-of nd)
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list 'deferred
nd))) (let* ((v nd)) (aset v 3 #'(lambda (x) (deferred:default-cancel x)
(if proc (progn ... ...)))))))
  (condition-case err (let ((default-directory pwd) (process-environment
env) (process-connection-type con-type)) (setq proc (if (null (car args))
(apply f proc-name buf-name command nil) (apply f proc-name buf-name
command args))) (set-process-sentinel proc #'(lambda (_proc event) (cond
((string-match "exited abnormally" event) (let ... ... ...)) ((equal event
"finished\n") (deferred:post-task nd ... proc-buf))))) (progn (or (and
(memq (type-of nd) cl-struct-deferred-tags) t) (signal 'wrong-type-argument
(list 'deferred nd))) (let* ((v nd)) (aset v 3 #'(lambda (x)
(deferred:default-cancel x) (if proc ...)))))) (error (deferred:post-task
nd 'ng err)))
  (closure ((proc) (proc-buf . #<buffer  *deferred:*/usr/bin/timeout*:42>)
(nd . #s(deferred :callback deferred:default-callback :errorback
deferred:default-errorback :cancel deferred:default-cancel :next
#s(deferred :callback (closure ... ... ...) :errorback
deferred:default-errorback :cancel (closure ... ... ... ...) :next
#s(deferred :callback ... :errorback deferred:default-errorback :cancel
deferred:default-cancel :next ... :status nil :value nil) :status nil
:value nil) :status nil :value nil)) (con-type . t) (env "TERM=dumb"
"P4CONFIG=.p4config" "MANPATH=/Users/slippycheeze/share/man:/User..."
"INFOPATH=/Users/slippycheeze/share/info:/Us..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28B..." "LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/sl..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launch..."
"Apple_PubSub_Socket_Render=/private/tmp/com..."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.com:/XXXXXX/X...") (buf-name . "
*deferred:*/usr/bin/timeout*:42") (proc-name .
"*deferred:*/usr/bin/timeout*:42") (uid . 42) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback #0 :errorback
deferred:default-errorback :cancel deferred:default-cancel :next nil
:status nil :value nil) :status nil :value nil)) (args "5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.com:/XXXXXX/X...") (command .
"/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags t) (_x)
(setq proc-buf (get-buffer-create buf-name)) (condition-case err (let
((default-directory pwd) (process-environment env) (process-connection-type
con-type)) (setq proc (if (null ...) (apply f proc-name buf-name command
nil) (apply f proc-name buf-name command args))) (set-process-sentinel proc
#'(lambda ... ...)) (progn (or (and ... t) (signal ... ...)) (let* (...)
(aset v 3 ...)))) (error (deferred:post-task nd 'ng err))) nil)(nil)
  funcall((closure ((proc) (proc-buf . #<buffer
*deferred:*/usr/bin/timeout*:42>) (nd . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback (closure (... ... ...
... ... cl-struct-deferred-tags t) (buf) (prog1 ... ...)) :errorback
deferred:default-errorback :cancel (closure (... ... ... ... ... ...
cl-struct-deferred-tags t) (_x) (deferred:default-cancel d)
(deferred:default-cancel pd)) :next #s(deferred :callback (closure ... ...
...) :errorback deferred:default-errorback :cancel deferred:default-cancel
:next #s(deferred :callback deferred:default-callback :errorback ignore
:cancel deferred:default-cancel :next ... :status nil :value nil) :status
nil :value nil) :status nil :value nil) :status nil :value nil)) (con-type
. t) (env "TERM=dumb" "P4CONFIG=.p4config"
"MANPATH=/Users/slippycheeze/share/man:/Users/slipp..."
"INFOPATH=/Users/slippycheeze/share/info:/Users/sli..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28Br4hHcs/..."
"LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/slippyche..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.Qs29e..."
"Apple_PubSub_Socket_Render=/private/tmp/com.apple...."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384ftww00c...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (buf-name . "
*deferred:*/usr/bin/timeout*:42") (proc-name .
"*deferred:*/usr/bin/timeout*:42") (uid . 42) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback #1 :errorback
deferred:default-errorback :cancel deferred:default-cancel :next nil
:status nil :value nil) :status nil :value nil)) (args "5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n%change..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (command .
"/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags t) (_x)
(setq proc-buf (get-buffer-create buf-name)) (condition-case err (let
((default-directory pwd) (process-environment env) (process-connection-type
con-type)) (setq proc (if (null (car args)) (apply f proc-name buf-name
command nil) (apply f proc-name buf-name command args)))
(set-process-sentinel proc #'(lambda (_proc event) (cond ... ...))) (progn
(or (and (memq ... cl-struct-deferred-tags) t) (signal 'wrong-type-argument
(list ... nd))) (let* ((v nd)) (aset v 3 #'...)))) (error
(deferred:post-task nd 'ng err))) nil) nil)
  (condition-case err (funcall f arg) ('wrong-number-of-arguments
(display-warning 'deferred "Callback that takes no argument may be
specified.\n..." err) (condition-case nil (funcall f)
('wrong-number-of-arguments (signal 'wrong-number-of-arguments (cdr
err))))))
  deferred:call-lambda((closure ((proc) (proc-buf . #<buffer
*deferred:*/usr/bin/timeout*:42>) (nd . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback (closure (... ... ...
... ... cl-struct-deferred-tags t) (buf) (prog1 ... ...)) :errorback
deferred:default-errorback :cancel (closure (... ... ... ... ... ...
cl-struct-deferred-tags t) (_x) (deferred:default-cancel d)
(deferred:default-cancel pd)) :next #s(deferred :callback (closure ... ...
...) :errorback deferred:default-errorback :cancel deferred:default-cancel
:next #s(deferred :callback deferred:default-callback :errorback ignore
:cancel deferred:default-cancel :next ... :status nil :value nil) :status
nil :value nil) :status nil :value nil) :status nil :value nil)) (con-type
. t) (env "TERM=dumb" "P4CONFIG=.p4config"
"MANPATH=/Users/slippycheeze/share/man:/Users/slipp..."
"INFOPATH=/Users/slippycheeze/share/info:/Users/sli..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28Br4hHcs/..."
"LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/slippyche..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.Qs29e..."
"Apple_PubSub_Socket_Render=/private/tmp/com.apple...."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384ftww00c...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (buf-name . "
*deferred:*/usr/bin/timeout*:42") (proc-name .
"*deferred:*/usr/bin/timeout*:42") (uid . 42) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback #1 :errorback
deferred:default-errorback :cancel deferred:default-cancel :next nil
:status nil :value nil) :status nil :value nil)) (args "5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n%change..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (command .
"/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags t) (_x)
(setq proc-buf (get-buffer-create buf-name)) (condition-case err (let
((default-directory pwd) (process-environment env) (process-connection-type
con-type)) (setq proc (if (null (car args)) (apply f proc-name buf-name
command nil) (apply f proc-name buf-name command args)))
(set-process-sentinel proc #'(lambda (_proc event) (cond ... ...))) (progn
(or (and (memq ... cl-struct-deferred-tags) t) (signal 'wrong-type-argument
(list ... nd))) (let* ((v nd)) (aset v 3 #'...)))) (error
(deferred:post-task nd 'ng err))) nil) nil)
  (let ((value (deferred:call-lambda callback arg))) (cond ((and (memq
(type-of value) cl-struct-deferred-tags) t) nil (if next-deferred
(deferred:set-next value next-deferred) value)) (t (if next-deferred
(deferred:post-task next-deferred 'ok value) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 5 'ok))) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 6 value))) value))))
  (condition-case err (let ((value (deferred:call-lambda callback arg)))
(cond ((and (memq (type-of value) cl-struct-deferred-tags) t) nil (if
next-deferred (deferred:set-next value next-deferred) value)) (t (if
next-deferred (deferred:post-task next-deferred 'ok value) (progn (or (and
... t) (signal ... ...)) (let* (...) (aset v 5 ...))) (progn (or (and ...
t) (signal ... ...)) (let* (...) (aset v 6 value))) value)))) (error (cond
(next-deferred (deferred:post-task next-deferred 'ng err))
(deferred:onerror (deferred:call-lambda deferred:onerror err)) (t nil
(message "deferred error : %S" err) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 5 'ng))) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 6 err))) err))))
  (let ((debug-on-signal (or debug-on-signal deferred:debug-on-signal)))
(condition-case err (let ((value (deferred:call-lambda callback arg)))
(cond ((and (memq (type-of value) cl-struct-deferred-tags) t) nil (if
next-deferred (deferred:set-next value next-deferred) value)) (t (if
next-deferred (deferred:post-task next-deferred 'ok value) (progn (or ...
...) (let* ... ...)) (progn (or ... ...) (let* ... ...)) value)))) (error
(cond (next-deferred (deferred:post-task next-deferred 'ng err))
(deferred:onerror (deferred:call-lambda deferred:onerror err)) (t nil
(message "deferred error : %S" err) (progn (or (and ... t) (signal ...
...)) (let* (...) (aset v 5 ...))) (progn (or (and ... t) (signal ... ...))
(let* (...) (aset v 6 err))) err)))))
  (cond (callback (let ((debug-on-signal (or debug-on-signal
deferred:debug-on-signal))) (condition-case err (let ((value
(deferred:call-lambda callback arg))) (cond ((and ... t) nil (if
next-deferred ... value)) (t (if next-deferred ... ... ... value)))) (error
(cond (next-deferred (deferred:post-task next-deferred ... err))
(deferred:onerror (deferred:call-lambda deferred:onerror err)) (t nil
(message "deferred error : %S" err) (progn ... ...) (progn ... ...)
err)))))) (t (cond (next-deferred (deferred:exec-task next-deferred which
arg)) ((eq which 'ok) arg) (t (deferred:resignal arg)))))
  (let ((callback (if (eq which 'ok) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(aref d 1)) (progn (or (and (memq ... cl-struct-deferred-tags) t) (signal
'wrong-type-argument (list ... d))) (aref d 2)))) (next-deferred (progn (or
(and (memq (type-of d) cl-struct-deferred-tags) t) (signal
'wrong-type-argument (list 'deferred d))) (aref d 4)))) (cond (callback
(let ((debug-on-signal (or debug-on-signal deferred:debug-on-signal)))
(condition-case err (let ((value ...)) (cond (... nil ...) (t ...))) (error
(cond (next-deferred ...) (deferred:onerror ...) (t nil ... ... ...
err)))))) (t (cond (next-deferred (deferred:exec-task next-deferred which
arg)) ((eq which 'ok) arg) (t (deferred:resignal arg))))))
  deferred:exec-task(#s(deferred :callback (closure ((proc) (proc-buf .
#<buffer  *deferred:*/usr/bin/timeout*:42>) (nd . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback (closure ... ... ...)
:errorback deferred:default-errorback :cancel (closure ... ... ... ...)
:next #s(deferred :callback ... :errorback deferred:default-errorback
:cancel deferred:default-cancel :next ... :status nil :value nil) :status
nil :value nil) :status nil :value nil)) (con-type . t) (env "TERM=dumb"
"P4CONFIG=.p4config"
"MANPATH=/Users/slippycheeze/share/man:/Users/slipp..."
"INFOPATH=/Users/slippycheeze/share/info:/Users/sli..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28Br4hHcs/..."
"LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/slippyche..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.Qs29e..."
"Apple_PubSub_Socket_Render=/private/tmp/com.apple...."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384ftww00c...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (buf-name . "
*deferred:*/usr/bin/timeout*:42") (proc-name .
"*deferred:*/usr/bin/timeout*:42") (uid . 42) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #1 :status nil :value nil)) (args "5s" "p4"
"-zprog=google-piper.el"
"--format=%depotFile%\n%clientFile%\n%action%\n%change..." "fstat" "--"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (command .
"/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags t) (_x)
(setq proc-buf (get-buffer-create buf-name)) (condition-case err (let
((default-directory pwd) (process-environment env) (process-connection-type
con-type)) (setq proc (if (null ...) (apply f proc-name buf-name command
nil) (apply f proc-name buf-name command args))) (set-process-sentinel proc
#'(lambda ... ...)) (progn (or (and ... t) (signal ... ...)) (let* (...)
(aset v 3 ...)))) (error (deferred:post-task nd 'ng err))) nil) :errorback
deferred:default-errorback :cancel deferred:default-cancel :next nil
:status nil :value nil) ok nil)
  (setq value (deferred:exec-task d which arg))
  (condition-case err (setq value (deferred:exec-task d which arg)) (error
nil (message "deferred error : %s" err)))
  (let* ((pack (car (last deferred:queue))) (d (car pack)) (which (car (cdr
pack))) (arg (cdr (cdr pack))) value) (setq deferred:queue (nbutlast
deferred:queue)) (condition-case err (setq value (deferred:exec-task d
which arg)) (error nil (message "deferred error : %s" err))) value)
  (progn (let* ((pack (car (last deferred:queue))) (d (car pack)) (which
(car (cdr pack))) (arg (cdr (cdr pack))) value) (setq deferred:queue
(nbutlast deferred:queue)) (condition-case err (setq value
(deferred:exec-task d which arg)) (error nil (message "deferred error : %s"
err))) value))
  (if deferred:queue (progn (let* ((pack (car (last deferred:queue))) (d
(car pack)) (which (car (cdr pack))) (arg (cdr (cdr pack))) value) (setq
deferred:queue (nbutlast deferred:queue)) (condition-case err (setq value
(deferred:exec-task d which arg)) (error nil (message "deferred error : %s"
err))) value)))
  deferred:worker()
  apply(deferred:worker nil)
  timer-event-handler([t 23709 65205 28583 nil deferred:worker nil nil 0])
  input-pending-p(t)
  sit-for(30)
  #f(compiled-function () #<bytecode 0x1fe44d8a0399>)()
  tramp-user-error(nil "Not a Tramp file name: \"%s\"" "~")
  (if (tramp-tramp-file-p name) nil (tramp-user-error nil "Not a Tramp file
name: \"%s\"" name))
  (unless (tramp-tramp-file-p name) (tramp-user-error nil "Not a Tramp file
name: \"%s\"" name))
  (progn (unless (tramp-tramp-file-p name) (tramp-user-error nil "Not a
Tramp file name: \"%s\"" name)) (if (not (string-match (nth 0
tramp-file-name-structure) name)) (error "`tramp-file-name-structure'
didn't match!") (let ((method (match-string (nth 1
tramp-file-name-structure) name)) (user (match-string (nth 2
tramp-file-name-structure) name)) (host (match-string (nth 3
tramp-file-name-structure) name)) (localname (match-string (nth 4
tramp-file-name-structure) name)) (hop (match-string (nth 5
tramp-file-name-structure) name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain
(match-string 2 user) user (match-string 1 user)))) (when host (when
(string-match tramp-host-with-port-regexp host) (setq port (match-string 2
host) host (match-string 1 host))) (when (string-match
tramp-prefix-ipv6-regexp host) (setq host (replace-match "" nil t host)))
(when (string-match tramp-postfix-ipv6-regexp host) (setq host
(replace-match "" nil t host)))) (unless nodefault (when hop (setq v
(tramp-dissect-hop-name hop) hop (and hop (tramp-make-tramp-hop-name v))))
(let ((tramp-default-host (or ... tramp-default-host))) (setq method
(tramp-find-method method user host) user (tramp-find-user method user
host) host (tramp-find-host method user host) hop (and hop (format-spec hop
...))))) (prog1 (setq v (make-tramp-file-name :method method :user user
:domain domain :host host :port port :localname localname :hop hop)) (when
(and hop (or (not ...) (tramp-get-method-parameter v ...)))
(tramp-user-error v "Method `%s' is not supported for multi-hops."
method))))))
  (unwind-protect (progn (unless (tramp-tramp-file-p name)
(tramp-user-error nil "Not a Tramp file name: \"%s\"" name)) (if (not
(string-match (nth 0 tramp-file-name-structure) name)) (error
"`tramp-file-name-structure' didn't match!") (let ((method (match-string
(nth 1 tramp-file-name-structure) name)) (user (match-string (nth 2
tramp-file-name-structure) name)) (host (match-string (nth 3
tramp-file-name-structure) name)) (localname (match-string (nth 4
tramp-file-name-structure) name)) (hop (match-string (nth 5
tramp-file-name-structure) name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain
(match-string 2 user) user (match-string 1 user)))) (when host (when
(string-match tramp-host-with-port-regexp host) (setq port (match-string 2
host) host (match-string 1 host))) (when (string-match
tramp-prefix-ipv6-regexp host) (setq host (replace-match "" nil t host)))
(when (string-match tramp-postfix-ipv6-regexp host) (setq host
(replace-match "" nil t host)))) (unless nodefault (when hop (setq v
(tramp-dissect-hop-name hop) hop (and hop ...))) (let ((tramp-default-host
...)) (setq method (tramp-find-method method user host) user
(tramp-find-user method user host) host (tramp-find-host method user host)
hop (and hop ...)))) (prog1 (setq v (make-tramp-file-name :method method
:user user :domain domain :host host :port port :localname localname :hop
hop)) (when (and hop (or ... ...)) (tramp-user-error v "Method `%s' is not
supported for multi-hops." method)))))) (set-match-data
save-match-data-internal 'evaporate))
  (let ((save-match-data-internal (match-data))) (unwind-protect (progn
(unless (tramp-tramp-file-p name) (tramp-user-error nil "Not a Tramp file
name: \"%s\"" name)) (if (not (string-match (nth 0
tramp-file-name-structure) name)) (error "`tramp-file-name-structure'
didn't match!") (let ((method (match-string ... name)) (user (match-string
... name)) (host (match-string ... name)) (localname (match-string ...
name)) (hop (match-string ... name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain ... user
...))) (when host (when (string-match tramp-host-with-port-regexp host)
(setq port ... host ...)) (when (string-match tramp-prefix-ipv6-regexp
host) (setq host ...)) (when (string-match tramp-postfix-ipv6-regexp host)
(setq host ...))) (unless nodefault (when hop (setq v ... hop ...)) (let
(...) (setq method ... user ... host ... hop ...))) (prog1 (setq v
(make-tramp-file-name :method method :user user :domain domain :host host
:port port :localname localname :hop hop)) (when (and hop ...)
(tramp-user-error v "Method `%s' is not supported for multi-hops."
method)))))) (set-match-data save-match-data-internal 'evaporate)))
  (save-match-data (unless (tramp-tramp-file-p name) (tramp-user-error nil
"Not a Tramp file name: \"%s\"" name)) (if (not (string-match (nth 0
tramp-file-name-structure) name)) (error "`tramp-file-name-structure'
didn't match!") (let ((method (match-string (nth 1
tramp-file-name-structure) name)) (user (match-string (nth 2
tramp-file-name-structure) name)) (host (match-string (nth 3
tramp-file-name-structure) name)) (localname (match-string (nth 4
tramp-file-name-structure) name)) (hop (match-string (nth 5
tramp-file-name-structure) name)) domain port v) (when user (when
(string-match tramp-user-with-domain-regexp user) (setq domain
(match-string 2 user) user (match-string 1 user)))) (when host (when
(string-match tramp-host-with-port-regexp host) (setq port (match-string 2
host) host (match-string 1 host))) (when (string-match
tramp-prefix-ipv6-regexp host) (setq host (replace-match "" nil t host)))
(when (string-match tramp-postfix-ipv6-regexp host) (setq host
(replace-match "" nil t host)))) (unless nodefault (when hop (setq v
(tramp-dissect-hop-name hop) hop (and hop (tramp-make-tramp-hop-name v))))
(let ((tramp-default-host (or ... tramp-default-host))) (setq method
(tramp-find-method method user host) user (tramp-find-user method user
host) host (tramp-find-host method user host) hop (and hop (format-spec hop
...))))) (prog1 (setq v (make-tramp-file-name :method method :user user
:domain domain :host host :port port :localname localname :hop hop)) (when
(and hop (or (not ...) (tramp-get-method-parameter v ...)))
(tramp-user-error v "Method `%s' is not supported for multi-hops."
method))))))
  tramp-dissect-file-name("~")
  (let* ((v (tramp-dissect-file-name filename)) (method
(tramp-file-name-method v)) (user (tramp-file-name-user v)) (domain
(tramp-file-name-domain v)) (host (tramp-file-name-host v)) (port
(tramp-file-name-port v)) (localname (tramp-file-name-localname v)) (hop
(tramp-file-name-hop v))) (ignore method user domain host port localname
hop) (cond ((and fn (memq operation '(file-exists-p file-readable-p)))
(add-to-list 'tramp-vc-registered-file-names localname 'append) nil) ((and
fn (eq operation 'process-file) 0)) ((and fn (eq operation
'start-file-process) nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))
  (with-parsed-tramp-file-name filename nil (cond ((and fn (memq operation
'(file-exists-p file-readable-p))) (add-to-list
'tramp-vc-registered-file-names localname 'append) nil) ((and fn (eq
operation 'process-file) 0)) ((and fn (eq operation 'start-file-process)
nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))
  (let ((filename (tramp-replace-environment-variables (apply
#'tramp-file-name-for-operation operation args))) (fn (assoc operation
tramp-sh-file-name-handler-alist))) (with-parsed-tramp-file-name filename
nil (cond ((and fn (memq operation '(file-exists-p file-readable-p)))
(add-to-list 'tramp-vc-registered-file-names localname 'append) nil) ((and
fn (eq operation 'process-file) 0)) ((and fn (eq operation
'start-file-process) nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args)))))
  (progn (let ((filename (tramp-replace-environment-variables (apply
#'tramp-file-name-for-operation operation args))) (fn (assoc operation
tramp-sh-file-name-handler-alist))) (with-parsed-tramp-file-name filename
nil (cond ((and fn (memq operation '...)) (add-to-list
'tramp-vc-registered-file-names localname 'append) nil) ((and fn (eq
operation 'process-file) 0)) ((and fn (eq operation 'start-file-process)
nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))))
  (unwind-protect (progn (let ((filename
(tramp-replace-environment-variables (apply #'tramp-file-name-for-operation
operation args))) (fn (assoc operation tramp-sh-file-name-handler-alist)))
(with-parsed-tramp-file-name filename nil (cond ((and fn (memq operation
...)) (add-to-list 'tramp-vc-registered-file-names localname 'append) nil)
((and fn (eq operation ...) 0)) ((and fn (eq operation ...) nil)) (fn
(save-match-data (apply ... args))) (t (tramp-run-real-handler operation
args)))))) (set-match-data save-match-data-internal 'evaporate))
  (let ((save-match-data-internal (match-data))) (unwind-protect (progn
(let ((filename (tramp-replace-environment-variables (apply ... operation
args))) (fn (assoc operation tramp-sh-file-name-handler-alist)))
(with-parsed-tramp-file-name filename nil (cond ((and fn ...) (add-to-list
... localname ...) nil) ((and fn ... 0)) ((and fn ... nil)) (fn
(save-match-data ...)) (t (tramp-run-real-handler operation args))))))
(set-match-data save-match-data-internal 'evaporate)))
  (save-match-data (let ((filename (tramp-replace-environment-variables
(apply #'tramp-file-name-for-operation operation args))) (fn (assoc
operation tramp-sh-file-name-handler-alist))) (with-parsed-tramp-file-name
filename nil (cond ((and fn (memq operation '...)) (add-to-list
'tramp-vc-registered-file-names localname 'append) nil) ((and fn (eq
operation 'process-file) 0)) ((and fn (eq operation 'start-file-process)
nil)) (fn (save-match-data (apply (cdr fn) args))) (t
(tramp-run-real-handler operation args))))))
  tramp-vc-file-name-handler(expand-file-name "~"
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  make-process(:name "*deferred:*/usr/bin/timeout*:41" :buffer "
*deferred:*/usr/bin/timeout*:41" :command ("/usr/bin/timeout" "1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info"))
  apply(make-process (:name "*deferred:*/usr/bin/timeout*:41" :buffer "
*deferred:*/usr/bin/timeout*:41" :command ("/usr/bin/timeout" "1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info")))
  start-process("*deferred:*/usr/bin/timeout*:41" "
*deferred:*/usr/bin/timeout*:41" "/usr/bin/timeout" "1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info")
  apply(start-process "*deferred:*/usr/bin/timeout*:41" "
*deferred:*/usr/bin/timeout*:41" "/usr/bin/timeout" ("1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info"))
  (if (null (car args)) (apply f proc-name buf-name command nil) (apply f
proc-name buf-name command args))
  (setq proc (if (null (car args)) (apply f proc-name buf-name command nil)
(apply f proc-name buf-name command args)))
  (let ((default-directory pwd) (process-environment env)
(process-connection-type con-type)) (setq proc (if (null (car args)) (apply
f proc-name buf-name command nil) (apply f proc-name buf-name command
args))) (set-process-sentinel proc #'(lambda (_proc event) (cond
((string-match "exited abnormally" event) (let (...) (kill-buffer proc-buf)
(deferred:post-task nd ... msg))) ((equal event "finished\n")
(deferred:post-task nd 'ok proc-buf))))) (progn (or (and (memq (type-of nd)
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list 'deferred
nd))) (let* ((v nd)) (aset v 3 #'(lambda (x) (deferred:default-cancel x)
(if proc (progn ... ...)))))))
  (condition-case err (let ((default-directory pwd) (process-environment
env) (process-connection-type con-type)) (setq proc (if (null (car args))
(apply f proc-name buf-name command nil) (apply f proc-name buf-name
command args))) (set-process-sentinel proc #'(lambda (_proc event) (cond
((string-match "exited abnormally" event) (let ... ... ...)) ((equal event
"finished\n") (deferred:post-task nd ... proc-buf))))) (progn (or (and
(memq (type-of nd) cl-struct-deferred-tags) t) (signal 'wrong-type-argument
(list 'deferred nd))) (let* ((v nd)) (aset v 3 #'(lambda (x)
(deferred:default-cancel x) (if proc ...)))))) (error (deferred:post-task
nd 'ng err)))
  (closure ((proc) (proc-buf . #<buffer  *deferred:*/usr/bin/timeout*:41>)
(nd . #s(deferred :callback deferred:default-callback :errorback
deferred:default-errorback :cancel deferred:default-cancel :next
#s(deferred :callback (closure ... ... ...) :errorback
deferred:default-errorback :cancel (closure ... ... ... ...) :next
#s(deferred :callback ... :errorback deferred:default-errorback :cancel
deferred:default-cancel :next ... :status nil :value nil) :status nil
:value nil) :status nil :value nil)) (con-type . t) (env "TERM=dumb"
"P4CONFIG=.p4config" "MANPATH=/Users/slippycheeze/share/man:/User..."
"INFOPATH=/Users/slippycheeze/share/info:/Us..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28B..." "LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/sl..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launch..."
"Apple_PubSub_Socket_Render=/private/tmp/com..."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.com:/XXXXXX/X...") (buf-name . "
*deferred:*/usr/bin/timeout*:41") (proc-name .
"*deferred:*/usr/bin/timeout*:41") (uid . 41) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback #0 :errorback
deferred:default-errorback :cancel deferred:default-cancel :next nil
:status nil :value nil) :status nil :value nil)) (args "1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info")
(command . "/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags
t) (_x) (setq proc-buf (get-buffer-create buf-name)) (condition-case err
(let ((default-directory pwd) (process-environment env)
(process-connection-type con-type)) (setq proc (if (null ...) (apply f
proc-name buf-name command nil) (apply f proc-name buf-name command args)))
(set-process-sentinel proc #'(lambda ... ...)) (progn (or (and ... t)
(signal ... ...)) (let* (...) (aset v 3 ...)))) (error (deferred:post-task
nd 'ng err))) nil)(nil)
  funcall((closure ((proc) (proc-buf . #<buffer
*deferred:*/usr/bin/timeout*:41>) (nd . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback (closure (... ... ...
... ... cl-struct-deferred-tags t) (buf) (prog1 ... ...)) :errorback
deferred:default-errorback :cancel (closure (... ... ... ... ... ...
cl-struct-deferred-tags t) (_x) (deferred:default-cancel d)
(deferred:default-cancel pd)) :next #s(deferred :callback (closure ... ...
...) :errorback deferred:default-errorback :cancel deferred:default-cancel
:next #s(deferred :callback ... :errorback deferred:default-errorback
:cancel deferred:default-cancel :next ... :status nil :value nil) :status
nil :value nil) :status nil :value nil) :status nil :value nil)) (con-type
. t) (env "TERM=dumb" "P4CONFIG=.p4config"
"MANPATH=/Users/slippycheeze/share/man:/Users/slipp..."
"INFOPATH=/Users/slippycheeze/share/info:/Users/sli..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28Br4hHcs/..."
"LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/slippyche..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.Qs29e..."
"Apple_PubSub_Socket_Render=/private/tmp/com.apple...."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384ftww00c...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (buf-name . "
*deferred:*/usr/bin/timeout*:41") (proc-name .
"*deferred:*/usr/bin/timeout*:41") (uid . 41) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback #1 :errorback
deferred:default-errorback :cancel deferred:default-cancel :next nil
:status nil :value nil) :status nil :value nil)) (args "1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info")
(command . "/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags
t) (_x) (setq proc-buf (get-buffer-create buf-name)) (condition-case err
(let ((default-directory pwd) (process-environment env)
(process-connection-type con-type)) (setq proc (if (null (car args)) (apply
f proc-name buf-name command nil) (apply f proc-name buf-name command
args))) (set-process-sentinel proc #'(lambda (_proc event) (cond ... ...)))
(progn (or (and (memq ... cl-struct-deferred-tags) t) (signal
'wrong-type-argument (list ... nd))) (let* ((v nd)) (aset v 3 #'...))))
(error (deferred:post-task nd 'ng err))) nil) nil)
  (condition-case err (funcall f arg) ('wrong-number-of-arguments
(display-warning 'deferred "Callback that takes no argument may be
specified.\n..." err) (condition-case nil (funcall f)
('wrong-number-of-arguments (signal 'wrong-number-of-arguments (cdr
err))))))
  deferred:call-lambda((closure ((proc) (proc-buf . #<buffer
*deferred:*/usr/bin/timeout*:41>) (nd . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback (closure (... ... ...
... ... cl-struct-deferred-tags t) (buf) (prog1 ... ...)) :errorback
deferred:default-errorback :cancel (closure (... ... ... ... ... ...
cl-struct-deferred-tags t) (_x) (deferred:default-cancel d)
(deferred:default-cancel pd)) :next #s(deferred :callback (closure ... ...
...) :errorback deferred:default-errorback :cancel deferred:default-cancel
:next #s(deferred :callback ... :errorback deferred:default-errorback
:cancel deferred:default-cancel :next ... :status nil :value nil) :status
nil :value nil) :status nil :value nil) :status nil :value nil)) (con-type
. t) (env "TERM=dumb" "P4CONFIG=.p4config"
"MANPATH=/Users/slippycheeze/share/man:/Users/slipp..."
"INFOPATH=/Users/slippycheeze/share/info:/Users/sli..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28Br4hHcs/..."
"LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/slippyche..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.Qs29e..."
"Apple_PubSub_Socket_Render=/private/tmp/com.apple...."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384ftww00c...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (buf-name . "
*deferred:*/usr/bin/timeout*:41") (proc-name .
"*deferred:*/usr/bin/timeout*:41") (uid . 41) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback #1 :errorback
deferred:default-errorback :cancel deferred:default-cancel :next nil
:status nil :value nil) :status nil :value nil)) (args "1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info")
(command . "/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags
t) (_x) (setq proc-buf (get-buffer-create buf-name)) (condition-case err
(let ((default-directory pwd) (process-environment env)
(process-connection-type con-type)) (setq proc (if (null (car args)) (apply
f proc-name buf-name command nil) (apply f proc-name buf-name command
args))) (set-process-sentinel proc #'(lambda (_proc event) (cond ... ...)))
(progn (or (and (memq ... cl-struct-deferred-tags) t) (signal
'wrong-type-argument (list ... nd))) (let* ((v nd)) (aset v 3 #'...))))
(error (deferred:post-task nd 'ng err))) nil) nil)
  (let ((value (deferred:call-lambda callback arg))) (cond ((and (memq
(type-of value) cl-struct-deferred-tags) t) nil (if next-deferred
(deferred:set-next value next-deferred) value)) (t (if next-deferred
(deferred:post-task next-deferred 'ok value) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 5 'ok))) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 6 value))) value))))
  (condition-case err (let ((value (deferred:call-lambda callback arg)))
(cond ((and (memq (type-of value) cl-struct-deferred-tags) t) nil (if
next-deferred (deferred:set-next value next-deferred) value)) (t (if
next-deferred (deferred:post-task next-deferred 'ok value) (progn (or (and
... t) (signal ... ...)) (let* (...) (aset v 5 ...))) (progn (or (and ...
t) (signal ... ...)) (let* (...) (aset v 6 value))) value)))) (error (cond
(next-deferred (deferred:post-task next-deferred 'ng err))
(deferred:onerror (deferred:call-lambda deferred:onerror err)) (t nil
(message "deferred error : %S" err) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 5 'ng))) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(let* ((v d)) (aset v 6 err))) err))))
  (let ((debug-on-signal (or debug-on-signal deferred:debug-on-signal)))
(condition-case err (let ((value (deferred:call-lambda callback arg)))
(cond ((and (memq (type-of value) cl-struct-deferred-tags) t) nil (if
next-deferred (deferred:set-next value next-deferred) value)) (t (if
next-deferred (deferred:post-task next-deferred 'ok value) (progn (or ...
...) (let* ... ...)) (progn (or ... ...) (let* ... ...)) value)))) (error
(cond (next-deferred (deferred:post-task next-deferred 'ng err))
(deferred:onerror (deferred:call-lambda deferred:onerror err)) (t nil
(message "deferred error : %S" err) (progn (or (and ... t) (signal ...
...)) (let* (...) (aset v 5 ...))) (progn (or (and ... t) (signal ... ...))
(let* (...) (aset v 6 err))) err)))))
  (cond (callback (let ((debug-on-signal (or debug-on-signal
deferred:debug-on-signal))) (condition-case err (let ((value
(deferred:call-lambda callback arg))) (cond ((and ... t) nil (if
next-deferred ... value)) (t (if next-deferred ... ... ... value)))) (error
(cond (next-deferred (deferred:post-task next-deferred ... err))
(deferred:onerror (deferred:call-lambda deferred:onerror err)) (t nil
(message "deferred error : %S" err) (progn ... ...) (progn ... ...)
err)))))) (t (cond (next-deferred (deferred:exec-task next-deferred which
arg)) ((eq which 'ok) arg) (t (deferred:resignal arg)))))
  (let ((callback (if (eq which 'ok) (progn (or (and (memq ...
cl-struct-deferred-tags) t) (signal 'wrong-type-argument (list ... d)))
(aref d 1)) (progn (or (and (memq ... cl-struct-deferred-tags) t) (signal
'wrong-type-argument (list ... d))) (aref d 2)))) (next-deferred (progn (or
(and (memq (type-of d) cl-struct-deferred-tags) t) (signal
'wrong-type-argument (list 'deferred d))) (aref d 4)))) (cond (callback
(let ((debug-on-signal (or debug-on-signal deferred:debug-on-signal)))
(condition-case err (let ((value ...)) (cond (... nil ...) (t ...))) (error
(cond (next-deferred ...) (deferred:onerror ...) (t nil ... ... ...
err)))))) (t (cond (next-deferred (deferred:exec-task next-deferred which
arg)) ((eq which 'ok) arg) (t (deferred:resignal arg))))))
  deferred:exec-task(#s(deferred :callback (closure ((proc) (proc-buf .
#<buffer  *deferred:*/usr/bin/timeout*:41>) (nd . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #s(deferred :callback (closure ... ... ...)
:errorback deferred:default-errorback :cancel (closure ... ... ... ...)
:next #s(deferred :callback ... :errorback deferred:default-errorback
:cancel deferred:default-cancel :next ... :status nil :value nil) :status
nil :value nil) :status nil :value nil)) (con-type . t) (env "TERM=dumb"
"P4CONFIG=.p4config"
"MANPATH=/Users/slippycheeze/share/man:/Users/slipp..."
"INFOPATH=/Users/slippycheeze/share/info:/Users/sli..." "LANG=en_US.UTF-8"
"XPC_FLAGS=0x0" "SECURITYSESSIONID=XXXXX" "USER=slippycheeze"
"COMMAND_MODE=unix2003" "XPC_SERVICE_NAME=org.gnu.Emacs.15324"
"DISPLAY=/private/tmp/com.apple.launchd.O28Br4hHcs/..."
"LOGNAME=slippycheeze"
"PATH=/Users/slippycheeze/.bagpipe:/Users/slippyche..."
"SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.Qs29e..."
"Apple_PubSub_Socket_Render=/private/tmp/com.apple...."
"SHELL=/Users/slippycheeze/homebrew/bin/zsh" "HOME=/Users/slippycheeze"
"__CF_USER_TEXT_ENCODING=0x64DE5:0x0:0x0"
"TMPDIR=/var/folders/bc/tpg4l8wj7gg2722p9384ftww00c...") (pwd .
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...") (buf-name . "
*deferred:*/usr/bin/timeout*:41") (proc-name .
"*deferred:*/usr/bin/timeout*:41") (uid . 41) (d . #s(deferred :callback
deferred:default-callback :errorback deferred:default-errorback :cancel
deferred:default-cancel :next #1 :status nil :value nil)) (args "1s" "p4"
"-zprog=google-piper.el" "--format=%clientName%\n%clientRoot%" "info")
(command . "/usr/bin/timeout") (f . start-process) cl-struct-deferred-tags
t) (_x) (setq proc-buf (get-buffer-create buf-name)) (condition-case err
(let ((default-directory pwd) (process-environment env)
(process-connection-type con-type)) (setq proc (if (null ...) (apply f
proc-name buf-name command nil) (apply f proc-name buf-name command args)))
(set-process-sentinel proc #'(lambda ... ...)) (progn (or (and ... t)
(signal ... ...)) (let* (...) (aset v 3 ...)))) (error (deferred:post-task
nd 'ng err))) nil) :errorback deferred:default-errorback :cancel
deferred:default-cancel :next nil :status nil :value nil) ok nil)
  (setq value (deferred:exec-task d which arg))
  (condition-case err (setq value (deferred:exec-task d which arg)) (error
nil (message "deferred error : %s" err)))
  (let* ((pack (car (last deferred:queue))) (d (car pack)) (which (car (cdr
pack))) (arg (cdr (cdr pack))) value) (setq deferred:queue (nbutlast
deferred:queue)) (condition-case err (setq value (deferred:exec-task d
which arg)) (error nil (message "deferred error : %s" err))) value)
  (progn (let* ((pack (car (last deferred:queue))) (d (car pack)) (which
(car (cdr pack))) (arg (cdr (cdr pack))) value) (setq deferred:queue
(nbutlast deferred:queue)) (condition-case err (setq value
(deferred:exec-task d which arg)) (error nil (message "deferred error : %s"
err))) value))
  (if deferred:queue (progn (let* ((pack (car (last deferred:queue))) (d
(car pack)) (which (car (cdr pack))) (arg (cdr (cdr pack))) value) (setq
deferred:queue (nbutlast deferred:queue)) (condition-case err (setq value
(deferred:exec-task d which arg)) (error nil (message "deferred error : %s"
err))) value)))
  deferred:worker()
  apply(deferred:worker nil)
  timer-event-handler([t 23709 65205 28556 nil deferred:worker nil nil 0])
  process-send-string(#<process *tramp/gssh slippycheeze.c.googlers.com*>
"tramp_vc_registered_read_file_names <<'c231581b08e...")
  tramp-send-string((tramp-file-name "gssh" nil nil "
slippycheeze.c.googlers.com" nil
"/google/src/cloud/slippycheeze/work/google3/storag..." nil)
"tramp_vc_registered_read_file_names <<'c231581b08e...")
  tramp-send-command((tramp-file-name "gssh" nil nil "
slippycheeze.c.googlers.com" nil
"/google/src/cloud/slippycheeze/work/google3/storag..." nil)
"tramp_vc_registered_read_file_names <<'c231581b08e...")

tramp-sh-handle-vc-registered("/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  apply(tramp-sh-handle-vc-registered
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  tramp-sh-file-name-handler(vc-registered
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  apply(tramp-sh-file-name-handler vc-registered
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  tramp-file-name-handler(vc-registered
"/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  vc-registered("/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  vc-backend("/gssh:slippycheeze.X.XXXXXXXX.XXX:/XXXXXX/XXX/XXXX...")
  vc-refresh-state()
  run-hooks(find-file-hook)
  after-find-file(nil nil t nil nil)
  revert-buffer--default(t nil)
  revert-buffer(t)
  funcall-interactively(revert-buffer t)
  call-interactively(revert-buffer record nil)
  command-execute(revert-buffer record)
  execute-extended-command(nil "revert-buffer" "revert-buf")
  funcall-interactively(execute-extended-command nil "revert-buffer"
"revert-buf")
  call-interactively(execute-extended-command nil nil)
  command-execute(execute-extended-command)

[-- Attachment #2: Type: text/html, Size: 66797 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
  2019-03-29 12:36       ` Daniel Pittman
@ 2019-03-29 17:03         ` Michael Albinus
  2019-04-02  9:34           ` Daniel Pittman
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Albinus @ 2019-03-29 17:03 UTC (permalink / raw)
  To: Daniel Pittman; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1154 bytes --]

Daniel Pittman <slippycheeze@google.com> writes:

Hi Daniel,

>     Since I cannot reproduce the problem (yet), do you have a
>     backtrace?
>
> Sure, please see it follow.  I have censored the content of a small
> number of strings, but this is replacing a standard ASCII letter with
> 'X' so should have no semantic effect.  Sorry to have to do that.
> Fair warning, it is ... long.

Thanks! Could you pls send it next time as attachment? As text in the
message body, line breaks are set randomly, which makes it hard to read.

> The most interesting part is at the very start, where my `revert-file
> ` operation on a remote file triggers a `vc-refresh-state`, which ends
> up causing `tramp-send-string` to run `process-send-string`, and then
> a timer fires that drives the "deferred" third party library [1] to
> move on to running a background command, using the timeout(1) and p4
> (1) binaries to grab some state information.

Yes. Tramp fights indeed with timers, and so I have disabled timers in
tramp-accept-process-output already. Maybe we shall do the same in
tramp-send-string? Would the following patch help?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 1705 bytes --]

*** /tmp/ediffDh3DJa	2019-03-29 18:01:12.059246938 +0100
--- /home/albinus/src/tramp/lisp/tramp.el	2019-03-29 17:58:44.756196926 +0100
***************
*** 4210,4216 ****
  the remote host use line-endings as defined in the variable
  `tramp-rsh-end-of-line'.  The communication buffer is erased before sending."
    (let* ((p (tramp-get-connection-process vec))
! 	 (chunksize (tramp-get-connection-property p "chunksize" nil)))
      (unless p
        (tramp-error
         vec 'file-error "Can't send string to remote host -- not logged in"))
--- 4210,4219 ----
  the remote host use line-endings as defined in the variable
  `tramp-rsh-end-of-line'.  The communication buffer is erased before sending."
    (let* ((p (tramp-get-connection-process vec))
! 	 (chunksize (tramp-get-connection-property p "chunksize" nil))
! 	 ;; We do not want to run timers.
!          (stimers (with-timeout-suspend))
! 	 timer-list timer-idle-list)
      (unless p
        (tramp-error
         vec 'file-error "Can't send string to remote host -- not logged in"))
***************
*** 4238,4244 ****
  	      (process-send-string
  	       p (substring string pos (min (+ pos chunksize) end)))
  	      (setq pos (+ pos chunksize))))
! 	(process-send-string p string)))))

  (defun tramp-get-inode (vec)
    "Returns the virtual inode number.
--- 4241,4249 ----
  	      (process-send-string
  	       p (substring string pos (min (+ pos chunksize) end)))
  	      (setq pos (+ pos chunksize))))
! 	(process-send-string p string))
!       ;; Reenable the timers.
!       (with-timeout-unsuspend stimers))))

  (defun tramp-get-inode (vec)
    "Returns the virtual inode number.

[-- Attachment #3: Type: text/plain, Size: 24 bytes --]


Best regards, Michael.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
  2019-03-29 17:03         ` Michael Albinus
@ 2019-04-02  9:34           ` Daniel Pittman
  2019-04-02 13:18             ` Michael Albinus
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Pittman @ 2019-04-02  9:34 UTC (permalink / raw)
  To: Michael Albinus; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1086 bytes --]

On Fri, Mar 29, 2019 at 5:03 PM Michael Albinus <michael.albinus@gmx.de>
wrote:

> Daniel Pittman <slippycheeze@google.com> writes:
> > The most interesting part is at the very start, where my `revert-file
> > ` operation on a remote file triggers a `vc-refresh-state`, which ends
> > up causing `tramp-send-string` to run `process-send-string`, and then
> > a timer fires that drives the "deferred" third party library [1] to
> > move on to running a background command, using the timeout(1) and p4
> > (1) binaries to grab some state information.
>
> Yes. Tramp fights indeed with timers, and so I have disabled timers in
> tramp-accept-process-output already. Maybe we shall do the same in
> tramp-send-string? Would the following patch help?


In brief testing – 100 percent reproducible error, but only one instance –
this patch did fix the problem.  I haven't tried to provoke a non-local
exit from anything contained within, or anything like that, since you
obviously omitted the code for that in this test patch.

So, yeah, I think that is sufficient.

[-- Attachment #2: Type: text/html, Size: 1498 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations.
  2019-04-02  9:34           ` Daniel Pittman
@ 2019-04-02 13:18             ` Michael Albinus
  0 siblings, 0 replies; 8+ messages in thread
From: Michael Albinus @ 2019-04-02 13:18 UTC (permalink / raw)
  To: Daniel Pittman; +Cc: emacs-devel

Daniel Pittman <slippycheeze@google.com> writes:

Hi Daniel,

>     Yes. Tramp fights indeed with timers, and so I have disabled
>     timers in tramp-accept-process-output already. Maybe we shall do
>     the same in tramp-send-string? Would the following patch help?
>
> In brief testing – 100 percent reproducible error, but only one
> instance – this patch did fix the problem.

Thanks for testing! I've pushed the patch, slightly extended, to the
repositories.

> I haven't tried to provoke a non-local exit from anything contained
> within, or anything like that, since you obviously omitted the code
> for that in this test patch.

Good catch. I've wrapped process-send-string by with-local-quit, as I
did already with accept-process-output. The other errors shall be
handled by the Tramp machinery.

> So, yeah, I think that is sufficient.

Please continue to stress Tramp, and report problems. Much appreciated!

Best regards, Michael.



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-04-02 13:18 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-03-27 15:38 TRAMP VC optimization fails: non-TRAMP filenames handled incorrectly in async operations Daniel Pittman
2019-03-27 15:55 ` Michael Albinus
2019-03-27 16:22   ` Daniel Pittman
2019-03-27 17:49     ` Michael Albinus
2019-03-29 12:36       ` Daniel Pittman
2019-03-29 17:03         ` Michael Albinus
2019-04-02  9:34           ` Daniel Pittman
2019-04-02 13:18             ` Michael Albinus

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).