diff options
| author | Michael Albinus | 2017-06-29 18:22:38 +0200 |
|---|---|---|
| committer | Michael Albinus | 2017-06-29 18:22:38 +0200 |
| commit | 138447c3abd749d1c27d99d7089b1b0903352ade (patch) | |
| tree | f8ab4620eb071453168bacb339766e938b825954 /lisp/net | |
| parent | 3b19663b44be29986ebaacfb3a3c95130cd65964 (diff) | |
| download | emacs-138447c3abd749d1c27d99d7089b1b0903352ade.tar.gz emacs-138447c3abd749d1c27d99d7089b1b0903352ade.zip | |
Improve timer handling when Tramp accepts output
* lisp/net/tramp-compat.el: Avoid compiler warning.
* lisp/net/tramp-sh.el (tramp-sh-file-name-handler):
Remove lock machinery.
* lisp/net/tramp.el (tramp-locked, tramp-locker): Move up.
(tramp-file-name-handler): Add lock machinery from
`tramp-sh-file-name-handler'. Allow timers to run.
(tramp-accept-process-output): Remove nasty workaround.
Suppress timers.
* test/lisp/net/tramp-tests.el (shell-command-sentinel):
Suppress run in tests.
(tramp--instrument-test-case-p): New defvar.
(tramp--instrument-test-case): Use it in order to allow nested calls.
(tramp--test-message, tramp--test-backtrace): New defsubst,
will be used for occasional test instrumentation.
(tramp-test00-availability, tramp-test31-vc-registered): Use them.
(tramp-test28-shell-command)
(tramp--test-shell-command-to-string-asynchronously): Suppress
nasty messages. Don't overwrite sentinel.
(tramp-test36-asynchronous-requests): Rewrite major parts.
Expect :passed.
Diffstat (limited to 'lisp/net')
| -rw-r--r-- | lisp/net/tramp-compat.el | 3 | ||||
| -rw-r--r-- | lisp/net/tramp-sh.el | 19 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 91 |
3 files changed, 51 insertions, 62 deletions
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el index c998df814c1..b2df4d6324b 100644 --- a/lisp/net/tramp-compat.el +++ b/lisp/net/tramp-compat.el | |||
| @@ -252,7 +252,8 @@ If NAME is a remote file name, the local part of NAME is unquoted." | |||
| 252 | (eval-after-load 'tramp | 252 | (eval-after-load 'tramp |
| 253 | '(unless | 253 | '(unless |
| 254 | (memq tramp-syntax (tramp-compat-funcall (quote tramp-syntax-values))) | 254 | (memq tramp-syntax (tramp-compat-funcall (quote tramp-syntax-values))) |
| 255 | (tramp-change-syntax (tramp-compat-tramp-syntax)))) | 255 | (tramp-compat-funcall |
| 256 | (quote tramp-change-syntax) (tramp-compat-tramp-syntax)))) | ||
| 256 | 257 | ||
| 257 | (provide 'tramp-compat) | 258 | (provide 'tramp-compat) |
| 258 | 259 | ||
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index f7b457ebf04..94518d0d359 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el | |||
| @@ -3500,21 +3500,10 @@ the result will be a local, non-Tramp, file name." | |||
| 3500 | (defun tramp-sh-file-name-handler (operation &rest args) | 3500 | (defun tramp-sh-file-name-handler (operation &rest args) |
| 3501 | "Invoke remote-shell Tramp file name handler. | 3501 | "Invoke remote-shell Tramp file name handler. |
| 3502 | Fall back to normal file name handler if no Tramp handler exists." | 3502 | Fall back to normal file name handler if no Tramp handler exists." |
| 3503 | (when (and tramp-locked (not tramp-locker)) | 3503 | (let ((fn (assoc operation tramp-sh-file-name-handler-alist))) |
| 3504 | (setq tramp-locked nil) | 3504 | (if fn |
| 3505 | (tramp-error | 3505 | (save-match-data (apply (cdr fn) args)) |
| 3506 | (car-safe tramp-current-connection) 'file-error | 3506 | (tramp-run-real-handler operation args)))) |
| 3507 | "Forbidden reentrant call of Tramp")) | ||
| 3508 | (let ((tl tramp-locked)) | ||
| 3509 | (setq tramp-locked t) | ||
| 3510 | (unwind-protect | ||
| 3511 | (let ((tramp-locker t)) | ||
| 3512 | (save-match-data | ||
| 3513 | (let ((fn (assoc operation tramp-sh-file-name-handler-alist))) | ||
| 3514 | (if fn | ||
| 3515 | (apply (cdr fn) args) | ||
| 3516 | (tramp-run-real-handler operation args))))) | ||
| 3517 | (setq tramp-locked tl)))) | ||
| 3518 | 3507 | ||
| 3519 | ;; This must be the last entry, because `identity' always matches. | 3508 | ;; This must be the last entry, because `identity' always matches. |
| 3520 | ;;;###tramp-autoload | 3509 | ;;;###tramp-autoload |
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 8d81ac64aa2..9c327c410a7 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el | |||
| @@ -2053,6 +2053,33 @@ ARGS are the arguments OPERATION has been called with." | |||
| 2053 | `(let ((debug-on-error tramp-debug-on-error)) | 2053 | `(let ((debug-on-error tramp-debug-on-error)) |
| 2054 | (condition-case-unless-debug ,var ,bodyform ,@handlers))) | 2054 | (condition-case-unless-debug ,var ,bodyform ,@handlers))) |
| 2055 | 2055 | ||
| 2056 | ;; In Emacs, there is some concurrency due to timers. If a timer | ||
| 2057 | ;; interrupts Tramp and wishes to use the same connection buffer as | ||
| 2058 | ;; the "main" Emacs, then garbage might occur in the connection | ||
| 2059 | ;; buffer. Therefore, we need to make sure that a timer does not use | ||
| 2060 | ;; the same connection buffer as the "main" Emacs. We implement a | ||
| 2061 | ;; cheap global lock, instead of locking each connection buffer | ||
| 2062 | ;; separately. The global lock is based on two variables, | ||
| 2063 | ;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true | ||
| 2064 | ;; (with setq) to indicate a lock. But Tramp also calls itself during | ||
| 2065 | ;; processing of a single file operation, so we need to allow | ||
| 2066 | ;; recursive calls. That's where the `tramp-locker' variable comes in | ||
| 2067 | ;; -- it is let-bound to t during the execution of the current | ||
| 2068 | ;; handler. So if `tramp-locked' is t and `tramp-locker' is also t, | ||
| 2069 | ;; then we should just proceed because we have been called | ||
| 2070 | ;; recursively. But if `tramp-locker' is nil, then we are a timer | ||
| 2071 | ;; interrupting the "main" Emacs, and then we signal an error. | ||
| 2072 | |||
| 2073 | (defvar tramp-locked nil | ||
| 2074 | "If non-nil, then Tramp is currently busy. | ||
| 2075 | Together with `tramp-locker', this implements a locking mechanism | ||
| 2076 | preventing reentrant calls of Tramp.") | ||
| 2077 | |||
| 2078 | (defvar tramp-locker nil | ||
| 2079 | "If non-nil, then a caller has locked Tramp. | ||
| 2080 | Together with `tramp-locked', this implements a locking mechanism | ||
| 2081 | preventing reentrant calls of Tramp.") | ||
| 2082 | |||
| 2056 | ;; Main function. | 2083 | ;; Main function. |
| 2057 | (defun tramp-file-name-handler (operation &rest args) | 2084 | (defun tramp-file-name-handler (operation &rest args) |
| 2058 | "Invoke Tramp file name handler. | 2085 | "Invoke Tramp file name handler. |
| @@ -2090,7 +2117,20 @@ Falls back to normal file name handler if no Tramp file name handler exists." | |||
| 2090 | (setq result | 2117 | (setq result |
| 2091 | (catch 'non-essential | 2118 | (catch 'non-essential |
| 2092 | (catch 'suppress | 2119 | (catch 'suppress |
| 2093 | (apply foreign operation args)))) | 2120 | (when (and tramp-locked (not tramp-locker)) |
| 2121 | (setq tramp-locked nil) | ||
| 2122 | (tramp-error | ||
| 2123 | (car-safe tramp-current-connection) | ||
| 2124 | 'file-error | ||
| 2125 | "Forbidden reentrant call of Tramp")) | ||
| 2126 | (let ((tl tramp-locked)) | ||
| 2127 | (setq tramp-locked t) | ||
| 2128 | (unwind-protect | ||
| 2129 | (let ((tramp-locker t)) | ||
| 2130 | (apply foreign operation args)) | ||
| 2131 | ;; Give timers a chance. | ||
| 2132 | (unless (setq tramp-locked tl) | ||
| 2133 | (sit-for 0.001 'nodisp))))))) | ||
| 2094 | (cond | 2134 | (cond |
| 2095 | ((eq result 'non-essential) | 2135 | ((eq result 'non-essential) |
| 2096 | (tramp-message | 2136 | (tramp-message |
| @@ -2145,33 +2185,6 @@ Falls back to normal file name handler if no Tramp file name handler exists." | |||
| 2145 | ;; we don't do anything. | 2185 | ;; we don't do anything. |
| 2146 | (tramp-run-real-handler operation args)))) | 2186 | (tramp-run-real-handler operation args)))) |
| 2147 | 2187 | ||
| 2148 | ;; In Emacs, there is some concurrency due to timers. If a timer | ||
| 2149 | ;; interrupts Tramp and wishes to use the same connection buffer as | ||
| 2150 | ;; the "main" Emacs, then garbage might occur in the connection | ||
| 2151 | ;; buffer. Therefore, we need to make sure that a timer does not use | ||
| 2152 | ;; the same connection buffer as the "main" Emacs. We implement a | ||
| 2153 | ;; cheap global lock, instead of locking each connection buffer | ||
| 2154 | ;; separately. The global lock is based on two variables, | ||
| 2155 | ;; `tramp-locked' and `tramp-locker'. `tramp-locked' is set to true | ||
| 2156 | ;; (with setq) to indicate a lock. But Tramp also calls itself during | ||
| 2157 | ;; processing of a single file operation, so we need to allow | ||
| 2158 | ;; recursive calls. That's where the `tramp-locker' variable comes in | ||
| 2159 | ;; -- it is let-bound to t during the execution of the current | ||
| 2160 | ;; handler. So if `tramp-locked' is t and `tramp-locker' is also t, | ||
| 2161 | ;; then we should just proceed because we have been called | ||
| 2162 | ;; recursively. But if `tramp-locker' is nil, then we are a timer | ||
| 2163 | ;; interrupting the "main" Emacs, and then we signal an error. | ||
| 2164 | |||
| 2165 | (defvar tramp-locked nil | ||
| 2166 | "If non-nil, then Tramp is currently busy. | ||
| 2167 | Together with `tramp-locker', this implements a locking mechanism | ||
| 2168 | preventing reentrant calls of Tramp.") | ||
| 2169 | |||
| 2170 | (defvar tramp-locker nil | ||
| 2171 | "If non-nil, then a caller has locked Tramp. | ||
| 2172 | Together with `tramp-locked', this implements a locking mechanism | ||
| 2173 | preventing reentrant calls of Tramp.") | ||
| 2174 | |||
| 2175 | ;;;###autoload | 2188 | ;;;###autoload |
| 2176 | (defun tramp-completion-file-name-handler (operation &rest args) | 2189 | (defun tramp-completion-file-name-handler (operation &rest args) |
| 2177 | "Invoke Tramp file name completion handler. | 2190 | "Invoke Tramp file name completion handler. |
| @@ -3631,31 +3644,17 @@ connection buffer." | |||
| 3631 | "Like `accept-process-output' for Tramp processes. | 3644 | "Like `accept-process-output' for Tramp processes. |
| 3632 | This is needed in order to hide `last-coding-system-used', which is set | 3645 | This is needed in order to hide `last-coding-system-used', which is set |
| 3633 | for process communication also." | 3646 | for process communication also." |
| 3634 | ;; FIXME: There are problems, when an asynchronous process runs in | ||
| 3635 | ;; parallel, and also timers are active. See | ||
| 3636 | ;; <http://lists.gnu.org/archive/html/tramp-devel/2017-01/msg00010.html>. | ||
| 3637 | (when (and timer-event-last | ||
| 3638 | (string-prefix-p "*tramp/" (process-name proc)) | ||
| 3639 | (let (result) | ||
| 3640 | (maphash | ||
| 3641 | (lambda (key _value) | ||
| 3642 | (and (processp key) | ||
| 3643 | (not (string-prefix-p "*tramp/" (process-name key))) | ||
| 3644 | (process-live-p key) | ||
| 3645 | (setq result t))) | ||
| 3646 | tramp-cache-data) | ||
| 3647 | result)) | ||
| 3648 | (sit-for 0.01 'nodisp)) | ||
| 3649 | (with-current-buffer (process-buffer proc) | 3647 | (with-current-buffer (process-buffer proc) |
| 3650 | (let (buffer-read-only last-coding-system-used) | 3648 | (let (buffer-read-only last-coding-system-used) |
| 3651 | ;; Under Windows XP, accept-process-output doesn't return | 3649 | ;; Under Windows XP, `accept-process-output' doesn't return |
| 3652 | ;; sometimes. So we add an additional timeout. JUST-THIS-ONE | 3650 | ;; sometimes. So we add an additional timeout. JUST-THIS-ONE |
| 3653 | ;; is set due to Bug#12145. | 3651 | ;; is set due to Bug#12145. It is an integer, in order to avoid |
| 3652 | ;; running timers as well. | ||
| 3654 | (tramp-message | 3653 | (tramp-message |
| 3655 | proc 10 "%s %s %s\n%s" | 3654 | proc 10 "%s %s %s\n%s" |
| 3656 | proc (process-status proc) | 3655 | proc (process-status proc) |
| 3657 | (with-timeout (timeout) | 3656 | (with-timeout (timeout) |
| 3658 | (accept-process-output proc timeout nil t)) | 3657 | (accept-process-output proc timeout nil 0)) |
| 3659 | (buffer-string))))) | 3658 | (buffer-string))))) |
| 3660 | 3659 | ||
| 3661 | (defun tramp-check-for-regexp (proc regexp) | 3660 | (defun tramp-check-for-regexp (proc regexp) |