Commit ee010797 authored by Paul Eggert's avatar Paul Eggert

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.
parent 02c66599
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> 2013-07-20 Glenn Morris <rgm@gnu.org>
* image.c (Fimage_flush): Fix doc typo. * image.c (Fimage_flush): Fix doc typo.
......
...@@ -1193,6 +1193,7 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, ...@@ -1193,6 +1193,7 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
{ {
char **env; char **env;
char *pwd_var; char *pwd_var;
int exec_errno;
#ifdef WINDOWSNT #ifdef WINDOWSNT
int cpid; int cpid;
HANDLE handles[3]; HANDLE handles[3];
...@@ -1368,13 +1369,16 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, ...@@ -1368,13 +1369,16 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
tcsetpgrp (0, pid); tcsetpgrp (0, pid);
execve (new_argv[0], new_argv, env); execve (new_argv[0], new_argv, env);
exec_errno = errno;
/* Don't output the program name here, as it can be arbitrarily long, /* Avoid deadlock if the child's perror writes to a full pipe; the
and a long write from a vforked child to its parent can cause a pipe's reader is the parent, but with vfork the parent can't
deadlock. */ run until the child exits. Truncate the diagnostic instead. */
emacs_perror ("child process"); 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 */ #else /* MSDOS */
pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env); pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env);
......
...@@ -1599,12 +1599,6 @@ start_process_unwind (Lisp_Object proc) ...@@ -1599,12 +1599,6 @@ start_process_unwind (Lisp_Object proc)
remove_process (proc); remove_process (proc);
} }
static void
create_process_1 (struct atimer *timer)
{
/* Nothing to do. */
}
static void static void
create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) 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) ...@@ -1841,14 +1835,13 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
unblock_child_signal (); unblock_child_signal ();
unblock_input (); unblock_input ();
if (forkin >= 0)
emacs_close (forkin);
if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
if (pid < 0) if (pid < 0)
{ report_file_errno ("Doing vfork", Qnil, vfork_errno);
if (forkin >= 0)
emacs_close (forkin);
if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
report_file_errno ("Doing vfork", Qnil, vfork_errno);
}
else else
{ {
/* vfork succeeded. */ /* vfork succeeded. */
...@@ -1857,26 +1850,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) ...@@ -1857,26 +1850,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
register_child (pid, inchannel); register_child (pid, inchannel);
#endif /* WINDOWSNT */ #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); pset_tty_name (XPROCESS (process), lisp_pty_name);
#ifndef WINDOWSNT #ifndef WINDOWSNT
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment