Tags: patch
Hi, to reproduce this issue please save the following elisp to proc.el:
(defvar p-stopped nil)
(defun my-sentinel (proc str)
(when (string-match "^\\(?:finished\n\\|exited abnormally\\|killed\n\\)"
str)
(setq p-stopped t)))
(defun wait-for-process-end (proc)
(while (not p-stopped)
(message "process status is: %s" (process-status proc))
(accept-process-output proc 0.1 nil t)))
(defun f ()
(with-temp-buffer
(inotify-add-watch "foo.txt" t #'ignore)
(let ((proc (start-process "p" (current-buffer) "bash" "-c" "touch foo.txt")))
(setq p-stopped nil)
(set-process-sentinel proc 'my-sentinel)
(wait-for-process-end proc))))
Please also create a file 'foo.txt'
$ touch foo.txt
Now, invoke the following command
$ emacs -Q --script proc.el --eval "(f)"
This command will never exit, and print "process status is: exit" forever.
The expected behavior is that, because process "p" is exited, its sentinel should be called, so 'wait-for-process-end'
will complete and Emacs will exit.
After some investigation, I found that 'wait_reading_process_output' in process.c never calls the sentinel
for the process because the pselect invocation in this code (src/process.c) always returns nonzero:
if ((thread_select (pselect, max_desc + 1,
&Atemp,
(num_pending_connects > 0 ? &Ctemp : NULL),
NULL, &timeout, NULL)
<= 0))
{
/* It's okay for us to do this and then continue with
the loop, since timeout has already been zeroed out. */
clear_waiting_for_input ();
got_some_output = status_notify (NULL, wait_proc);
if (do_display) redisplay_preserve_echo_area (13);
}
This pselect invocation always returns nonzero because the inotify fd for "foo.txt" is included in the pselect
readfds and is readable. However, the inotify fd is never handled within 'wait_reading_process_output'.
If I understand this code correctly, the intent here is to prioritize handling ready fds before calling 'status_notify',
which invokes sentinels. However, it seems inotify fds are not handled in 'wait_reading_process_output', so there is no reason to care about inotify fds here. I believe the correct fix is to filter for process fds in this pselect call. To accomplish this,
the included patch filters for process fds in 'compute_input_wait_mask'. It appears to me that all usage of 'compute_input_wait_mask' only cares about process fds, so I believe this is a safe change.
In GNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version
3.24.38, cairo version 1.17.8) of 2023-12-23 built on ostrich
Repository revision: 5c3ff1494b69bf45b99125f2423174222badfa43
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101011
System Description: Arch Linux
Configured using:
'configure --prefix=/usr --sysconfdir=/etc --libexecdir=/usr/lib
--localstatedir=/var --mandir=/usr/share/man --with-gameuser=:games
--with-modules --without-m17n-flt --without-gconf
--with-native-compilation=yes --with-xinput2 --with-x-toolkit=gtk3
--without-xaw3d --with-sound=no --with-tree-sitter --without-gpm
--without-compress-install
'--program-transform-name=s/\([ec]tags\)/\1.emacs/'
'CFLAGS=-march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions
-Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security
-fstack-clash-protection -fcf-protection'
LDFLAGS=-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now'