From a5d4c3659b7029fd58138210fb47249e77f65e15 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Tue, 25 Jun 2024 21:39:35 -0700 Subject: [PATCH] Always perform Eshell process cleanup runs in the Eshell buffer Previously, some code executed in a timer, which could execute in the wrong buffer, leading to a hang. * lisp/eshell/esh-proc.el (eshell-sentinel): Use 'with-current-buffer' in the timer function. * test/lisp/eshell/esh-proc-tests.el (eshell-test-value): New variable. (esh-proc-test/sentinel/change-buffer): New test. (cherry picked from commit da4bc5c9274a6705501e24fb8f2984f5bf5fe099) --- lisp/eshell/esh-proc.el | 46 ++++++++++++++++-------------- test/lisp/eshell/esh-proc-tests.el | 16 +++++++++++ 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index e05590f2542..2ff41c3d409 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -530,28 +530,30 @@ PROC is the process that's exiting. STRING is the exit message." (not (process-live-p proc)))) (finish-io (lambda () - (if (or (process-get proc :eshell-busy) - (and wait-for-stderr (car stderr-live))) - (progn - (eshell-debug-command 'process - "i/o busy for process `%s'" proc) - (run-at-time 0 nil finish-io)) - (when data - (ignore-error eshell-pipe-broken - (eshell-output-object - data index handles))) - (eshell-close-handles - status - (when status (list 'quote (= status 0))) - handles) - ;; Clear the handles to mark that we're 100% - ;; finished with the I/O for this process. - (process-put proc :eshell-handles nil) - (eshell-debug-command 'process - "finished external process `%s'" proc) - (if primary - (run-hook-with-args 'eshell-kill-hook proc string) - (setcar stderr-live nil)))))) + (with-current-buffer (process-buffer proc) + (if (or (process-get proc :eshell-busy) + (and wait-for-stderr (car stderr-live))) + (progn + (eshell-debug-command 'process + "i/o busy for process `%s'" proc) + (run-at-time 0 nil finish-io)) + (when data + (ignore-error eshell-pipe-broken + (eshell-output-object + data index handles))) + (eshell-close-handles + status + (when status (list 'quote (= status 0))) + handles) + ;; Clear the handles to mark that we're 100% + ;; finished with the I/O for this process. + (process-put proc :eshell-handles nil) + (eshell-debug-command 'process + "finished external process `%s'" proc) + (if primary + (run-hook-with-args 'eshell-kill-hook + proc string) + (setcar stderr-live nil))))))) (funcall finish-io))) (when-let ((entry (assq proc eshell-process-list))) (eshell-remove-process-entry entry)))))) diff --git a/test/lisp/eshell/esh-proc-tests.el b/test/lisp/eshell/esh-proc-tests.el index 643cb8b125a..85b02845ab3 100644 --- a/test/lisp/eshell/esh-proc-tests.el +++ b/test/lisp/eshell/esh-proc-tests.el @@ -45,6 +45,8 @@ "'") "A shell command that prints the standard streams connected as TTYs.") +(defvar eshell-test-value nil) + ;;; Tests: @@ -130,6 +132,20 @@ (should (= eshell-last-command-status 1)) (should (eq eshell-last-command-result nil))))) +(ert-deftest esh-proc-test/sentinel/change-buffer () + "Check that changing the current buffer while running a command works. +See bug#71778." + (eshell-with-temp-buffer bufname "" + (with-temp-eshell + (let (eshell-test-value) + (eshell-insert-command + (concat (format "for i in 1 2 {sleep 1; echo hello} > #<%s>; " bufname) + "setq eshell-test-value t")) + (with-current-buffer bufname + (eshell-wait-for (lambda () eshell-test-value)) + (should (equal (buffer-string) "hellohello"))) + (eshell-match-command-output "echo goodbye" "\\`goodbye\n"))))) + ;; Pipelines -- 2.39.2