+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.
{
char **env;
char *pwd_var;
+ int exec_errno;
#ifdef WINDOWSNT
int cpid;
HANDLE handles[3];
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);
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)
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. */
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