diff options
| author | Paul Eggert | 2017-05-19 00:11:48 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-05-19 00:13:27 -0700 |
| commit | 7c951fd51832badb09055a8e177f8ec358cbbdcf (patch) | |
| tree | 1b77d643aa5d2719ee7e070a82f499292d60adb3 /src | |
| parent | df9bec3b39b12b33db8f5a97d86797f6636e5e7d (diff) | |
| download | emacs-7c951fd51832badb09055a8e177f8ec358cbbdcf.tar.gz emacs-7c951fd51832badb09055a8e177f8ec358cbbdcf.zip | |
Attempt to work around macOS vfork bug
Problem reported by YAMAMOTO Mitsuharu in:
http://lists.gnu.org/archive/html/emacs-devel/2017-05/msg00342.html
This is related to the fix for Bug#26397.
* src/callproc.c (call_process_cleanup, call_process) [!MSDOS]:
Report internal error if wait_for_termination fails.
* src/sysdep.c (get_child_status): Return -1 if waitpid is
buggy, instead of aborting.
(wait_for_termination): Return bool success value.
All callers changed.
Diffstat (limited to 'src')
| -rw-r--r-- | src/callproc.c | 13 | ||||
| -rw-r--r-- | src/sysdep.c | 25 | ||||
| -rw-r--r-- | src/syswait.h | 2 |
3 files changed, 24 insertions, 16 deletions
diff --git a/src/callproc.c b/src/callproc.c index e967e45d03f..7c85eed835f 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -202,10 +202,11 @@ call_process_cleanup (Lisp_Object buffer) | |||
| 202 | message1 ("Waiting for process to die...(type C-g again to kill it instantly)"); | 202 | message1 ("Waiting for process to die...(type C-g again to kill it instantly)"); |
| 203 | 203 | ||
| 204 | /* This will quit on C-g. */ | 204 | /* This will quit on C-g. */ |
| 205 | wait_for_termination (synch_process_pid, 0, 1); | 205 | bool wait_ok = wait_for_termination (synch_process_pid, NULL, true); |
| 206 | |||
| 207 | synch_process_pid = 0; | 206 | synch_process_pid = 0; |
| 208 | message1 ("Waiting for process to die...done"); | 207 | message1 (wait_ok |
| 208 | ? "Waiting for process to die...done" | ||
| 209 | : "Waiting for process to die...internal error"); | ||
| 209 | } | 210 | } |
| 210 | #endif /* !MSDOS */ | 211 | #endif /* !MSDOS */ |
| 211 | } | 212 | } |
| @@ -866,9 +867,10 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, | |||
| 866 | make_number (total_read)); | 867 | make_number (total_read)); |
| 867 | } | 868 | } |
| 868 | 869 | ||
| 870 | bool wait_ok = true; | ||
| 869 | #ifndef MSDOS | 871 | #ifndef MSDOS |
| 870 | /* Wait for it to terminate, unless it already has. */ | 872 | /* Wait for it to terminate, unless it already has. */ |
| 871 | wait_for_termination (pid, &status, fd0 < 0); | 873 | wait_ok = wait_for_termination (pid, &status, fd0 < 0); |
| 872 | #endif | 874 | #endif |
| 873 | 875 | ||
| 874 | /* Don't kill any children that the subprocess may have left behind | 876 | /* Don't kill any children that the subprocess may have left behind |
| @@ -878,6 +880,9 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, | |||
| 878 | SAFE_FREE (); | 880 | SAFE_FREE (); |
| 879 | unbind_to (count, Qnil); | 881 | unbind_to (count, Qnil); |
| 880 | 882 | ||
| 883 | if (!wait_ok) | ||
| 884 | return build_unibyte_string ("internal error"); | ||
| 885 | |||
| 881 | if (WIFSIGNALED (status)) | 886 | if (WIFSIGNALED (status)) |
| 882 | { | 887 | { |
| 883 | const char *signame; | 888 | const char *signame; |
diff --git a/src/sysdep.c b/src/sysdep.c index ac6eed0e581..70f4a9dd7ea 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -368,8 +368,8 @@ init_baud_rate (int fd) | |||
| 368 | Use waitpid-style OPTIONS when waiting. | 368 | Use waitpid-style OPTIONS when waiting. |
| 369 | If INTERRUPTIBLE, this function is interruptible by a signal. | 369 | If INTERRUPTIBLE, this function is interruptible by a signal. |
| 370 | 370 | ||
| 371 | Return CHILD if successful, 0 if no status is available; | 371 | Return CHILD if successful, 0 if no status is available, and a |
| 372 | the latter is possible only when options & NOHANG. */ | 372 | negative value (setting errno) if waitpid is buggy. */ |
| 373 | static pid_t | 373 | static pid_t |
| 374 | get_child_status (pid_t child, int *status, int options, bool interruptible) | 374 | get_child_status (pid_t child, int *status, int options, bool interruptible) |
| 375 | { | 375 | { |
| @@ -392,13 +392,14 @@ get_child_status (pid_t child, int *status, int options, bool interruptible) | |||
| 392 | pid = waitpid (child, status, options); | 392 | pid = waitpid (child, status, options); |
| 393 | if (0 <= pid) | 393 | if (0 <= pid) |
| 394 | break; | 394 | break; |
| 395 | |||
| 396 | /* Check that CHILD is a child process that has not been reaped, | ||
| 397 | and that STATUS and OPTIONS are valid. Otherwise abort, | ||
| 398 | as continuing after this internal error could cause Emacs to | ||
| 399 | become confused and kill innocent-victim processes. */ | ||
| 400 | if (errno != EINTR) | 395 | if (errno != EINTR) |
| 401 | emacs_abort (); | 396 | { |
| 397 | /* Most likely, waitpid is buggy and the operating system | ||
| 398 | lost track of the child somehow. Return -1 and let the | ||
| 399 | caller try to figure things out. Possibly the bug could | ||
| 400 | cause Emacs to kill the wrong process. Oh well. */ | ||
| 401 | return pid; | ||
| 402 | } | ||
| 402 | } | 403 | } |
| 403 | 404 | ||
| 404 | /* If successful and status is requested, tell wait_reading_process_output | 405 | /* If successful and status is requested, tell wait_reading_process_output |
| @@ -413,11 +414,13 @@ get_child_status (pid_t child, int *status, int options, bool interruptible) | |||
| 413 | CHILD must be a child process that has not been reaped. | 414 | CHILD must be a child process that has not been reaped. |
| 414 | If STATUS is non-null, store the waitpid-style exit status into *STATUS | 415 | If STATUS is non-null, store the waitpid-style exit status into *STATUS |
| 415 | and tell wait_reading_process_output that it needs to look around. | 416 | and tell wait_reading_process_output that it needs to look around. |
| 416 | If INTERRUPTIBLE, this function is interruptible by a signal. */ | 417 | If INTERRUPTIBLE, this function is interruptible by a signal. |
| 417 | void | 418 | Return true if successful, false (setting errno) if CHILD cannot be |
| 419 | waited for because waitpid is buggy. */ | ||
| 420 | bool | ||
| 418 | wait_for_termination (pid_t child, int *status, bool interruptible) | 421 | wait_for_termination (pid_t child, int *status, bool interruptible) |
| 419 | { | 422 | { |
| 420 | get_child_status (child, status, 0, interruptible); | 423 | return 0 <= get_child_status (child, status, 0, interruptible); |
| 421 | } | 424 | } |
| 422 | 425 | ||
| 423 | /* Report whether the subprocess with process id CHILD has changed status. | 426 | /* Report whether the subprocess with process id CHILD has changed status. |
diff --git a/src/syswait.h b/src/syswait.h index 846a975b241..055562ae48b 100644 --- a/src/syswait.h +++ b/src/syswait.h | |||
| @@ -56,7 +56,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 56 | #endif | 56 | #endif |
| 57 | 57 | ||
| 58 | /* Defined in sysdep.c. */ | 58 | /* Defined in sysdep.c. */ |
| 59 | extern void wait_for_termination (pid_t, int *, bool); | 59 | extern bool wait_for_termination (pid_t, int *, bool); |
| 60 | extern pid_t child_status_changed (pid_t, int *, int); | 60 | extern pid_t child_status_changed (pid_t, int *, int); |
| 61 | 61 | ||
| 62 | #endif /* EMACS_SYSWAIT_H */ | 62 | #endif /* EMACS_SYSWAIT_H */ |