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 da4bc5c927)
This commit is contained in:
Jim Porter 2024-06-25 21:39:35 -07:00
parent 8b1841021c
commit 1809f6a93e
2 changed files with 40 additions and 22 deletions

View file

@ -530,28 +530,30 @@ PROC is the process that's exiting. STRING is the exit message."
(not (process-live-p proc)))) (not (process-live-p proc))))
(finish-io (finish-io
(lambda () (lambda ()
(if (or (process-get proc :eshell-busy) (with-current-buffer (process-buffer proc)
(and wait-for-stderr (car stderr-live))) (if (or (process-get proc :eshell-busy)
(progn (and wait-for-stderr (car stderr-live)))
(eshell-debug-command 'process (progn
"i/o busy for process `%s'" proc) (eshell-debug-command 'process
(run-at-time 0 nil finish-io)) "i/o busy for process `%s'" proc)
(when data (run-at-time 0 nil finish-io))
(ignore-error eshell-pipe-broken (when data
(eshell-output-object (ignore-error eshell-pipe-broken
data index handles))) (eshell-output-object
(eshell-close-handles data index handles)))
status (eshell-close-handles
(when status (list 'quote (= status 0))) status
handles) (when status (list 'quote (= status 0)))
;; Clear the handles to mark that we're 100% handles)
;; finished with the I/O for this process. ;; Clear the handles to mark that we're 100%
(process-put proc :eshell-handles nil) ;; finished with the I/O for this process.
(eshell-debug-command 'process (process-put proc :eshell-handles nil)
"finished external process `%s'" proc) (eshell-debug-command 'process
(if primary "finished external process `%s'" proc)
(run-hook-with-args 'eshell-kill-hook proc string) (if primary
(setcar stderr-live nil)))))) (run-hook-with-args 'eshell-kill-hook
proc string)
(setcar stderr-live nil)))))))
(funcall finish-io))) (funcall finish-io)))
(when-let ((entry (assq proc eshell-process-list))) (when-let ((entry (assq proc eshell-process-list)))
(eshell-remove-process-entry entry)))))) (eshell-remove-process-entry entry))))))

View file

@ -45,6 +45,8 @@
"'") "'")
"A shell command that prints the standard streams connected as TTYs.") "A shell command that prints the standard streams connected as TTYs.")
(defvar eshell-test-value nil)
;;; Tests: ;;; Tests:
@ -130,6 +132,20 @@
(should (= eshell-last-command-status 1)) (should (= eshell-last-command-status 1))
(should (eq eshell-last-command-result nil))))) (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 ;; Pipelines