aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/net
diff options
context:
space:
mode:
authorMichael Albinus2017-06-29 18:22:38 +0200
committerMichael Albinus2017-06-29 18:22:38 +0200
commit138447c3abd749d1c27d99d7089b1b0903352ade (patch)
treef8ab4620eb071453168bacb339766e938b825954 /lisp/net
parent3b19663b44be29986ebaacfb3a3c95130cd65964 (diff)
downloademacs-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.el3
-rw-r--r--lisp/net/tramp-sh.el19
-rw-r--r--lisp/net/tramp.el91
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.
3502Fall back to normal file name handler if no Tramp handler exists." 3502Fall 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.
2075Together with `tramp-locker', this implements a locking mechanism
2076preventing reentrant calls of Tramp.")
2077
2078(defvar tramp-locker nil
2079 "If non-nil, then a caller has locked Tramp.
2080Together with `tramp-locked', this implements a locking mechanism
2081preventing 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.
2167Together with `tramp-locker', this implements a locking mechanism
2168preventing reentrant calls of Tramp.")
2169
2170(defvar tramp-locker nil
2171 "If non-nil, then a caller has locked Tramp.
2172Together with `tramp-locked', this implements a locking mechanism
2173preventing 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.
3632This is needed in order to hide `last-coding-system-used', which is set 3645This is needed in order to hide `last-coding-system-used', which is set
3633for process communication also." 3646for 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)