(ignore-errors (cancel-timer timer))
(ignore-errors (delete-directory tmp-name 'recursive)))))))
+(ert-deftest tramp-test43-threads ()
+ "Check that Tramp cooperates with threads."
+ (skip-unless (tramp--test-enabled))
+ (skip-unless (featurep 'threads))
+ (skip-unless (= (length (all-threads)) 1))
+ (skip-unless (not (thread-last-error)))
+
+ ;; We cannot bind the variables dynamically; they are used in the threads.
+ (defvar tmp-name1 (tramp--test-make-temp-name))
+ (defvar tmp-name2 (tramp--test-make-temp-name))
+ (defvar tmp-mutex (make-mutex "mutex"))
+ (defvar tmp-condvar1 (make-condition-variable tmp-mutex "condvar1"))
+ (defvar tmp-condvar2 (make-condition-variable tmp-mutex "condvar2"))
+
+ ;; Rename simple file.
+ (unwind-protect
+ (let (tmp-thread1 tmp-thread2)
+ (write-region "foo" nil tmp-name1)
+ (should (file-exists-p tmp-name1))
+ (should-not (file-exists-p tmp-name2))
+
+ (should (mutexp tmp-mutex))
+ (should (condition-variable-p tmp-condvar1))
+ (should (condition-variable-p tmp-condvar2))
+
+ ;; This thread renames `tmp-name1' to `tmp-name2' twice.
+ (setq
+ tmp-thread1
+ (make-thread
+ (lambda ()
+ ;; Rename first time.
+ (rename-file tmp-name1 tmp-name2)
+ ;; Notify thread2.
+ (with-mutex (condition-mutex tmp-condvar2)
+ (condition-notify tmp-condvar2 t))
+ ;; Rename second time, once we've got notification from thread2.
+ (with-mutex (condition-mutex tmp-condvar1)
+ (condition-wait tmp-condvar1))
+ (rename-file tmp-name1 tmp-name2))
+ "thread1"))
+
+ (should (threadp tmp-thread1))
+ (should (thread-alive-p tmp-thread1))
+
+ ;; This thread renames `tmp-name2' to `tmp-name1' twice.
+ (setq
+ tmp-thread2
+ (make-thread
+ (lambda ()
+ ;; Rename first time, once we've got notification from thread1.
+ (with-mutex (condition-mutex tmp-condvar2)
+ (condition-wait tmp-condvar2))
+ (rename-file tmp-name2 tmp-name1)
+ ;; Notify thread1.
+ (with-mutex (condition-mutex tmp-condvar1)
+ (condition-notify tmp-condvar1 t))
+ ;; Rename second time, once we've got notification from
+ ;; the main thread.
+ (with-mutex (condition-mutex tmp-condvar2)
+ (condition-wait tmp-condvar2))
+ (rename-file tmp-name2 tmp-name1))
+ "thread2"))
+
+ (should (threadp tmp-thread2))
+ (should (thread-alive-p tmp-thread2))
+ (should (= (length (all-threads)) 3))
+
+ ;; Wait for thread1.
+ (thread-join tmp-thread1)
+ ;; Checks.
+ (should-not (thread-alive-p tmp-thread1))
+ (should (= (length (all-threads)) 2))
+ (should-not (thread-last-error))
+ (should (file-exists-p tmp-name2))
+ (should-not (file-exists-p tmp-name1))
+
+ ;; Notify thread2.
+ (with-mutex (condition-mutex tmp-condvar2)
+ (condition-notify tmp-condvar2 t))
+
+ ;; Wait for thread2.
+ (thread-join tmp-thread2)
+ ;; Checks.
+ (should-not (thread-alive-p tmp-thread2))
+ (should (= (length (all-threads)) 1))
+ (should-not (thread-last-error))
+ (should (file-exists-p tmp-name1))
+ (should-not (file-exists-p tmp-name2)))
+
+ ;; Cleanup.
+ (ignore-errors (delete-file tmp-name1))
+ (ignore-errors (delete-file tmp-name2))
+ ;; We could have spurious threads still running; wait for them to die.
+ (while (cdr (all-threads))
+ (thread-signal (cadr (all-threads)) 'error nil)
+ (thread-yield))
+ ;; Cleanup errors.
+ (thread-last-error 'cleanup)))
+
;; This test is inspired by Bug#29163.
-(ert-deftest tramp-test43-auto-load ()
+(ert-deftest tramp-test44-auto-load ()
"Check that Tramp autoloads properly."
+ (skip-unless (tramp--test-enabled))
+
(let ((default-directory (expand-file-name temporary-file-directory))
(code
(format