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.
This commit is contained in:
Paul Eggert 2017-05-19 00:11:48 -07:00
parent df9bec3b39
commit 7c951fd518
3 changed files with 24 additions and 16 deletions

View file

@ -202,10 +202,11 @@ call_process_cleanup (Lisp_Object buffer)
message1 ("Waiting for process to die...(type C-g again to kill it instantly)");
/* This will quit on C-g. */
wait_for_termination (synch_process_pid, 0, 1);
bool wait_ok = wait_for_termination (synch_process_pid, NULL, true);
synch_process_pid = 0;
message1 ("Waiting for process to die...done");
message1 (wait_ok
? "Waiting for process to die...done"
: "Waiting for process to die...internal error");
}
#endif /* !MSDOS */
}
@ -866,9 +867,10 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
make_number (total_read));
}
bool wait_ok = true;
#ifndef MSDOS
/* Wait for it to terminate, unless it already has. */
wait_for_termination (pid, &status, fd0 < 0);
wait_ok = wait_for_termination (pid, &status, fd0 < 0);
#endif
/* 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,
SAFE_FREE ();
unbind_to (count, Qnil);
if (!wait_ok)
return build_unibyte_string ("internal error");
if (WIFSIGNALED (status))
{
const char *signame;

View file

@ -368,8 +368,8 @@ init_baud_rate (int fd)
Use waitpid-style OPTIONS when waiting.
If INTERRUPTIBLE, this function is interruptible by a signal.
Return CHILD if successful, 0 if no status is available;
the latter is possible only when options & NOHANG. */
Return CHILD if successful, 0 if no status is available, and a
negative value (setting errno) if waitpid is buggy. */
static pid_t
get_child_status (pid_t child, int *status, int options, bool interruptible)
{
@ -392,13 +392,14 @@ get_child_status (pid_t child, int *status, int options, bool interruptible)
pid = waitpid (child, status, options);
if (0 <= pid)
break;
/* Check that CHILD is a child process that has not been reaped,
and that STATUS and OPTIONS are valid. Otherwise abort,
as continuing after this internal error could cause Emacs to
become confused and kill innocent-victim processes. */
if (errno != EINTR)
emacs_abort ();
{
/* Most likely, waitpid is buggy and the operating system
lost track of the child somehow. Return -1 and let the
caller try to figure things out. Possibly the bug could
cause Emacs to kill the wrong process. Oh well. */
return pid;
}
}
/* 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)
CHILD must be a child process that has not been reaped.
If STATUS is non-null, store the waitpid-style exit status into *STATUS
and tell wait_reading_process_output that it needs to look around.
If INTERRUPTIBLE, this function is interruptible by a signal. */
void
If INTERRUPTIBLE, this function is interruptible by a signal.
Return true if successful, false (setting errno) if CHILD cannot be
waited for because waitpid is buggy. */
bool
wait_for_termination (pid_t child, int *status, bool interruptible)
{
get_child_status (child, status, 0, interruptible);
return 0 <= get_child_status (child, status, 0, interruptible);
}
/* Report whether the subprocess with process id CHILD has changed status.

View file

@ -56,7 +56,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#endif
/* Defined in sysdep.c. */
extern void wait_for_termination (pid_t, int *, bool);
extern bool wait_for_termination (pid_t, int *, bool);
extern pid_t child_status_changed (pid_t, int *, int);
#endif /* EMACS_SYSWAIT_H */