diff options
| author | Paul Eggert | 2012-12-03 13:42:12 -0800 |
|---|---|---|
| committer | Paul Eggert | 2012-12-03 13:42:12 -0800 |
| commit | bb5f74ee84398a56435baa2ef15e12d8a35e5e03 (patch) | |
| tree | 4bb59aacd4d69b873154ce576e51fe8efe345150 | |
| parent | bc9dbce6ee527ded152682c98f5f82e42c33dde9 (diff) | |
| download | emacs-bb5f74ee84398a56435baa2ef15e12d8a35e5e03.tar.gz emacs-bb5f74ee84398a56435baa2ef15e12d8a35e5e03.zip | |
Don't let call-process be a zombie factory.
Fixing this bug required some cleanup of the signal-handling code.
As a side effect, this change also fixes a longstanding rare race
condition whereby Emacs could mistakenly kill unrelated processes,
and it fixes a bug where a second C-g does not kill a recalcitrant
synchronous process in GNU/Linux and similar platforms.
The patch should also fix the last vestiges of Bug#9488,
a bug which has mostly been fixed on the trunk by other changes.
* callproc.c, process.h (synch_process_alive, synch_process_death)
(synch_process_termsig, sync_process_retcode):
Remove. All uses removed, to simplify analysis and so that
less consing is done inside critical sections.
* callproc.c (call_process_exited): Remove. All uses replaced
with !synch_process_pid.
* callproc.c (synch_process_pid, synch_process_fd): New static vars.
These take the role of what used to be in unwind-protect arg.
All uses changed.
(block_child_signal, unblock_child_signal):
New functions, to avoid races that could kill innocent-victim processes.
(call_process_kill, call_process_cleanup, Fcall_process): Use them.
(call_process_kill): Record killed processes as deleted, so that
zombies do not clutter up the system. Do this inside a critical
section, to avoid a race that would allow the clutter.
(call_process_cleanup): Fix code so that the second C-g works again
on common platforms such as GNU/Linux.
(Fcall_process): Create the child process in a critical section,
to fix a race condition. If creating an asynchronous process,
record it as deleted so that zombies do not clutter up the system.
Do unwind-protect for WINDOWSNT too, as that's simpler in the
light of these changes. Omit unnecessary call to emacs_close
before failure, as the unwind-protect code does that.
* callproc.c (call_process_cleanup):
* w32proc.c (waitpid): Simplify now that synch_process_alive is gone.
* process.c (record_deleted_pid): New function, containing
code refactored out of Fdelete_process.
(Fdelete_process): Use it.
(process_status_retrieved): Remove. All callers changed to use
child_status_change.
(record_child_status_change): Remove, folding its contents into ...
(handle_child_signal): ... this signal handler. Now, this
function is purely a handler for SIGCHLD, and is not called after
a synchronous waitpid returns; the synchronous code is moved to
wait_for_termination. There is no need to worry about reaping
more than one child now.
* sysdep.c (get_child_status, child_status_changed): New functions.
(wait_for_termination): Now takes int * status and bool
interruptible arguments, too. Do not record child status change;
that's now the caller's responsibility. All callers changed.
Reimplement in terms of get_child_status.
(wait_for_termination_1, interruptible_wait_for_termination):
Remove. All callers changed to use wait_for_termination.
* syswait.h: Include <stdbool.h>, for bool.
(record_child_status_change, interruptible_wait_for_termination):
Remove decls.
(record_deleted_pid, child_status_changed): New decls.
(wait_for_termination): Adjust to API changes noted above.
Fixes: debbugs:12980
| -rw-r--r-- | src/ChangeLog | 57 | ||||
| -rw-r--r-- | src/callproc.c | 238 | ||||
| -rw-r--r-- | src/process.c | 136 | ||||
| -rw-r--r-- | src/process.h | 17 | ||||
| -rw-r--r-- | src/sysdep.c | 80 | ||||
| -rw-r--r-- | src/syswait.h | 7 | ||||
| -rw-r--r-- | src/w32proc.c | 28 |
7 files changed, 296 insertions, 267 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 019caf306b7..1a91eb0f1a3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,62 @@ | |||
| 1 | 2012-12-03 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2012-12-03 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | Don't let call-process be a zombie factory (Bug#12980). | ||
| 4 | Fixing this bug required some cleanup of the signal-handling code. | ||
| 5 | As a side effect, this change also fixes a longstanding rare race | ||
| 6 | condition whereby Emacs could mistakenly kill unrelated processes, | ||
| 7 | and it fixes a bug where a second C-g does not kill a recalcitrant | ||
| 8 | synchronous process in GNU/Linux and similar platforms. | ||
| 9 | The patch should also fix the last vestiges of Bug#9488, | ||
| 10 | a bug which has mostly been fixed on the trunk by other changes. | ||
| 11 | * callproc.c, process.h (synch_process_alive, synch_process_death) | ||
| 12 | (synch_process_termsig, sync_process_retcode): | ||
| 13 | Remove. All uses removed, to simplify analysis and so that | ||
| 14 | less consing is done inside critical sections. | ||
| 15 | * callproc.c (call_process_exited): Remove. All uses replaced | ||
| 16 | with !synch_process_pid. | ||
| 17 | * callproc.c (synch_process_pid, synch_process_fd): New static vars. | ||
| 18 | These take the role of what used to be in unwind-protect arg. | ||
| 19 | All uses changed. | ||
| 20 | (block_child_signal, unblock_child_signal): | ||
| 21 | New functions, to avoid races that could kill innocent-victim processes. | ||
| 22 | (call_process_kill, call_process_cleanup, Fcall_process): Use them. | ||
| 23 | (call_process_kill): Record killed processes as deleted, so that | ||
| 24 | zombies do not clutter up the system. Do this inside a critical | ||
| 25 | section, to avoid a race that would allow the clutter. | ||
| 26 | (call_process_cleanup): Fix code so that the second C-g works again | ||
| 27 | on common platforms such as GNU/Linux. | ||
| 28 | (Fcall_process): Create the child process in a critical section, | ||
| 29 | to fix a race condition. If creating an asynchronous process, | ||
| 30 | record it as deleted so that zombies do not clutter up the system. | ||
| 31 | Do unwind-protect for WINDOWSNT too, as that's simpler in the | ||
| 32 | light of these changes. Omit unnecessary call to emacs_close | ||
| 33 | before failure, as the unwind-protect code does that. | ||
| 34 | * callproc.c (call_process_cleanup): | ||
| 35 | * w32proc.c (waitpid): Simplify now that synch_process_alive is gone. | ||
| 36 | * process.c (record_deleted_pid): New function, containing | ||
| 37 | code refactored out of Fdelete_process. | ||
| 38 | (Fdelete_process): Use it. | ||
| 39 | (process_status_retrieved): Remove. All callers changed to use | ||
| 40 | child_status_change. | ||
| 41 | (record_child_status_change): Remove, folding its contents into ... | ||
| 42 | (handle_child_signal): ... this signal handler. Now, this | ||
| 43 | function is purely a handler for SIGCHLD, and is not called after | ||
| 44 | a synchronous waitpid returns; the synchronous code is moved to | ||
| 45 | wait_for_termination. There is no need to worry about reaping | ||
| 46 | more than one child now. | ||
| 47 | * sysdep.c (get_child_status, child_status_changed): New functions. | ||
| 48 | (wait_for_termination): Now takes int * status and bool | ||
| 49 | interruptible arguments, too. Do not record child status change; | ||
| 50 | that's now the caller's responsibility. All callers changed. | ||
| 51 | Reimplement in terms of get_child_status. | ||
| 52 | (wait_for_termination_1, interruptible_wait_for_termination): | ||
| 53 | Remove. All callers changed to use wait_for_termination. | ||
| 54 | * syswait.h: Include <stdbool.h>, for bool. | ||
| 55 | (record_child_status_change, interruptible_wait_for_termination): | ||
| 56 | Remove decls. | ||
| 57 | (record_deleted_pid, child_status_changed): New decls. | ||
| 58 | (wait_for_termination): Adjust to API changes noted above. | ||
| 59 | |||
| 3 | * bytecode.c, lisp.h (Qbytecode): Remove. | 60 | * bytecode.c, lisp.h (Qbytecode): Remove. |
| 4 | No longer needed after 2012-11-20 interactive-p changes. | 61 | No longer needed after 2012-11-20 interactive-p changes. |
| 5 | 62 | ||
diff --git a/src/callproc.c b/src/callproc.c index 0242755eb5f..21c52d09e6b 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -67,88 +67,110 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 67 | /* Pattern used by call-process-region to make temp files. */ | 67 | /* Pattern used by call-process-region to make temp files. */ |
| 68 | static Lisp_Object Vtemp_file_name_pattern; | 68 | static Lisp_Object Vtemp_file_name_pattern; |
| 69 | 69 | ||
| 70 | /* True if we are about to fork off a synchronous process or if we | 70 | /* The next two variables are valid only while record-unwind-protect |
| 71 | are waiting for it. */ | 71 | is in place during call-process for a synchronous subprocess. At |
| 72 | bool synch_process_alive; | 72 | other times, their contents are irrelevant. Doing this via static |
| 73 | 73 | C variables is more convenient than putting them into the arguments | |
| 74 | /* Nonzero => this is a string explaining death of synchronous subprocess. */ | 74 | of record-unwind-protect, as they need to be updated at randomish |
| 75 | const char *synch_process_death; | 75 | times in the code, and Lisp cannot always store these values as |
| 76 | Emacs integers. It's safe to use static variables here, as the | ||
| 77 | code is never invoked reentrantly. */ | ||
| 78 | |||
| 79 | /* If nonzero, a process-ID that has not been reaped. */ | ||
| 80 | static pid_t synch_process_pid; | ||
| 81 | |||
| 82 | /* If nonnegative, a file descriptor that has not been closed. */ | ||
| 83 | static int synch_process_fd; | ||
| 84 | |||
| 85 | /* Block SIGCHLD. */ | ||
| 76 | 86 | ||
| 77 | /* Nonzero => this is the signal number that terminated the subprocess. */ | 87 | static void |
| 78 | int synch_process_termsig; | 88 | block_child_signal (void) |
| 89 | { | ||
| 90 | #ifdef SIGCHLD | ||
| 91 | sigset_t blocked; | ||
| 92 | sigemptyset (&blocked); | ||
| 93 | sigaddset (&blocked, SIGCHLD); | ||
| 94 | pthread_sigmask (SIG_BLOCK, &blocked, 0); | ||
| 95 | #endif | ||
| 96 | } | ||
| 79 | 97 | ||
| 80 | /* If synch_process_death is zero, | 98 | /* Unblock SIGCHLD. */ |
| 81 | this is exit code of synchronous subprocess. */ | ||
| 82 | int synch_process_retcode; | ||
| 83 | 99 | ||
| 84 | 100 | static void | |
| 85 | /* Clean up when exiting Fcall_process. | 101 | unblock_child_signal (void) |
| 86 | On MSDOS, delete the temporary file on any kind of termination. | 102 | { |
| 87 | On Unix, kill the process and any children on termination by signal. */ | 103 | #ifdef SIGCHLD |
| 104 | pthread_sigmask (SIG_SETMASK, &empty_mask, 0); | ||
| 105 | #endif | ||
| 106 | } | ||
| 88 | 107 | ||
| 89 | /* True if this is termination due to exit. */ | 108 | /* Clean up when exiting call_process_cleanup. */ |
| 90 | static bool call_process_exited; | ||
| 91 | 109 | ||
| 92 | static Lisp_Object | 110 | static Lisp_Object |
| 93 | call_process_kill (Lisp_Object fdpid) | 111 | call_process_kill (Lisp_Object ignored) |
| 94 | { | 112 | { |
| 95 | int fd; | 113 | if (0 <= synch_process_fd) |
| 96 | pid_t pid; | 114 | emacs_close (synch_process_fd); |
| 97 | CONS_TO_INTEGER (Fcar (fdpid), int, fd); | 115 | |
| 98 | CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid); | 116 | /* If PID is reapable, kill it and record it as a deleted process. |
| 99 | emacs_close (fd); | 117 | Do this in a critical section. Unless PID is wedged it will be |
| 100 | EMACS_KILLPG (pid, SIGKILL); | 118 | reaped on receipt of the first SIGCHLD after the critical section. */ |
| 101 | synch_process_alive = 0; | 119 | if (synch_process_pid) |
| 120 | { | ||
| 121 | block_child_signal (); | ||
| 122 | record_deleted_pid (synch_process_pid); | ||
| 123 | EMACS_KILLPG (synch_process_pid, SIGKILL); | ||
| 124 | unblock_child_signal (); | ||
| 125 | } | ||
| 126 | |||
| 102 | return Qnil; | 127 | return Qnil; |
| 103 | } | 128 | } |
| 104 | 129 | ||
| 130 | /* Clean up when exiting Fcall_process. | ||
| 131 | On MSDOS, delete the temporary file on any kind of termination. | ||
| 132 | On Unix, kill the process and any children on termination by signal. */ | ||
| 133 | |||
| 105 | static Lisp_Object | 134 | static Lisp_Object |
| 106 | call_process_cleanup (Lisp_Object arg) | 135 | call_process_cleanup (Lisp_Object arg) |
| 107 | { | 136 | { |
| 108 | Lisp_Object fdpid = Fcdr (arg); | 137 | #ifdef MSDOS |
| 109 | int fd; | 138 | Lisp_Object buffer = Fcar (arg); |
| 110 | #if defined (MSDOS) | 139 | Lisp_Object file = Fcdr (arg); |
| 111 | Lisp_Object file; | ||
| 112 | #else | 140 | #else |
| 113 | pid_t pid; | 141 | Lisp_Object buffer = arg; |
| 114 | #endif | 142 | #endif |
| 115 | 143 | ||
| 116 | Fset_buffer (Fcar (arg)); | 144 | Fset_buffer (buffer); |
| 117 | CONS_TO_INTEGER (Fcar (fdpid), int, fd); | ||
| 118 | |||
| 119 | #if defined (MSDOS) | ||
| 120 | /* for MSDOS fdpid is really (fd . tempfile) */ | ||
| 121 | file = Fcdr (fdpid); | ||
| 122 | /* FD is -1 and FILE is "" when we didn't actually create a | ||
| 123 | temporary file in call-process. */ | ||
| 124 | if (fd >= 0) | ||
| 125 | emacs_close (fd); | ||
| 126 | if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0')) | ||
| 127 | unlink (SDATA (file)); | ||
| 128 | #else /* not MSDOS */ | ||
| 129 | CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid); | ||
| 130 | 145 | ||
| 131 | if (call_process_exited) | 146 | #ifndef MSDOS |
| 132 | { | 147 | /* If the process still exists, kill its process group. */ |
| 133 | emacs_close (fd); | 148 | if (synch_process_pid) |
| 134 | return Qnil; | ||
| 135 | } | ||
| 136 | |||
| 137 | if (EMACS_KILLPG (pid, SIGINT) == 0) | ||
| 138 | { | 149 | { |
| 139 | ptrdiff_t count = SPECPDL_INDEX (); | 150 | ptrdiff_t count = SPECPDL_INDEX (); |
| 140 | record_unwind_protect (call_process_kill, fdpid); | 151 | EMACS_KILLPG (synch_process_pid, SIGINT); |
| 152 | record_unwind_protect (call_process_kill, make_number (0)); | ||
| 141 | message1 ("Waiting for process to die...(type C-g again to kill it instantly)"); | 153 | message1 ("Waiting for process to die...(type C-g again to kill it instantly)"); |
| 142 | immediate_quit = 1; | 154 | immediate_quit = 1; |
| 143 | QUIT; | 155 | QUIT; |
| 144 | wait_for_termination (pid); | 156 | wait_for_termination (synch_process_pid, 0, 1); |
| 157 | synch_process_pid = 0; | ||
| 145 | immediate_quit = 0; | 158 | immediate_quit = 0; |
| 146 | specpdl_ptr = specpdl + count; /* Discard the unwind protect. */ | 159 | specpdl_ptr = specpdl + count; /* Discard the unwind protect. */ |
| 147 | message1 ("Waiting for process to die...done"); | 160 | message1 ("Waiting for process to die...done"); |
| 148 | } | 161 | } |
| 149 | synch_process_alive = 0; | 162 | #endif |
| 150 | emacs_close (fd); | 163 | |
| 151 | #endif /* not MSDOS */ | 164 | if (0 <= synch_process_fd) |
| 165 | emacs_close (synch_process_fd); | ||
| 166 | |||
| 167 | #ifdef MSDOS | ||
| 168 | /* FILE is "" when we didn't actually create a temporary file in | ||
| 169 | call-process. */ | ||
| 170 | if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0')) | ||
| 171 | unlink (SDATA (file)); | ||
| 172 | #endif | ||
| 173 | |||
| 152 | return Qnil; | 174 | return Qnil; |
| 153 | } | 175 | } |
| 154 | 176 | ||
| @@ -181,9 +203,10 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again. | |||
| 181 | usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | 203 | usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) |
| 182 | (ptrdiff_t nargs, Lisp_Object *args) | 204 | (ptrdiff_t nargs, Lisp_Object *args) |
| 183 | { | 205 | { |
| 184 | Lisp_Object infile, buffer, current_dir, path, cleanup_info_tail; | 206 | Lisp_Object infile, buffer, current_dir, path; |
| 185 | bool display_p; | 207 | bool display_p; |
| 186 | int fd0, fd1, filefd; | 208 | int fd0, fd1, filefd; |
| 209 | int status; | ||
| 187 | ptrdiff_t count = SPECPDL_INDEX (); | 210 | ptrdiff_t count = SPECPDL_INDEX (); |
| 188 | USE_SAFE_ALLOCA; | 211 | USE_SAFE_ALLOCA; |
| 189 | 212 | ||
| @@ -199,7 +222,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 199 | #else | 222 | #else |
| 200 | pid_t pid; | 223 | pid_t pid; |
| 201 | #endif | 224 | #endif |
| 202 | int vfork_errno; | 225 | int child_errno; |
| 203 | int fd_output = -1; | 226 | int fd_output = -1; |
| 204 | struct coding_system process_coding; /* coding-system of process output */ | 227 | struct coding_system process_coding; /* coding-system of process output */ |
| 205 | struct coding_system argument_coding; /* coding-system of arguments */ | 228 | struct coding_system argument_coding; /* coding-system of arguments */ |
| @@ -493,16 +516,6 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 493 | if (fd_output >= 0) | 516 | if (fd_output >= 0) |
| 494 | fd1 = fd_output; | 517 | fd1 = fd_output; |
| 495 | 518 | ||
| 496 | /* Record that we're about to create a synchronous process. */ | ||
| 497 | synch_process_alive = 1; | ||
| 498 | |||
| 499 | /* These vars record information from process termination. | ||
| 500 | Clear them now before process can possibly terminate, | ||
| 501 | to avoid timing error if process terminates soon. */ | ||
| 502 | synch_process_death = 0; | ||
| 503 | synch_process_retcode = 0; | ||
| 504 | synch_process_termsig = 0; | ||
| 505 | |||
| 506 | if (NILP (error_file)) | 519 | if (NILP (error_file)) |
| 507 | fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0); | 520 | fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0); |
| 508 | else if (STRINGP (error_file)) | 521 | else if (STRINGP (error_file)) |
| @@ -535,23 +548,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 535 | 548 | ||
| 536 | #ifdef MSDOS /* MW, July 1993 */ | 549 | #ifdef MSDOS /* MW, July 1993 */ |
| 537 | /* Note that on MSDOS `child_setup' actually returns the child process | 550 | /* Note that on MSDOS `child_setup' actually returns the child process |
| 538 | exit status, not its PID, so we assign it to `synch_process_retcode' | 551 | exit status, not its PID, so assign it to status below. */ |
| 539 | below. */ | ||
| 540 | pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir); | 552 | pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir); |
| 541 | 553 | child_errno = errno; | |
| 542 | /* Record that the synchronous process exited and note its | ||
| 543 | termination status. */ | ||
| 544 | synch_process_alive = 0; | ||
| 545 | synch_process_retcode = pid; | ||
| 546 | if (synch_process_retcode < 0) /* means it couldn't be exec'ed */ | ||
| 547 | { | ||
| 548 | synchronize_system_messages_locale (); | ||
| 549 | synch_process_death = strerror (errno); | ||
| 550 | } | ||
| 551 | 554 | ||
| 552 | emacs_close (outfilefd); | 555 | emacs_close (outfilefd); |
| 553 | if (fd_error != outfilefd) | 556 | if (fd_error != outfilefd) |
| 554 | emacs_close (fd_error); | 557 | emacs_close (fd_error); |
| 558 | if (pid < 0) | ||
| 559 | { | ||
| 560 | synchronize_system_messages_locale (); | ||
| 561 | return | ||
| 562 | code_convert_string_norecord (build_string (strerror (child_errno)), | ||
| 563 | Vlocale_coding_system, 0); | ||
| 564 | } | ||
| 565 | status = pid; | ||
| 555 | fd1 = -1; /* No harm in closing that one! */ | 566 | fd1 = -1; /* No harm in closing that one! */ |
| 556 | if (tempfile) | 567 | if (tempfile) |
| 557 | { | 568 | { |
| @@ -569,12 +580,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 569 | else | 580 | else |
| 570 | fd0 = -1; /* We are not going to read from tempfile. */ | 581 | fd0 = -1; /* We are not going to read from tempfile. */ |
| 571 | #else /* not MSDOS */ | 582 | #else /* not MSDOS */ |
| 583 | |||
| 584 | /* Do the unwind-protect now, even though the pid is not known, so | ||
| 585 | that no storage allocation is done in the critical section. | ||
| 586 | The actual PID will be filled in during the critical section. */ | ||
| 587 | synch_process_pid = 0; | ||
| 588 | synch_process_fd = fd0; | ||
| 589 | record_unwind_protect (call_process_cleanup, Fcurrent_buffer ()); | ||
| 590 | |||
| 591 | block_input (); | ||
| 592 | block_child_signal (); | ||
| 593 | |||
| 572 | #ifdef WINDOWSNT | 594 | #ifdef WINDOWSNT |
| 573 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); | 595 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
| 574 | #else /* not WINDOWSNT */ | 596 | #else /* not WINDOWSNT */ |
| 575 | 597 | ||
| 576 | block_input (); | ||
| 577 | |||
| 578 | /* vfork, and prevent local vars from being clobbered by the vfork. */ | 598 | /* vfork, and prevent local vars from being clobbered by the vfork. */ |
| 579 | { | 599 | { |
| 580 | Lisp_Object volatile buffer_volatile = buffer; | 600 | Lisp_Object volatile buffer_volatile = buffer; |
| @@ -593,6 +613,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 593 | char **volatile new_argv_volatile = new_argv; | 613 | char **volatile new_argv_volatile = new_argv; |
| 594 | 614 | ||
| 595 | pid = vfork (); | 615 | pid = vfork (); |
| 616 | child_errno = errno; | ||
| 596 | 617 | ||
| 597 | buffer = buffer_volatile; | 618 | buffer = buffer_volatile; |
| 598 | coding_systems = coding_systems_volatile; | 619 | coding_systems = coding_systems_volatile; |
| @@ -612,6 +633,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 612 | 633 | ||
| 613 | if (pid == 0) | 634 | if (pid == 0) |
| 614 | { | 635 | { |
| 636 | unblock_child_signal (); | ||
| 637 | |||
| 615 | if (fd0 >= 0) | 638 | if (fd0 >= 0) |
| 616 | emacs_close (fd0); | 639 | emacs_close (fd0); |
| 617 | 640 | ||
| @@ -623,11 +646,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 623 | child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); | 646 | child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
| 624 | } | 647 | } |
| 625 | 648 | ||
| 626 | vfork_errno = errno; | ||
| 627 | unblock_input (); | ||
| 628 | |||
| 629 | #endif /* not WINDOWSNT */ | 649 | #endif /* not WINDOWSNT */ |
| 630 | 650 | ||
| 651 | child_errno = errno; | ||
| 652 | |||
| 653 | if (0 < pid) | ||
| 654 | { | ||
| 655 | if (INTEGERP (buffer)) | ||
| 656 | record_deleted_pid (pid); | ||
| 657 | else | ||
| 658 | synch_process_pid = pid; | ||
| 659 | } | ||
| 660 | |||
| 661 | unblock_child_signal (); | ||
| 662 | unblock_input (); | ||
| 663 | |||
| 631 | /* The MSDOS case did this already. */ | 664 | /* The MSDOS case did this already. */ |
| 632 | if (fd_error >= 0) | 665 | if (fd_error >= 0) |
| 633 | emacs_close (fd_error); | 666 | emacs_close (fd_error); |
| @@ -644,9 +677,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 644 | 677 | ||
| 645 | if (pid < 0) | 678 | if (pid < 0) |
| 646 | { | 679 | { |
| 647 | if (fd0 >= 0) | 680 | errno = child_errno; |
| 648 | emacs_close (fd0); | ||
| 649 | errno = vfork_errno; | ||
| 650 | report_file_error ("Doing vfork", Qnil); | 681 | report_file_error ("Doing vfork", Qnil); |
| 651 | } | 682 | } |
| 652 | 683 | ||
| @@ -657,19 +688,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 657 | return Qnil; | 688 | return Qnil; |
| 658 | } | 689 | } |
| 659 | 690 | ||
| 660 | /* Enable sending signal if user quits below. */ | ||
| 661 | call_process_exited = 0; | ||
| 662 | |||
| 663 | #if defined (MSDOS) | 691 | #if defined (MSDOS) |
| 664 | /* MSDOS needs different cleanup information. */ | 692 | /* MSDOS needs different cleanup information. */ |
| 665 | cleanup_info_tail = build_string (tempfile ? tempfile : ""); | ||
| 666 | #else | ||
| 667 | cleanup_info_tail = INTEGER_TO_CONS (pid); | ||
| 668 | #endif /* not MSDOS */ | ||
| 669 | record_unwind_protect (call_process_cleanup, | 693 | record_unwind_protect (call_process_cleanup, |
| 670 | Fcons (Fcurrent_buffer (), | 694 | Fcons (Fcurrent_buffer (), |
| 671 | Fcons (INTEGER_TO_CONS (fd0), | 695 | build_string (tempfile ? tempfile : ""))); |
| 672 | cleanup_info_tail))); | 696 | #endif |
| 673 | 697 | ||
| 674 | if (BUFFERP (buffer)) | 698 | if (BUFFERP (buffer)) |
| 675 | Fset_buffer (buffer); | 699 | Fset_buffer (buffer); |
| @@ -856,38 +880,34 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 856 | 880 | ||
| 857 | #ifndef MSDOS | 881 | #ifndef MSDOS |
| 858 | /* Wait for it to terminate, unless it already has. */ | 882 | /* Wait for it to terminate, unless it already has. */ |
| 859 | if (output_to_buffer) | 883 | wait_for_termination (pid, &status, !output_to_buffer); |
| 860 | wait_for_termination (pid); | ||
| 861 | else | ||
| 862 | interruptible_wait_for_termination (pid); | ||
| 863 | #endif | 884 | #endif |
| 864 | 885 | ||
| 865 | immediate_quit = 0; | 886 | immediate_quit = 0; |
| 866 | 887 | ||
| 867 | /* Don't kill any children that the subprocess may have left behind | 888 | /* Don't kill any children that the subprocess may have left behind |
| 868 | when exiting. */ | 889 | when exiting. */ |
| 869 | call_process_exited = 1; | 890 | synch_process_pid = 0; |
| 870 | 891 | ||
| 871 | SAFE_FREE (); | 892 | SAFE_FREE (); |
| 872 | unbind_to (count, Qnil); | 893 | unbind_to (count, Qnil); |
| 873 | 894 | ||
| 874 | if (synch_process_termsig) | 895 | if (WIFSIGNALED (status)) |
| 875 | { | 896 | { |
| 876 | const char *signame; | 897 | const char *signame; |
| 877 | 898 | ||
| 878 | synchronize_system_messages_locale (); | 899 | synchronize_system_messages_locale (); |
| 879 | signame = strsignal (synch_process_termsig); | 900 | signame = strsignal (WTERMSIG (status)); |
| 880 | 901 | ||
| 881 | if (signame == 0) | 902 | if (signame == 0) |
| 882 | signame = "unknown"; | 903 | signame = "unknown"; |
| 883 | 904 | ||
| 884 | synch_process_death = signame; | 905 | return code_convert_string_norecord (build_string (signame), |
| 906 | Vlocale_coding_system, 0); | ||
| 885 | } | 907 | } |
| 886 | 908 | ||
| 887 | if (synch_process_death) | 909 | eassert (WIFEXITED (status)); |
| 888 | return code_convert_string_norecord (build_string (synch_process_death), | 910 | return make_number (WEXITSTATUS (status)); |
| 889 | Vlocale_coding_system, 0); | ||
| 890 | return make_number (synch_process_retcode); | ||
| 891 | } | 911 | } |
| 892 | 912 | ||
| 893 | static Lisp_Object | 913 | static Lisp_Object |
diff --git a/src/process.c b/src/process.c index c6139c9f929..27009882c99 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -777,10 +777,23 @@ get_process (register Lisp_Object name) | |||
| 777 | /* Fdelete_process promises to immediately forget about the process, but in | 777 | /* Fdelete_process promises to immediately forget about the process, but in |
| 778 | reality, Emacs needs to remember those processes until they have been | 778 | reality, Emacs needs to remember those processes until they have been |
| 779 | treated by the SIGCHLD handler and waitpid has been invoked on them; | 779 | treated by the SIGCHLD handler and waitpid has been invoked on them; |
| 780 | otherwise they might fill up the kernel's process table. */ | 780 | otherwise they might fill up the kernel's process table. |
| 781 | |||
| 782 | Some processes created by call-process are also put onto this list. */ | ||
| 781 | static Lisp_Object deleted_pid_list; | 783 | static Lisp_Object deleted_pid_list; |
| 782 | #endif | 784 | #endif |
| 783 | 785 | ||
| 786 | void | ||
| 787 | record_deleted_pid (pid_t pid) | ||
| 788 | { | ||
| 789 | #ifdef SIGCHLD | ||
| 790 | deleted_pid_list = Fcons (make_fixnum_or_float (pid), | ||
| 791 | /* GC treated elements set to nil. */ | ||
| 792 | Fdelq (Qnil, deleted_pid_list)); | ||
| 793 | |||
| 794 | #endif | ||
| 795 | } | ||
| 796 | |||
| 784 | DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0, | 797 | DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0, |
| 785 | doc: /* Delete PROCESS: kill it and forget about it immediately. | 798 | doc: /* Delete PROCESS: kill it and forget about it immediately. |
| 786 | PROCESS may be a process, a buffer, the name of a process or buffer, or | 799 | PROCESS may be a process, a buffer, the name of a process or buffer, or |
| @@ -807,9 +820,7 @@ nil, indicating the current buffer's process. */) | |||
| 807 | pid_t pid = p->pid; | 820 | pid_t pid = p->pid; |
| 808 | 821 | ||
| 809 | /* No problem storing the pid here, as it is still in Vprocess_alist. */ | 822 | /* No problem storing the pid here, as it is still in Vprocess_alist. */ |
| 810 | deleted_pid_list = Fcons (make_fixnum_or_float (pid), | 823 | record_deleted_pid (pid); |
| 811 | /* GC treated elements set to nil. */ | ||
| 812 | Fdelq (Qnil, deleted_pid_list)); | ||
| 813 | /* If the process has already signaled, remove it from the list. */ | 824 | /* If the process has already signaled, remove it from the list. */ |
| 814 | if (p->raw_status_new) | 825 | if (p->raw_status_new) |
| 815 | update_status (p); | 826 | update_status (p); |
| @@ -6147,35 +6158,37 @@ process has been transmitted to the serial port. */) | |||
| 6147 | return process; | 6158 | return process; |
| 6148 | } | 6159 | } |
| 6149 | 6160 | ||
| 6150 | /* If the status of the process DESIRED has changed, return true and | 6161 | #ifdef SIGCHLD |
| 6151 | set *STATUS to its exit status; otherwise, return false. | ||
| 6152 | If HAVE is nonnegative, assume that HAVE = waitpid (HAVE, STATUS, ...) | ||
| 6153 | has already been invoked, and do not invoke waitpid again. */ | ||
| 6154 | 6162 | ||
| 6155 | static bool | 6163 | /* The main Emacs thread records child processes in three places: |
| 6156 | process_status_retrieved (pid_t desired, pid_t have, int *status) | ||
| 6157 | { | ||
| 6158 | if (have < 0) | ||
| 6159 | { | ||
| 6160 | /* Invoke waitpid only with a known process ID; do not invoke | ||
| 6161 | waitpid with a nonpositive argument. Otherwise, Emacs might | ||
| 6162 | reap an unwanted process by mistake. For example, invoking | ||
| 6163 | waitpid (-1, ...) can mess up glib by reaping glib's subprocesses, | ||
| 6164 | so that another thread running glib won't find them. */ | ||
| 6165 | do | ||
| 6166 | have = waitpid (desired, status, WNOHANG | WUNTRACED); | ||
| 6167 | while (have < 0 && errno == EINTR); | ||
| 6168 | } | ||
| 6169 | 6164 | ||
| 6170 | return have == desired; | 6165 | - Vprocess_alist, for asynchronous subprocesses, which are child |
| 6171 | } | 6166 | processes visible to Lisp. |
| 6167 | |||
| 6168 | - deleted_pid_list, for child processes invisible to Lisp, | ||
| 6169 | typically because of delete-process. These are recorded so that | ||
| 6170 | the processes can be reaped when they exit, so that the operating | ||
| 6171 | system's process table is not cluttered by zombies. | ||
| 6172 | 6172 | ||
| 6173 | /* If PID is nonnegative, the child process PID with wait status W has | 6173 | - the local variable PID in Fcall_process, call_process_cleanup and |
| 6174 | changed its status; record this and return true. | 6174 | call_process_kill, for synchronous subprocesses. |
| 6175 | record_unwind_protect is used to make sure this process is not | ||
| 6176 | forgotten: if the user interrupts call-process and the child | ||
| 6177 | process refuses to exit immediately even with two C-g's, | ||
| 6178 | call_process_kill adds PID's contents to deleted_pid_list before | ||
| 6179 | returning. | ||
| 6175 | 6180 | ||
| 6176 | If PID is negative, ignore W, and look for known child processes | 6181 | The main Emacs thread invokes waitpid only on child processes that |
| 6177 | of Emacs whose status have changed. For each one found, record its new | 6182 | it creates and that have not been reaped. This avoid races on |
| 6178 | status. | 6183 | platforms such as GTK, where other threads create their own |
| 6184 | subprocesses which the main thread should not reap. For example, | ||
| 6185 | if the main thread attempted to reap an already-reaped child, it | ||
| 6186 | might inadvertently reap a GTK-created process that happened to | ||
| 6187 | have the same process ID. */ | ||
| 6188 | |||
| 6189 | /* Handle a SIGCHLD signal by looking for known child processes of | ||
| 6190 | Emacs whose status have changed. For each one found, record its | ||
| 6191 | new status. | ||
| 6179 | 6192 | ||
| 6180 | All we do is change the status; we do not run sentinels or print | 6193 | All we do is change the status; we do not run sentinels or print |
| 6181 | notifications. That is saved for the next time keyboard input is | 6194 | notifications. That is saved for the next time keyboard input is |
| @@ -6198,20 +6211,15 @@ process_status_retrieved (pid_t desired, pid_t have, int *status) | |||
| 6198 | ** Malloc WARNING: This should never call malloc either directly or | 6211 | ** Malloc WARNING: This should never call malloc either directly or |
| 6199 | indirectly; if it does, that is a bug */ | 6212 | indirectly; if it does, that is a bug */ |
| 6200 | 6213 | ||
| 6201 | void | 6214 | static void |
| 6202 | record_child_status_change (pid_t pid, int w) | 6215 | handle_child_signal (int sig) |
| 6203 | { | 6216 | { |
| 6204 | #ifdef SIGCHLD | ||
| 6205 | |||
| 6206 | /* Record at most one child only if we already know one child that | ||
| 6207 | has exited. */ | ||
| 6208 | bool record_at_most_one_child = 0 <= pid; | ||
| 6209 | |||
| 6210 | Lisp_Object tail; | 6217 | Lisp_Object tail; |
| 6211 | 6218 | ||
| 6212 | /* Find the process that signaled us, and record its status. */ | 6219 | /* Find the process that signaled us, and record its status. */ |
| 6213 | 6220 | ||
| 6214 | /* The process can have been deleted by Fdelete_process. */ | 6221 | /* The process can have been deleted by Fdelete_process, or have |
| 6222 | been started asynchronously by Fcall_process. */ | ||
| 6215 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) | 6223 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) |
| 6216 | { | 6224 | { |
| 6217 | bool all_pids_are_fixnums | 6225 | bool all_pids_are_fixnums |
| @@ -6225,12 +6233,8 @@ record_child_status_change (pid_t pid, int w) | |||
| 6225 | deleted_pid = XINT (xpid); | 6233 | deleted_pid = XINT (xpid); |
| 6226 | else | 6234 | else |
| 6227 | deleted_pid = XFLOAT_DATA (xpid); | 6235 | deleted_pid = XFLOAT_DATA (xpid); |
| 6228 | if (process_status_retrieved (deleted_pid, pid, &w)) | 6236 | if (child_status_changed (deleted_pid, 0, 0)) |
| 6229 | { | 6237 | XSETCAR (tail, Qnil); |
| 6230 | XSETCAR (tail, Qnil); | ||
| 6231 | if (record_at_most_one_child) | ||
| 6232 | return; | ||
| 6233 | } | ||
| 6234 | } | 6238 | } |
| 6235 | } | 6239 | } |
| 6236 | 6240 | ||
| @@ -6239,15 +6243,17 @@ record_child_status_change (pid_t pid, int w) | |||
| 6239 | { | 6243 | { |
| 6240 | Lisp_Object proc = XCDR (XCAR (tail)); | 6244 | Lisp_Object proc = XCDR (XCAR (tail)); |
| 6241 | struct Lisp_Process *p = XPROCESS (proc); | 6245 | struct Lisp_Process *p = XPROCESS (proc); |
| 6242 | if (p->alive && process_status_retrieved (p->pid, pid, &w)) | 6246 | int status; |
| 6247 | |||
| 6248 | if (p->alive && child_status_changed (p->pid, &status, WUNTRACED)) | ||
| 6243 | { | 6249 | { |
| 6244 | /* Change the status of the process that was found. */ | 6250 | /* Change the status of the process that was found. */ |
| 6245 | p->tick = ++process_tick; | 6251 | p->tick = ++process_tick; |
| 6246 | p->raw_status = w; | 6252 | p->raw_status = status; |
| 6247 | p->raw_status_new = 1; | 6253 | p->raw_status_new = 1; |
| 6248 | 6254 | ||
| 6249 | /* If process has terminated, stop waiting for its output. */ | 6255 | /* If process has terminated, stop waiting for its output. */ |
| 6250 | if (WIFSIGNALED (w) || WIFEXITED (w)) | 6256 | if (WIFSIGNALED (status) || WIFEXITED (status)) |
| 6251 | { | 6257 | { |
| 6252 | int clear_desc_flag = 0; | 6258 | int clear_desc_flag = 0; |
| 6253 | p->alive = 0; | 6259 | p->alive = 0; |
| @@ -6261,44 +6267,8 @@ record_child_status_change (pid_t pid, int w) | |||
| 6261 | FD_CLR (p->infd, &non_keyboard_wait_mask); | 6267 | FD_CLR (p->infd, &non_keyboard_wait_mask); |
| 6262 | } | 6268 | } |
| 6263 | } | 6269 | } |
| 6264 | |||
| 6265 | /* Tell wait_reading_process_output that it needs to wake up and | ||
| 6266 | look around. */ | ||
| 6267 | if (input_available_clear_time) | ||
| 6268 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 6269 | |||
| 6270 | if (record_at_most_one_child) | ||
| 6271 | return; | ||
| 6272 | } | 6270 | } |
| 6273 | } | 6271 | } |
| 6274 | |||
| 6275 | if (0 <= pid) | ||
| 6276 | { | ||
| 6277 | /* The caller successfully waited for a pid but no asynchronous | ||
| 6278 | process was found for it, so this is a synchronous process. */ | ||
| 6279 | |||
| 6280 | synch_process_alive = 0; | ||
| 6281 | |||
| 6282 | /* Report the status of the synchronous process. */ | ||
| 6283 | if (WIFEXITED (w)) | ||
| 6284 | synch_process_retcode = WEXITSTATUS (w); | ||
| 6285 | else if (WIFSIGNALED (w)) | ||
| 6286 | synch_process_termsig = WTERMSIG (w); | ||
| 6287 | |||
| 6288 | /* Tell wait_reading_process_output that it needs to wake up and | ||
| 6289 | look around. */ | ||
| 6290 | if (input_available_clear_time) | ||
| 6291 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 6292 | } | ||
| 6293 | #endif | ||
| 6294 | } | ||
| 6295 | |||
| 6296 | #ifdef SIGCHLD | ||
| 6297 | |||
| 6298 | static void | ||
| 6299 | handle_child_signal (int sig) | ||
| 6300 | { | ||
| 6301 | record_child_status_change (-1, 0); | ||
| 6302 | } | 6272 | } |
| 6303 | 6273 | ||
| 6304 | static void | 6274 | static void |
diff --git a/src/process.h b/src/process.h index 74d1a124060..4fa22747ca9 100644 --- a/src/process.h +++ b/src/process.h | |||
| @@ -185,23 +185,6 @@ pset_gnutls_cred_type (struct Lisp_Process *p, Lisp_Object val) | |||
| 185 | } | 185 | } |
| 186 | #endif | 186 | #endif |
| 187 | 187 | ||
| 188 | /* True if we are about to fork off a synchronous process or if we | ||
| 189 | are waiting for it. */ | ||
| 190 | extern bool synch_process_alive; | ||
| 191 | |||
| 192 | /* Communicate exit status of sync process to from sigchld_handler | ||
| 193 | to Fcall_process. */ | ||
| 194 | |||
| 195 | /* Nonzero => this is a string explaining death of synchronous subprocess. */ | ||
| 196 | extern const char *synch_process_death; | ||
| 197 | |||
| 198 | /* Nonzero => this is the signal number that terminated the subprocess. */ | ||
| 199 | extern int synch_process_termsig; | ||
| 200 | |||
| 201 | /* If synch_process_death is zero, | ||
| 202 | this is exit code of synchronous subprocess. */ | ||
| 203 | extern int synch_process_retcode; | ||
| 204 | |||
| 205 | /* Nonzero means don't run process sentinels. This is used | 188 | /* Nonzero means don't run process sentinels. This is used |
| 206 | when exiting. */ | 189 | when exiting. */ |
| 207 | extern int inhibit_sentinels; | 190 | extern int inhibit_sentinels; |
diff --git a/src/sysdep.c b/src/sysdep.c index 1a3834f0379..7068a4f0977 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -266,45 +266,71 @@ init_baud_rate (int fd) | |||
| 266 | 266 | ||
| 267 | #ifndef MSDOS | 267 | #ifndef MSDOS |
| 268 | 268 | ||
| 269 | static void | 269 | /* Wait for the subprocess with process id CHILD to terminate or change status. |
| 270 | wait_for_termination_1 (pid_t pid, int interruptible) | 270 | CHILD must be a child process that has not been reaped. |
| 271 | If STATUS is non-null, store the waitpid-style exit status into *STATUS | ||
| 272 | and tell wait_reading_process_output that it needs to look around. | ||
| 273 | Use waitpid-style OPTIONS when waiting. | ||
| 274 | If INTERRUPTIBLE, this function is interruptible by a signal. | ||
| 275 | |||
| 276 | Return CHILD if successful, 0 if no status is available; | ||
| 277 | the latter is possible only when options & NOHANG. */ | ||
| 278 | static pid_t | ||
| 279 | get_child_status (pid_t child, int *status, int options, bool interruptible) | ||
| 271 | { | 280 | { |
| 272 | while (1) | 281 | pid_t pid; |
| 282 | |||
| 283 | /* Invoke waitpid only with a known process ID; do not invoke | ||
| 284 | waitpid with a nonpositive argument. Otherwise, Emacs might | ||
| 285 | reap an unwanted process by mistake. For example, invoking | ||
| 286 | waitpid (-1, ...) can mess up glib by reaping glib's subprocesses, | ||
| 287 | so that another thread running glib won't find them. */ | ||
| 288 | eassert (0 < child); | ||
| 289 | |||
| 290 | while ((pid = waitpid (child, status, options)) < 0) | ||
| 273 | { | 291 | { |
| 274 | int status; | 292 | /* CHILD must be a child process that has not been reaped, and |
| 275 | int wait_result = waitpid (pid, &status, 0); | 293 | STATUS and OPTIONS must be valid. */ |
| 276 | if (wait_result < 0) | 294 | eassert (errno == EINTR); |
| 277 | { | ||
| 278 | if (errno != EINTR) | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | else | ||
| 282 | { | ||
| 283 | record_child_status_change (wait_result, status); | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | 295 | ||
| 287 | /* Note: the MS-Windows emulation of waitpid calls QUIT | 296 | /* Note: the MS-Windows emulation of waitpid calls QUIT |
| 288 | internally. */ | 297 | internally. */ |
| 289 | if (interruptible) | 298 | if (interruptible) |
| 290 | QUIT; | 299 | QUIT; |
| 291 | } | 300 | } |
| 292 | } | ||
| 293 | 301 | ||
| 294 | /* Wait for subprocess with process id `pid' to terminate and | 302 | /* If successful and status is requested, tell wait_reading_process_output |
| 295 | make sure it will get eliminated (not remain forever as a zombie) */ | 303 | that it needs to wake up and look around. */ |
| 304 | if (pid && status && input_available_clear_time) | ||
| 305 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 296 | 306 | ||
| 307 | return pid; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* Wait for the subprocess with process id CHILD to terminate. | ||
| 311 | CHILD must be a child process that has not been reaped. | ||
| 312 | If STATUS is non-null, store the waitpid-style exit status into *STATUS | ||
| 313 | and tell wait_reading_process_output that it needs to look around. | ||
| 314 | If INTERRUPTIBLE, this function is interruptible by a signal. */ | ||
| 297 | void | 315 | void |
| 298 | wait_for_termination (pid_t pid) | 316 | wait_for_termination (pid_t child, int *status, bool interruptible) |
| 299 | { | 317 | { |
| 300 | wait_for_termination_1 (pid, 0); | 318 | get_child_status (child, status, 0, interruptible); |
| 301 | } | 319 | } |
| 302 | 320 | ||
| 303 | /* Like the above, but allow keyboard interruption. */ | 321 | /* Report whether the subprocess with process id CHILD has changed status. |
| 304 | void | 322 | Termination counts as a change of status. |
| 305 | interruptible_wait_for_termination (pid_t pid) | 323 | CHILD must be a child process that has not been reaped. |
| 324 | If STATUS is non-null, store the waitpid-style exit status into *STATUS | ||
| 325 | and tell wait_reading_process_output that it needs to look around. | ||
| 326 | Use waitpid-style OPTIONS to check status, but do not wait. | ||
| 327 | |||
| 328 | Return CHILD if successful, 0 if no status is available because | ||
| 329 | the process's state has not changed. */ | ||
| 330 | pid_t | ||
| 331 | child_status_changed (pid_t child, int *status, int options) | ||
| 306 | { | 332 | { |
| 307 | wait_for_termination_1 (pid, 1); | 333 | return get_child_status (child, status, WNOHANG | options, 0); |
| 308 | } | 334 | } |
| 309 | 335 | ||
| 310 | /* | 336 | /* |
| @@ -454,6 +480,7 @@ sys_subshell (void) | |||
| 454 | char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ | 480 | char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ |
| 455 | #endif | 481 | #endif |
| 456 | pid_t pid; | 482 | pid_t pid; |
| 483 | int status; | ||
| 457 | struct save_signal saved_handlers[5]; | 484 | struct save_signal saved_handlers[5]; |
| 458 | Lisp_Object dir; | 485 | Lisp_Object dir; |
| 459 | unsigned char *volatile str_volatile = 0; | 486 | unsigned char *volatile str_volatile = 0; |
| @@ -491,7 +518,6 @@ sys_subshell (void) | |||
| 491 | #ifdef DOS_NT | 518 | #ifdef DOS_NT |
| 492 | pid = 0; | 519 | pid = 0; |
| 493 | save_signal_handlers (saved_handlers); | 520 | save_signal_handlers (saved_handlers); |
| 494 | synch_process_alive = 1; | ||
| 495 | #else | 521 | #else |
| 496 | pid = vfork (); | 522 | pid = vfork (); |
| 497 | if (pid == -1) | 523 | if (pid == -1) |
| @@ -560,14 +586,12 @@ sys_subshell (void) | |||
| 560 | /* Do this now if we did not do it before. */ | 586 | /* Do this now if we did not do it before. */ |
| 561 | #ifndef MSDOS | 587 | #ifndef MSDOS |
| 562 | save_signal_handlers (saved_handlers); | 588 | save_signal_handlers (saved_handlers); |
| 563 | synch_process_alive = 1; | ||
| 564 | #endif | 589 | #endif |
| 565 | 590 | ||
| 566 | #ifndef DOS_NT | 591 | #ifndef DOS_NT |
| 567 | wait_for_termination (pid); | 592 | wait_for_termination (pid, &status, 0); |
| 568 | #endif | 593 | #endif |
| 569 | restore_signal_handlers (saved_handlers); | 594 | restore_signal_handlers (saved_handlers); |
| 570 | synch_process_alive = 0; | ||
| 571 | } | 595 | } |
| 572 | 596 | ||
| 573 | static void | 597 | static void |
diff --git a/src/syswait.h b/src/syswait.h index aa4c4bcf527..360407d558e 100644 --- a/src/syswait.h +++ b/src/syswait.h | |||
| @@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 23 | #ifndef EMACS_SYSWAIT_H | 23 | #ifndef EMACS_SYSWAIT_H |
| 24 | #define EMACS_SYSWAIT_H | 24 | #define EMACS_SYSWAIT_H |
| 25 | 25 | ||
| 26 | #include <stdbool.h> | ||
| 26 | #include <sys/types.h> | 27 | #include <sys/types.h> |
| 27 | 28 | ||
| 28 | #ifdef HAVE_SYS_WAIT_H /* We have sys/wait.h with POSIXoid definitions. */ | 29 | #ifdef HAVE_SYS_WAIT_H /* We have sys/wait.h with POSIXoid definitions. */ |
| @@ -52,10 +53,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 52 | #endif | 53 | #endif |
| 53 | 54 | ||
| 54 | /* Defined in process.c. */ | 55 | /* Defined in process.c. */ |
| 55 | extern void record_child_status_change (pid_t, int); | 56 | extern void record_deleted_pid (pid_t); |
| 56 | 57 | ||
| 57 | /* Defined in sysdep.c. */ | 58 | /* Defined in sysdep.c. */ |
| 58 | extern void wait_for_termination (pid_t); | 59 | extern void wait_for_termination (pid_t, int *, bool); |
| 59 | extern void interruptible_wait_for_termination (pid_t); | 60 | extern pid_t child_status_changed (pid_t, int *, int); |
| 60 | 61 | ||
| 61 | #endif /* EMACS_SYSWAIT_H */ | 62 | #endif /* EMACS_SYSWAIT_H */ |
diff --git a/src/w32proc.c b/src/w32proc.c index 9b111b40e36..87af8682390 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -1274,33 +1274,7 @@ waitpid (pid_t pid, int *status, int options) | |||
| 1274 | #endif | 1274 | #endif |
| 1275 | 1275 | ||
| 1276 | if (status) | 1276 | if (status) |
| 1277 | { | 1277 | *status = retval; |
| 1278 | *status = retval; | ||
| 1279 | } | ||
| 1280 | else if (synch_process_alive) | ||
| 1281 | { | ||
| 1282 | synch_process_alive = 0; | ||
| 1283 | |||
| 1284 | /* Report the status of the synchronous process. */ | ||
| 1285 | if (WIFEXITED (retval)) | ||
| 1286 | synch_process_retcode = WEXITSTATUS (retval); | ||
| 1287 | else if (WIFSIGNALED (retval)) | ||
| 1288 | { | ||
| 1289 | int code = WTERMSIG (retval); | ||
| 1290 | const char *signame; | ||
| 1291 | |||
| 1292 | synchronize_system_messages_locale (); | ||
| 1293 | signame = strsignal (code); | ||
| 1294 | |||
| 1295 | if (signame == 0) | ||
| 1296 | signame = "unknown"; | ||
| 1297 | |||
| 1298 | synch_process_death = signame; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | reap_subprocess (cp); | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | reap_subprocess (cp); | 1278 | reap_subprocess (cp); |
| 1305 | 1279 | ||
| 1306 | return pid; | 1280 | return pid; |