Avoid vfork-related deadlock more cleanly.

* callproc.c (child_setup): When the child's exec fails, output
the program name, as that's more useful.  Use O_NONBLOCK to avoid
deadlock.
* process.c (create_process_1): Remove; no longer needed.
(create_process): Remove timer hack; no longer needed, now that
the child avoids deadlock.
This commit is contained in:
Paul Eggert 2013-07-20 23:53:47 -07:00
parent 02c66599e3
commit ee01079735
3 changed files with 25 additions and 38 deletions

View file

@ -1,3 +1,13 @@
2013-07-21 Paul Eggert <eggert@cs.ucla.edu>
Avoid vfork-related deadlock more cleanly.
* callproc.c (child_setup): When the child's exec fails, output
the program name, as that's more useful. Use O_NONBLOCK to avoid
deadlock.
* process.c (create_process_1): Remove; no longer needed.
(create_process): Remove timer hack; no longer needed, now that
the child avoids deadlock.
2013-07-20 Glenn Morris <rgm@gnu.org>
* image.c (Fimage_flush): Fix doc typo.

View file

@ -1193,6 +1193,7 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
{
char **env;
char *pwd_var;
int exec_errno;
#ifdef WINDOWSNT
int cpid;
HANDLE handles[3];
@ -1368,13 +1369,16 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
tcsetpgrp (0, pid);
execve (new_argv[0], new_argv, env);
exec_errno = errno;
/* Don't output the program name here, as it can be arbitrarily long,
and a long write from a vforked child to its parent can cause a
deadlock. */
emacs_perror ("child process");
/* Avoid deadlock if the child's perror writes to a full pipe; the
pipe's reader is the parent, but with vfork the parent can't
run until the child exits. Truncate the diagnostic instead. */
fcntl (STDERR_FILENO, F_SETFL, O_NONBLOCK);
_exit (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
errno = exec_errno;
emacs_perror (new_argv[0]);
_exit (exec_errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
#else /* MSDOS */
pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env);

View file

@ -1599,12 +1599,6 @@ start_process_unwind (Lisp_Object proc)
remove_process (proc);
}
static void
create_process_1 (struct atimer *timer)
{
/* Nothing to do. */
}
static void
create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
@ -1841,14 +1835,13 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
unblock_child_signal ();
unblock_input ();
if (forkin >= 0)
emacs_close (forkin);
if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
if (pid < 0)
{
if (forkin >= 0)
emacs_close (forkin);
if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
report_file_errno ("Doing vfork", Qnil, vfork_errno);
}
report_file_errno ("Doing vfork", Qnil, vfork_errno);
else
{
/* vfork succeeded. */
@ -1857,26 +1850,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
register_child (pid, inchannel);
#endif /* WINDOWSNT */
/* If the subfork execv fails, and it exits,
this close hangs. I don't know why.
So have an interrupt jar it loose. */
{
struct atimer *timer;
EMACS_TIME offset = make_emacs_time (1, 0);
stop_polling ();
timer = start_atimer (ATIMER_RELATIVE, offset, create_process_1, 0);
if (forkin >= 0)
emacs_close (forkin);
cancel_atimer (timer);
start_polling ();
}
if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
pset_tty_name (XPROCESS (process), lisp_pty_name);
#ifndef WINDOWSNT