Merge from emacs-24; up to 2012-12-05T00:13:56Z!yamaoka@jpl.org
[bpt/emacs.git] / src / process.c
index 785282f..7ab651a 100644 (file)
@@ -91,6 +91,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <pty.h>
 #endif
 
+#include <c-ctype.h>
+#include <sig2str.h>
+
 #endif /* subprocesses */
 
 #include "systime.h"
@@ -130,18 +133,6 @@ extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
                       EMACS_TIME *, void *);
 #endif
 
-/* This is for DOS_NT ports.  FIXME: Remove this old portability cruft
-   by having DOS_NT ports implement waitpid instead of wait.  Nowadays
-   POSIXish hosts all define waitpid, WNOHANG, and WUNTRACED, as these
-   have been standard since POSIX.1-1988.  */
-#ifndef WNOHANG
-# undef waitpid
-# define waitpid(pid, status, options) wait (status)
-#endif
-#ifndef WUNTRACED
-# define WUNTRACED 0
-#endif
-
 /* Work around GCC 4.7.0 bug with strict overflow checking; see
    <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>.
    These lines can be removed once the GCC bug is fixed.  */
@@ -208,11 +199,9 @@ static EMACS_INT update_tick;
 #ifndef NON_BLOCKING_CONNECT
 #ifdef HAVE_SELECT
 #if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
-#if O_NONBLOCK || O_NDELAY
 #if defined (EWOULDBLOCK) || defined (EINPROGRESS)
 #define NON_BLOCKING_CONNECT
 #endif /* EWOULDBLOCK || EINPROGRESS */
-#endif /* O_NONBLOCK || O_NDELAY */
 #endif /* HAVE_GETPEERNAME || GNU_LINUX */
 #endif /* HAVE_SELECT */
 #endif /* NON_BLOCKING_CONNECT */
@@ -651,13 +640,7 @@ allocate_pty (void)
 #ifdef PTY_OPEN
        PTY_OPEN;
 #else /* no PTY_OPEN */
-       {
-#  if O_NONBLOCK
-         fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
-#  else
-         fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0);
-#  endif
-       }
+       fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
 #endif /* no PTY_OPEN */
 
        if (fd >= 0)
@@ -793,13 +776,22 @@ get_process (register Lisp_Object name)
 }
 
 
-#ifdef SIGCHLD
 /* Fdelete_process promises to immediately forget about the process, but in
    reality, Emacs needs to remember those processes until they have been
    treated by the SIGCHLD handler and waitpid has been invoked on them;
-   otherwise they might fill up the kernel's process table.  */
+   otherwise they might fill up the kernel's process table.
+
+   Some processes created by call-process are also put onto this list.  */
 static Lisp_Object deleted_pid_list;
-#endif
+
+void
+record_deleted_pid (pid_t pid)
+{
+  deleted_pid_list = Fcons (make_fixnum_or_float (pid),
+                           /* GC treated elements set to nil.  */
+                           Fdelq (Qnil, deleted_pid_list));
+
+}
 
 DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
        doc: /* Delete PROCESS: kill it and forget about it immediately.
@@ -820,32 +812,22 @@ nil, indicating the current buffer's process.  */)
       status_notify (p);
       redisplay_preserve_echo_area (13);
     }
-  else if (p->infd >= 0)
+  else
     {
-#ifdef SIGCHLD
-      Lisp_Object symbol;
-      pid_t pid = p->pid;
-
-      /* No problem storing the pid here, as it is still in Vprocess_alist.  */
-      deleted_pid_list = Fcons (make_fixnum_or_float (pid),
-                               /* GC treated elements set to nil.  */
-                               Fdelq (Qnil, deleted_pid_list));
-      /* If the process has already signaled, remove it from the list.  */
-      if (p->raw_status_new)
-       update_status (p);
-      symbol = p->status;
-      if (CONSP (p->status))
-       symbol = XCAR (p->status);
-      if (EQ (symbol, Qsignal) || EQ (symbol, Qexit))
-       deleted_pid_list
-         = Fdelete (make_fixnum_or_float (pid), deleted_pid_list);
-      else
-#endif
+      if (p->alive)
+       record_kill_process (p);
+
+      if (p->infd >= 0)
        {
-         Fkill_process (process, Qnil);
-         /* Do this now, since remove_process will make the
-            SIGCHLD handler do nothing.  */
-         pset_status (p, Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil)));
+         /* Update P's status, since record_kill_process will make the
+            SIGCHLD handler update deleted_pid_list, not *P.  */
+         Lisp_Object symbol;
+         if (p->raw_status_new)
+           update_status (p);
+         symbol = CONSP (p->status) ? XCAR (p->status) : p->status;
+         if (! (EQ (symbol, Qsignal) || EQ (symbol, Qexit)))
+           pset_status (p, list2 (Qsignal, make_number (SIGKILL)));
+
          p->tick = ++process_tick;
          status_notify (p);
          redisplay_preserve_echo_area (13);
@@ -1595,20 +1577,15 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
   int inchannel, outchannel;
   pid_t pid;
   int sv[2];
-#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+#ifndef WINDOWSNT
   int wait_child_setup[2];
 #endif
-#ifdef SIGCHLD
   sigset_t blocked;
-#endif
   /* Use volatile to protect variables from being clobbered by vfork.  */
   volatile int forkin, forkout;
   volatile int pty_flag = 0;
   volatile Lisp_Object lisp_pty_name = Qnil;
   volatile Lisp_Object encoded_current_dir;
-#if HAVE_WORKING_VFORK
-  char **volatile save_environ;
-#endif
 
   inchannel = outchannel = -1;
 
@@ -1621,13 +1598,9 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 #if ! defined (USG) || defined (USG_SUBTTY_WORKS)
       /* On most USG systems it does not work to open the pty's tty here,
         then close it and reopen it in the child.  */
-#if O_NOCTTY
       /* Don't let this terminal become our controlling terminal
         (in case we don't have one).  */
       forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
-#else
-      forkout = forkin = emacs_open (pty_name, O_RDWR, 0);
-#endif
       if (forkin < 0)
        report_file_error ("Opening pty", Qnil);
 #else
@@ -1656,7 +1629,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       forkin = sv[0];
     }
 
-#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+#ifndef WINDOWSNT
     {
       int tem;
 
@@ -1675,15 +1648,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
     }
 #endif
 
-#if O_NONBLOCK
   fcntl (inchannel, F_SETFL, O_NONBLOCK);
   fcntl (outchannel, F_SETFL, O_NONBLOCK);
-#else
-#if O_NDELAY
-  fcntl (inchannel, F_SETFL, O_NDELAY);
-  fcntl (outchannel, F_SETFL, O_NDELAY);
-#endif
-#endif
 
   /* Record this as an active process, with its channels.
      As a result, child_setup will close Emacs's side of the pipes.  */
@@ -1711,19 +1677,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 
   block_input ();
 
-#ifdef SIGCHLD
   /* Block SIGCHLD until we have a chance to store the new fork's
      pid in its process structure.  */
   sigemptyset (&blocked);
   sigaddset (&blocked, SIGCHLD);
   pthread_sigmask (SIG_BLOCK, &blocked, 0);
-#endif
-
-#if HAVE_WORKING_VFORK
-  /* child_setup must clobber environ on systems with true vfork.
-     Protect it from permanent change.  */
-  save_environ = environ;
-#endif
 
 #ifndef WINDOWSNT
   pid = vfork ();
@@ -1831,10 +1789,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       /* Emacs ignores SIGPIPE, but the child should not.  */
       signal (SIGPIPE, SIG_DFL);
 
-#ifdef SIGCHLD
        /* Stop blocking signals in the child.  */
       pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
-#endif
 
       if (pty_flag)
        child_setup_tty (xforkout);
@@ -1842,9 +1798,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       pid = child_setup (xforkin, xforkout, xforkout,
                         new_argv, 1, encoded_current_dir);
 #else  /* not WINDOWSNT */
-#ifdef FD_CLOEXEC
       emacs_close (wait_child_setup[0]);
-#endif
       child_setup (xforkin, xforkout, xforkout,
                   new_argv, 1, encoded_current_dir);
 #endif /* not WINDOWSNT */
@@ -1852,18 +1806,12 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 
   /* Back in the parent process.  */
 
-#if HAVE_WORKING_VFORK
-  environ = save_environ;
-#endif
-
   XPROCESS (process)->pid = pid;
   if (0 <= pid)
     XPROCESS (process)->alive = 1;
 
   /* Stop blocking signals in the parent.  */
-#ifdef SIGCHLD
   pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
-#endif
   unblock_input ();
 
   if (pid < 0)
@@ -1903,11 +1851,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 
       pset_tty_name (XPROCESS (process), lisp_pty_name);
 
-#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+#ifndef WINDOWSNT
       /* Wait for child_setup to complete in case that vfork is
         actually defined as fork.  The descriptor wait_child_setup[1]
         of a pipe is closed at the child side either by close-on-exec
-        on successful execvp or the _exit call in child_setup.  */
+        on successful execve or the _exit call in child_setup.  */
       {
        char dummy;
 
@@ -1940,13 +1888,9 @@ create_pty (Lisp_Object process)
 #if ! defined (USG) || defined (USG_SUBTTY_WORKS)
       /* On most USG systems it does not work to open the pty's tty here,
         then close it and reopen it in the child.  */
-#if O_NOCTTY
       /* Don't let this terminal become our controlling terminal
         (in case we don't have one).  */
       int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
-#else
-      int forkout = emacs_open (pty_name, O_RDWR, 0);
-#endif
       if (forkout < 0)
        report_file_error ("Opening pty", Qnil);
 #if defined (DONT_REOPEN_PTY)
@@ -1960,15 +1904,8 @@ create_pty (Lisp_Object process)
     }
 #endif /* HAVE_PTYS */
 
-#if O_NONBLOCK
   fcntl (inchannel, F_SETFL, O_NONBLOCK);
   fcntl (outchannel, F_SETFL, O_NONBLOCK);
-#else
-#if O_NDELAY
-  fcntl (inchannel, F_SETFL, O_NDELAY);
-  fcntl (outchannel, F_SETFL, O_NDELAY);
-#endif
-#endif
 
   /* Record this as an active process, with its channels.
      As a result, child_setup will close Emacs's side of the pipes.  */
@@ -2924,13 +2861,9 @@ usage: (make-network-process &rest ARGS)  */)
     {
       /* Don't support network sockets when non-blocking mode is
         not available, since a blocked Emacs is not useful.  */
-#if !O_NONBLOCK && !O_NDELAY
-      error ("Network servers not supported");
-#else
       is_server = 1;
       if (TYPE_RANGED_INTEGERP (int, tem))
        backlog = XINT (tem);
-#endif
     }
 
   /* Make QCaddress an alias for :local (server) or :remote (client).  */
@@ -3190,11 +3123,7 @@ usage: (make-network-process &rest ARGS)  */)
 #ifdef NON_BLOCKING_CONNECT
       if (is_non_blocking_client)
        {
-#if O_NONBLOCK
          ret = fcntl (s, F_SETFL, O_NONBLOCK);
-#else
-         ret = fcntl (s, F_SETFL, O_NDELAY);
-#endif
          if (ret < 0)
            {
              xerrno = errno;
@@ -3407,13 +3336,7 @@ usage: (make-network-process &rest ARGS)  */)
 
   chan_process[inch] = proc;
 
-#if O_NONBLOCK
   fcntl (inch, F_SETFL, O_NONBLOCK);
-#else
-#if O_NDELAY
-  fcntl (inch, F_SETFL, O_NDELAY);
-#endif
-#endif
 
   p = XPROCESS (proc);
 
@@ -4142,13 +4065,7 @@ server_accept_connection (Lisp_Object server, int channel)
 
   chan_process[s] = proc;
 
-#if O_NONBLOCK
   fcntl (s, F_SETFL, O_NONBLOCK);
-#else
-#if O_NDELAY
-  fcntl (s, F_SETFL, O_NDELAY);
-#endif
-#endif
 
   p = XPROCESS (proc);
 
@@ -4496,14 +4413,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                  total_nread += nread;
                  got_some_input = 1;
                }
-#ifdef EIO
-             else if (nread == -1 && EIO == errno)
-               break;
-#endif
-#ifdef EAGAIN
-             else if (nread == -1 && EAGAIN == errno)
+             else if (nread == -1 && (errno == EIO || errno == EAGAIN))
                break;
-#endif
 #ifdef EWOULDBLOCK
              else if (nread == -1 && EWOULDBLOCK == errno)
                break;
@@ -4692,7 +4603,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                 yielding EBADF here or at select() call above.
                 So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF
                 in m/ibmrt-aix.h), and here we just ignore the select error.
-                Cleanup occurs c/o status_notify after SIGCLD. */
+                Cleanup occurs c/o status_notify after SIGCHLD. */
              no_avail = 1; /* Cannot depend on values returned */
 #else
              emacs_abort ();
@@ -4844,23 +4755,17 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              else if (nread == -1 && errno == EWOULDBLOCK)
                ;
 #endif
-             /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK,
-                and Emacs uses O_NONBLOCK, so what we get is EAGAIN.  */
-#if O_NONBLOCK
-             else if (nread == -1 && errno == EAGAIN)
-               ;
-#else
-#if O_NDELAY
              else if (nread == -1 && errno == EAGAIN)
                ;
+#ifdef WINDOWSNT
+             /* FIXME: Is this special case still needed?  */
              /* Note that we cannot distinguish between no input
                 available now and a closed pipe.
                 With luck, a closed pipe will be accompanied by
                 subprocess termination and SIGCHLD.  */
              else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc))
                ;
-#endif /* O_NDELAY */
-#endif /* O_NONBLOCK */
+#endif
 #ifdef HAVE_PTYS
              /* On some OSs with ptys, when the process on one end of
                 a pty exits, the other end gets an error reading with
@@ -4868,11 +4773,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                 Therefore, if we get an error reading and errno =
                 EIO, just continue, because the child process has
                 exited and should clean itself up soon (e.g. when we
-                get a SIGCHLD).
-
-                However, it has been known to happen that the SIGCHLD
-                got lost.  So raise the signal again just in case.
-                It can't hurt.  */
+                get a SIGCHLD).  */
              else if (nread == -1 && errno == EIO)
                {
                  struct Lisp_Process *p = XPROCESS (proc);
@@ -4890,16 +4791,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                      p->tick = ++process_tick;
                      pset_status (p, Qfailed);
                    }
-                  else
-                   handle_child_signal (SIGCHLD);
                }
 #endif /* HAVE_PTYS */
              /* If we can detect process termination, don't consider the
                 process gone just because its pipe is closed.  */
-#ifdef SIGCHLD
              else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc))
                ;
-#endif
              else
                {
                  /* Preserve status of processes already terminated.  */
@@ -5587,12 +5484,9 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
 
          if (rv < 0)
            {
-             if (0
+             if (errno == EAGAIN
 #ifdef EWOULDBLOCK
                  || errno == EWOULDBLOCK
-#endif
-#ifdef EAGAIN
-                 || errno == EAGAIN
 #endif
                  )
                /* Buffer is full.  Wait, accepting input;
@@ -5662,19 +5556,19 @@ it is sent in several bunches.  This may happen even for shorter regions.
 Output from processes can arrive in between bunches.  */)
   (Lisp_Object process, Lisp_Object start, Lisp_Object end)
 {
-  Lisp_Object proc;
-  ptrdiff_t start1, end1;
+  Lisp_Object proc = get_process (process);
+  ptrdiff_t start_byte, end_byte;
 
-  proc = get_process (process);
   validate_region (&start, &end);
 
+  start_byte = CHAR_TO_BYTE (XINT (start));
+  end_byte = CHAR_TO_BYTE (XINT (end));
+
   if (XINT (start) < GPT && XINT (end) > GPT)
-    move_gap (XINT (start));
+    move_gap_both (XINT (start), start_byte);
 
-  start1 = CHAR_TO_BYTE (XINT (start));
-  end1 = CHAR_TO_BYTE (XINT (end));
-  send_process (proc, (char *) BYTE_POS_ADDR (start1), end1 - start1,
-               Fcurrent_buffer ());
+  send_process (proc, (char *) BYTE_POS_ADDR (start_byte), 
+               end_byte - start_byte, Fcurrent_buffer ());
 
   return Qnil;
 }
@@ -5765,7 +5659,7 @@ return t unconditionally.  */)
 
    If we can, we try to signal PROCESS by sending control characters
    down the pty.  This allows us to signal inferiors who have changed
-   their uid, for which killpg would return an EPERM error.  */
+   their uid, for which kill would return an EPERM error.  */
 
 static void
 process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
@@ -5903,7 +5797,7 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
   if (!NILP (current_group))
     {
       if (ioctl (p->infd, TIOCSIGSEND, signo) == -1)
-       EMACS_KILLPG (gid, signo);
+       kill (-gid, signo);
     }
   else
     {
@@ -5911,7 +5805,7 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
       kill (gid, signo);
     }
 #else /* ! defined (TIOCSIGSEND) */
-  EMACS_KILLPG (gid, signo);
+  kill (-gid, signo);
 #endif /* ! defined (TIOCSIGSEND) */
 }
 
@@ -6016,6 +5910,27 @@ traffic.  */)
   return process;
 }
 
+/* Return the integer value of the signal whose abbreviation is ABBR,
+   or a negative number if there is no such signal.  */
+static int
+abbr_to_signal (char const *name)
+{
+  int i, signo;
+  char sigbuf[20]; /* Large enough for all valid signal abbreviations.  */
+
+  if (!strncmp (name, "SIG", 3) || !strncmp (name, "sig", 3))
+    name += 3;
+
+  for (i = 0; i < sizeof sigbuf; i++)
+    {
+      sigbuf[i] = c_toupper (name[i]);
+      if (! sigbuf[i])
+       return str2sig (sigbuf, &signo) == 0 ? signo : -1;
+    }
+
+  return -1;
+}
+
 DEFUN ("signal-process", Fsignal_process, Ssignal_process,
        2, 2, "sProcess (name or number): \nnSignal code: ",
        doc: /* Send PROCESS the signal with code SIGCODE.
@@ -6026,6 +5941,7 @@ SIGCODE may be an integer, or a symbol whose name is a signal name.  */)
   (Lisp_Object process, Lisp_Object sigcode)
 {
   pid_t pid;
+  int signo;
 
   if (STRINGP (process))
     {
@@ -6055,12 +5971,11 @@ SIGCODE may be an integer, or a symbol whose name is a signal name.  */)
        error ("Cannot signal process %s", SDATA (XPROCESS (process)->name));
     }
 
-#define parse_signal(NAME, VALUE)              \
-  else if (!xstrcasecmp (name, NAME))          \
-    XSETINT (sigcode, VALUE)
-
   if (INTEGERP (sigcode))
-    CHECK_TYPE_RANGED_INTEGER (int, sigcode);
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, sigcode);
+      signo = XINT (sigcode);
+    }
   else
     {
       char *name;
@@ -6068,96 +5983,12 @@ SIGCODE may be an integer, or a symbol whose name is a signal name.  */)
       CHECK_SYMBOL (sigcode);
       name = SSDATA (SYMBOL_NAME (sigcode));
 
-      if (!strncmp (name, "SIG", 3) || !strncmp (name, "sig", 3))
-       name += 3;
-
-      if (0)
-       ;
-#ifdef SIGUSR1
-      parse_signal ("usr1", SIGUSR1);
-#endif
-#ifdef SIGUSR2
-      parse_signal ("usr2", SIGUSR2);
-#endif
-      parse_signal ("term", SIGTERM);
-#ifdef SIGHUP
-      parse_signal ("hup", SIGHUP);
-#endif
-      parse_signal ("int", SIGINT);
-#ifdef SIGQUIT
-      parse_signal ("quit", SIGQUIT);
-#endif
-      parse_signal ("ill", SIGILL);
-      parse_signal ("abrt", SIGABRT);
-#ifdef SIGEMT
-      parse_signal ("emt", SIGEMT);
-#endif
-#ifdef SIGKILL
-      parse_signal ("kill", SIGKILL);
-#endif
-      parse_signal ("fpe", SIGFPE);
-#ifdef SIGBUS
-      parse_signal ("bus", SIGBUS);
-#endif
-      parse_signal ("segv", SIGSEGV);
-#ifdef SIGSYS
-      parse_signal ("sys", SIGSYS);
-#endif
-#ifdef SIGPIPE
-      parse_signal ("pipe", SIGPIPE);
-#endif
-#ifdef SIGALRM
-      parse_signal ("alrm", SIGALRM);
-#endif
-#ifdef SIGURG
-      parse_signal ("urg", SIGURG);
-#endif
-#ifdef SIGSTOP
-      parse_signal ("stop", SIGSTOP);
-#endif
-#ifdef SIGTSTP
-      parse_signal ("tstp", SIGTSTP);
-#endif
-#ifdef SIGCONT
-      parse_signal ("cont", SIGCONT);
-#endif
-#ifdef SIGCHLD
-      parse_signal ("chld", SIGCHLD);
-#endif
-#ifdef SIGTTIN
-      parse_signal ("ttin", SIGTTIN);
-#endif
-#ifdef SIGTTOU
-      parse_signal ("ttou", SIGTTOU);
-#endif
-#ifdef SIGIO
-      parse_signal ("io", SIGIO);
-#endif
-#ifdef SIGXCPU
-      parse_signal ("xcpu", SIGXCPU);
-#endif
-#ifdef SIGXFSZ
-      parse_signal ("xfsz", SIGXFSZ);
-#endif
-#ifdef SIGVTALRM
-      parse_signal ("vtalrm", SIGVTALRM);
-#endif
-#ifdef SIGPROF
-      parse_signal ("prof", SIGPROF);
-#endif
-#ifdef SIGWINCH
-      parse_signal ("winch", SIGWINCH);
-#endif
-#ifdef SIGINFO
-      parse_signal ("info", SIGINFO);
-#endif
-      else
+      signo = abbr_to_signal (name);
+      if (signo < 0)
        error ("Undefined signal name %s", name);
     }
 
-#undef parse_signal
-
-  return make_number (kill (pid, XINT (sigcode)));
+  return make_number (kill (pid, signo));
 }
 
 DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
@@ -6239,35 +6070,35 @@ process has been transmitted to the serial port.  */)
   return process;
 }
 \f
-/* If the status of the process DESIRED has changed, return true and
-   set *STATUS to its exit status; otherwise, return false.
-   If HAVE is nonnegative, assume that HAVE = waitpid (HAVE, STATUS, ...)
-   has already been invoked, and do not invoke waitpid again.  */
-
-static bool
-process_status_retrieved (pid_t desired, pid_t have, int *status)
-{
-  if (have < 0)
-    {
-      /* Invoke waitpid only with a known process ID; do not invoke
-        waitpid with a nonpositive argument.  Otherwise, Emacs might
-        reap an unwanted process by mistake.  For example, invoking
-        waitpid (-1, ...) can mess up glib by reaping glib's subprocesses,
-        so that another thread running glib won't find them.  */
-      do
-       have = waitpid (desired, status, WNOHANG | WUNTRACED);
-      while (have < 0 && errno == EINTR);
-    }
-
-  return have == desired;
-}
-
-/* If PID is nonnegative, the child process PID with wait status W has
-   changed its status; record this and return true.
-
-   If PID is negative, ignore W, and look for known child processes
-   of Emacs whose status have changed.  For each one found, record its new
-   status.
+/* The main Emacs thread records child processes in three places:
+
+   - Vprocess_alist, for asynchronous subprocesses, which are child
+     processes visible to Lisp.
+
+   - deleted_pid_list, for child processes invisible to Lisp,
+     typically because of delete-process.  These are recorded so that
+     the processes can be reaped when they exit, so that the operating
+     system's process table is not cluttered by zombies.
+
+   - the local variable PID in Fcall_process, call_process_cleanup and
+     call_process_kill, for synchronous subprocesses.
+     record_unwind_protect is used to make sure this process is not
+     forgotten: if the user interrupts call-process and the child
+     process refuses to exit immediately even with two C-g's,
+     call_process_kill adds PID's contents to deleted_pid_list before
+     returning.
+
+   The main Emacs thread invokes waitpid only on child processes that
+   it creates and that have not been reaped.  This avoid races on
+   platforms such as GTK, where other threads create their own
+   subprocesses which the main thread should not reap.  For example,
+   if the main thread attempted to reap an already-reaped child, it
+   might inadvertently reap a GTK-created process that happened to
+   have the same process ID.  */
+
+/* Handle a SIGCHLD signal by looking for known child processes of
+   Emacs whose status have changed.  For each one found, record its
+   new status.
 
    All we do is change the status; we do not run sentinels or print
    notifications.  That is saved for the next time keyboard input is
@@ -6290,28 +6121,15 @@ process_status_retrieved (pid_t desired, pid_t have, int *status)
    ** Malloc WARNING: This should never call malloc either directly or
    indirectly; if it does, that is a bug  */
 
-void
-record_child_status_change (pid_t pid, int w)
+static void
+handle_child_signal (int sig)
 {
-#ifdef SIGCHLD
-
-# ifdef WNOHANG
-  /* On POSIXish hosts, record at most one child only if we already
-     know one child that has exited.  */
-  bool record_at_most_one_child = 0 <= pid;
-# else
-  /* On DOS_NT (the only porting target that lacks WNOHANG),
-     record the status of at most one child process, since the SIGCHLD
-     handler must return right away.  If any more processes want to
-     signal us, we will get another signal.  */
-  bool record_at_most_one_child = 1;
-# endif
-
   Lisp_Object tail;
 
   /* Find the process that signaled us, and record its status.  */
 
-  /* The process can have been deleted by Fdelete_process.  */
+  /* The process can have been deleted by Fdelete_process, or have
+     been started asynchronously by Fcall_process.  */
   for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail))
     {
       bool all_pids_are_fixnums
@@ -6325,12 +6143,8 @@ record_child_status_change (pid_t pid, int w)
            deleted_pid = XINT (xpid);
          else
            deleted_pid = XFLOAT_DATA (xpid);
-         if (process_status_retrieved (deleted_pid, pid, &w))
-           {
-             XSETCAR (tail, Qnil);
-             if (record_at_most_one_child)
-               return;
-           }
+         if (child_status_changed (deleted_pid, 0, 0))
+           XSETCAR (tail, Qnil);
        }
     }
 
@@ -6339,15 +6153,17 @@ record_child_status_change (pid_t pid, int w)
     {
       Lisp_Object proc = XCDR (XCAR (tail));
       struct Lisp_Process *p = XPROCESS (proc);
-      if (p->alive && process_status_retrieved (p->pid, pid, &w))
+      int status;
+
+      if (p->alive && child_status_changed (p->pid, &status, WUNTRACED))
        {
          /* Change the status of the process that was found.  */
          p->tick = ++process_tick;
-         p->raw_status = w;
+         p->raw_status = status;
          p->raw_status_new = 1;
 
          /* If process has terminated, stop waiting for its output.  */
-         if (WIFSIGNALED (w) || WIFEXITED (w))
+         if (WIFSIGNALED (status) || WIFEXITED (status))
            {
              int clear_desc_flag = 0;
              p->alive = 0;
@@ -6361,44 +6177,8 @@ record_child_status_change (pid_t pid, int w)
                  FD_CLR (p->infd, &non_keyboard_wait_mask);
                }
            }
-
-         /* Tell wait_reading_process_output that it needs to wake up and
-            look around.  */
-         if (input_available_clear_time)
-           *input_available_clear_time = make_emacs_time (0, 0);
-
-         if (record_at_most_one_child)
-           return;
        }
     }
-
-  if (0 <= pid)
-    {
-      /* The caller successfully waited for a pid but no asynchronous
-        process was found for it, so this is a synchronous process.  */
-
-      synch_process_alive = 0;
-
-      /* Report the status of the synchronous process.  */
-      if (WIFEXITED (w))
-       synch_process_retcode = WEXITSTATUS (w);
-      else if (WIFSIGNALED (w))
-       synch_process_termsig = WTERMSIG (w);
-
-      /* Tell wait_reading_process_output that it needs to wake up and
-        look around.  */
-      if (input_available_clear_time)
-       *input_available_clear_time = make_emacs_time (0, 0);
-    }
-#endif
-}
-
-#ifdef SIGCHLD
-
-static void
-handle_child_signal (int sig)
-{
-  record_child_status_change (-1, 0);
 }
 
 static void
@@ -6406,8 +6186,6 @@ deliver_child_signal (int sig)
 {
   deliver_process_signal (sig, handle_child_signal);
 }
-
-#endif /* SIGCHLD */
 \f
 
 static Lisp_Object
@@ -7256,7 +7034,6 @@ init_process_emacs (void)
 
   inhibit_sentinels = 0;
 
-#ifdef SIGCHLD
 #ifndef CANNOT_DUMP
   if (! noninteractive || initialized)
 #endif
@@ -7265,7 +7042,6 @@ init_process_emacs (void)
       emacs_sigaction_init (&action, deliver_child_signal);
       sigaction (SIGCHLD, &action, 0);
     }
-#endif
 
   FD_ZERO (&input_wait_mask);
   FD_ZERO (&non_keyboard_wait_mask);
@@ -7292,9 +7068,7 @@ init_process_emacs (void)
 #endif
 
   Vprocess_alist = Qnil;
-#ifdef SIGCHLD
   deleted_pid_list = Qnil;
-#endif
   for (i = 0; i < MAXDESC; i++)
     {
       chan_process[i] = Qnil;
@@ -7332,9 +7106,7 @@ init_process_emacs (void)
 #ifdef HAVE_GETSOCKNAME
    ADD_SUBFEATURE (QCservice, Qt);
 #endif
-#if O_NONBLOCK || O_NDELAY
    ADD_SUBFEATURE (QCserver, Qt);
-#endif
 
    for (sopt = socket_options; sopt->name; sopt++)
      subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
@@ -7423,9 +7195,7 @@ syms_of_process (void)
   DEFSYM (Qlast_nonmenu_event, "last-nonmenu-event");
 
   staticpro (&Vprocess_alist);
-#ifdef SIGCHLD
   staticpro (&deleted_pid_list);
-#endif
 
 #endif /* subprocesses */