Assume POSIX 1003.1-1988 or later for errno.h.
[bpt/emacs.git] / src / process.c
index ab21576..b23f06f 100644 (file)
@@ -125,12 +125,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "xgselect.h"
 #endif
 
-#ifndef WNOHANG
-# undef waitpid
-# define waitpid(pid, status, options) wait (status)
-#endif
-#ifndef WUNTRACED
-# define WUNTRACED 0
+#ifdef WINDOWSNT
+extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
+                      EMACS_TIME *, void *);
 #endif
 
 /* Work around GCC 4.7.0 bug with strict overflow checking; see
@@ -199,11 +196,9 @@ static EMACS_INT update_tick;
 #ifndef NON_BLOCKING_CONNECT
 #ifdef HAVE_SELECT
 #if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
-#if defined (O_NONBLOCK) || defined (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 */
@@ -331,86 +326,83 @@ static struct sockaddr_and_len {
 #define DATAGRAM_CONN_P(proc)  (0)
 #endif
 
-/* Maximum number of bytes to send to a pty without an eof.  */
-static int pty_max_bytes;
-
 /* These setters are used only in this file, so they can be private.  */
-static inline void
+static void
 pset_buffer (struct Lisp_Process *p, Lisp_Object val)
 {
   p->buffer = val;
 }
-static inline void
+static void
 pset_command (struct Lisp_Process *p, Lisp_Object val)
 {
   p->command = val;
 }
-static inline void
+static void
 pset_decode_coding_system (struct Lisp_Process *p, Lisp_Object val)
 {
   p->decode_coding_system = val;
 }
-static inline void
+static void
 pset_decoding_buf (struct Lisp_Process *p, Lisp_Object val)
 {
   p->decoding_buf = val;
 }
-static inline void
+static void
 pset_encode_coding_system (struct Lisp_Process *p, Lisp_Object val)
 {
   p->encode_coding_system = val;
 }
-static inline void
+static void
 pset_encoding_buf (struct Lisp_Process *p, Lisp_Object val)
 {
   p->encoding_buf = val;
 }
-static inline void
+static void
 pset_filter (struct Lisp_Process *p, Lisp_Object val)
 {
   p->filter = val;
 }
-static inline void
+static void
 pset_log (struct Lisp_Process *p, Lisp_Object val)
 {
   p->log = val;
 }
-static inline void
+static void
 pset_mark (struct Lisp_Process *p, Lisp_Object val)
 {
   p->mark = val;
 }
-static inline void
+static void
 pset_name (struct Lisp_Process *p, Lisp_Object val)
 {
   p->name = val;
 }
-static inline void
+static void
 pset_plist (struct Lisp_Process *p, Lisp_Object val)
 {
   p->plist = val;
 }
-static inline void
+static void
 pset_sentinel (struct Lisp_Process *p, Lisp_Object val)
 {
   p->sentinel = val;
 }
-static inline void
+static void
 pset_status (struct Lisp_Process *p, Lisp_Object val)
 {
   p->status = val;
 }
-static inline void
+static void
 pset_tty_name (struct Lisp_Process *p, Lisp_Object val)
 {
   p->tty_name = val;
 }
-static inline void
+static void
 pset_type (struct Lisp_Process *p, Lisp_Object val)
 {
   p->type = val;
 }
-static inline void
+static void
 pset_write_queue (struct Lisp_Process *p, Lisp_Object val)
 {
   p->write_queue = val;
@@ -570,7 +562,7 @@ status_message (struct Lisp_Process *p)
 
   if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
     {
-      char *signame;
+      char const *signame;
       synchronize_system_messages_locale ();
       signame = strsignal (code);
       if (signame == 0)
@@ -645,30 +637,7 @@ allocate_pty (void)
 #ifdef PTY_OPEN
        PTY_OPEN;
 #else /* no PTY_OPEN */
-       {
-         { /* Some systems name their pseudoterminals so that there are gaps in
-              the usual sequence - for example, on HP9000/S700 systems, there
-              are no pseudoterminals with names ending in 'f'.  So we wait for
-              three failures in a row before deciding that we've reached the
-              end of the ptys.  */
-           int failed_count = 0;
-           struct stat stb;
-
-           if (stat (pty_name, &stb) < 0)
-             {
-               failed_count++;
-               if (failed_count >= 3)
-                 return -1;
-             }
-           else
-             failed_count = 0;
-         }
-#  ifdef 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)
@@ -680,7 +649,7 @@ allocate_pty (void)
 #else
            sprintf (pty_name, "/dev/tty%c%x", c, i);
 #endif /* no PTY_TTY_NAME_SPRINTF */
-           if (access (pty_name, 6) != 0)
+           if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0)
              {
                emacs_close (fd);
 # ifndef __sgi
@@ -807,9 +776,8 @@ 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; otherwise this handler would consider the
-   process as being synchronous and say that the synchronous process is
-   dead.  */
+   treated by the SIGCHLD handler and waitpid has been invoked on them;
+   otherwise they might fill up the kernel's process table.  */
 static Lisp_Object deleted_pid_list;
 #endif
 
@@ -1607,7 +1575,7 @@ 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
@@ -1633,13 +1601,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.  */
-#ifdef 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
@@ -1668,7 +1632,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;
 
@@ -1687,15 +1651,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
     }
 #endif
 
-#ifdef O_NONBLOCK
   fcntl (inchannel, F_SETFL, O_NONBLOCK);
   fcntl (outchannel, F_SETFL, O_NONBLOCK);
-#else
-#ifdef 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.  */
@@ -1716,16 +1673,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
   if (inchannel > max_process_desc)
     max_process_desc = inchannel;
 
-  /* Until we store the proper pid, enable the SIGCHLD handler
-     to recognize an unknown pid as standing for this process.
-     It is very important not to let this `marker' value stay
-     in the table after this function has returned; if it does
-     it might cause call-process to hang and subsequent asynchronous
-     processes to get their return values scrambled.  */
-  XPROCESS (process)->pid = -1;
-
-  /* This must be called after the above line because it may signal an
-     error. */
+  /* This may signal an error. */
   setup_process_coding_systems (process);
 
   encoded_current_dir = ENCODE_FILE (current_dir);
@@ -1757,7 +1705,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       /* Make the pty be the controlling terminal of the process.  */
 #ifdef HAVE_PTYS
       /* First, disconnect its current controlling terminal.  */
-#ifdef HAVE_SETSID
       /* We tried doing setsid only if pty_flag, but it caused
         process_set_signal to fail on SGI when using a pipe.  */
       setsid ();
@@ -1770,14 +1717,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
          ioctl (xforkin, TIOCSCTTY, 0);
 #endif
        }
-#else /* not HAVE_SETSID */
-#ifdef USG
-      /* It's very important to call setpgrp here and no time
-        afterwards.  Otherwise, we lose our controlling tty which
-        is set when we open the pty. */
-      setpgrp ();
-#endif /* USG */
-#endif /* not HAVE_SETSID */
 #if defined (LDISC1)
       if (pty_flag && xforkin >= 0)
        {
@@ -1810,26 +1749,15 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
              ioctl (j, TIOCNOTTY, 0);
              emacs_close (j);
            }
-#ifndef USG
-         /* In order to get a controlling terminal on some versions
-            of BSD, it is necessary to put the process in pgrp 0
-            before it opens the terminal.  */
-#ifdef HAVE_SETPGID
-         setpgid (0, 0);
-#else
-         setpgrp (0, 0);
-#endif
-#endif
        }
 #endif /* TIOCNOTTY */
 
 #if !defined (DONT_REOPEN_PTY)
 /*** There is a suggestion that this ought to be a
-     conditional on TIOCSPGRP,
-     or !(defined (HAVE_SETSID) && defined (TIOCSCTTY)).
+     conditional on TIOCSPGRP, or !defined TIOCSCTTY.
      Trying the latter gave the wrong results on Debian GNU/Linux 1.1;
      that system does seem to need this code, even though
-     both HAVE_SETSID and TIOCSCTTY are defined.  */
+     both TIOCSCTTY is defined.  */
        /* Now close the pty (if we had it open) and reopen it.
           This makes the pty the controlling terminal of the subprocess.  */
       if (pty_flag)
@@ -1883,9 +1811,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 */
@@ -1898,6 +1824,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 #endif
 
   XPROCESS (process)->pid = pid;
+  if (0 <= pid)
+    XPROCESS (process)->alive = 1;
 
   /* Stop blocking signals in the parent.  */
 #ifdef SIGCHLD
@@ -1942,7 +1870,7 @@ 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
@@ -1979,13 +1907,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.  */
-#ifdef 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)
@@ -1999,15 +1923,8 @@ create_pty (Lisp_Object process)
     }
 #endif /* HAVE_PTYS */
 
-#ifdef O_NONBLOCK
   fcntl (inchannel, F_SETFL, O_NONBLOCK);
   fcntl (outchannel, F_SETFL, O_NONBLOCK);
-#else
-#ifdef 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.  */
@@ -2963,13 +2880,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 !defined (O_NONBLOCK) && !defined (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).  */
@@ -3229,11 +3142,7 @@ usage: (make-network-process &rest ARGS)  */)
 #ifdef NON_BLOCKING_CONNECT
       if (is_non_blocking_client)
        {
-#ifdef O_NONBLOCK
          ret = fcntl (s, F_SETFL, O_NONBLOCK);
-#else
-         ret = fcntl (s, F_SETFL, O_NDELAY);
-#endif
          if (ret < 0)
            {
              xerrno = errno;
@@ -3446,13 +3355,7 @@ usage: (make-network-process &rest ARGS)  */)
 
   chan_process[inch] = proc;
 
-#ifdef O_NONBLOCK
   fcntl (inch, F_SETFL, O_NONBLOCK);
-#else
-#ifdef O_NDELAY
-  fcntl (inch, F_SETFL, O_NDELAY);
-#endif
-#endif
 
   p = XPROCESS (proc);
 
@@ -4181,13 +4084,7 @@ server_accept_connection (Lisp_Object server, int channel)
 
   chan_process[s] = proc;
 
-#ifdef O_NONBLOCK
   fcntl (s, F_SETFL, O_NONBLOCK);
-#else
-#ifdef O_NDELAY
-  fcntl (s, F_SETFL, O_NDELAY);
-#endif
-#endif
 
   p = XPROCESS (proc);
 
@@ -4302,7 +4199,7 @@ wait_reading_process_output_1 (void)
      -1 meaning caller will actually read the input, so don't throw to
        the quit handler, or
 
-   DO_DISPLAY != 0 means redisplay should be done to show subprocess
+   DO_DISPLAY means redisplay should be done to show subprocess
      output that arrives.
 
    If WAIT_FOR_CELL is a cons cell, wait until its car is non-nil
@@ -4322,7 +4219,7 @@ wait_reading_process_output_1 (void)
 
 int
 wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
-                            int do_display,
+                            bool do_display,
                             Lisp_Object wait_for_cell,
                             struct Lisp_Process *wait_proc, int just_wait_proc)
 {
@@ -4419,7 +4316,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 
          do
            {
-             int old_timers_run = timers_run;
+             unsigned old_timers_run = timers_run;
              struct buffer *old_buffer = current_buffer;
              Lisp_Object old_window = selected_window;
 
@@ -4455,7 +4352,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                  if (EMACS_TIME_LT (timer_delay, timeout))
                    {
                      timeout = timer_delay;
-                     timeout_reduced_for_timers = 1;
+                     timeout_reduced_for_timers = 1;
                    }
                }
              else
@@ -4535,14 +4432,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;
@@ -4646,6 +4537,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              process_output_skip = 0;
            }
 #endif
+
 #if defined (USE_GTK) || defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
           nfds = xg_select
 #elif defined (HAVE_NS)
@@ -4752,7 +4644,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 
       if (read_kbd != 0)
        {
-         int old_timers_run = timers_run;
+         unsigned old_timers_run = timers_run;
          struct buffer *old_buffer = current_buffer;
          Lisp_Object old_window = selected_window;
          int leave = 0;
@@ -4882,23 +4774,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.  */
-#ifdef O_NONBLOCK
-             else if (nread == -1 && errno == EAGAIN)
-               ;
-#else
-#ifdef 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
@@ -5567,19 +5453,6 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
       buf = SSDATA (object);
     }
 
-  if (pty_max_bytes == 0)
-    {
-#if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON)
-      pty_max_bytes = fpathconf (p->outfd, _PC_MAX_CANON);
-      if (pty_max_bytes < 0)
-       pty_max_bytes = 250;
-#else
-      pty_max_bytes = 250;
-#endif
-      /* Deduct one, to leave space for the eof.  */
-      pty_max_bytes--;
-    }
-
   /* If there is already data in the write_queue, put the new data
      in the back of queue.  Otherwise, ignore it.  */
   if (!NILP (p->write_queue))
@@ -5638,12 +5511,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;
@@ -6290,9 +6160,35 @@ process has been transmitted to the serial port.  */)
   return process;
 }
 \f
-/* On receipt of a signal that a child status has changed, loop asking
-   about children with changed statuses until the system says there
-   are no more.
+/* 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.
 
    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
@@ -6315,13 +6211,15 @@ process has been transmitted to the serial port.  */)
    ** Malloc WARNING: This should never call malloc either directly or
    indirectly; if it does, that is a bug  */
 
-/* Record the changed status of the child process PID with wait status W.  */
 void
 record_child_status_change (pid_t pid, int w)
 {
 #ifdef SIGCHLD
-  Lisp_Object proc;
-  struct Lisp_Process *p;
+
+  /* Record at most one child only if we already know one child that
+     has exited.  */
+  bool record_at_most_one_child = 0 <= pid;
+
   Lisp_Object tail;
 
   /* Find the process that signaled us, and record its status.  */
@@ -6329,68 +6227,69 @@ record_child_status_change (pid_t pid, int w)
   /* The process can have been deleted by Fdelete_process.  */
   for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail))
     {
+      bool all_pids_are_fixnums
+       = (MOST_NEGATIVE_FIXNUM <= TYPE_MINIMUM (pid_t)
+          && TYPE_MAXIMUM (pid_t) <= MOST_POSITIVE_FIXNUM);
       Lisp_Object xpid = XCAR (tail);
-      if ((INTEGERP (xpid) && pid == XINT (xpid))
-         || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid)))
+      if (all_pids_are_fixnums ? INTEGERP (xpid) : NUMBERP (xpid))
        {
-         XSETCAR (tail, Qnil);
-         return;
+         pid_t deleted_pid;
+         if (INTEGERP (xpid))
+           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;
+           }
        }
     }
 
   /* Otherwise, if it is asynchronous, it is in Vprocess_alist.  */
-  p = 0;
   for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
     {
-      proc = XCDR (XCAR (tail));
-      p = XPROCESS (proc);
-      if (EQ (p->type, Qreal) && p->pid == pid)
-       break;
-      p = 0;
-    }
-
-  /* Look for an asynchronous process whose pid hasn't been filled
-     in yet.  */
-  if (! p)
-    for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
-      {
-       proc = XCDR (XCAR (tail));
-       p = XPROCESS (proc);
-       if (p->pid == -1)
-         break;
-       p = 0;
-      }
+      Lisp_Object proc = XCDR (XCAR (tail));
+      struct Lisp_Process *p = XPROCESS (proc);
+      if (p->alive && process_status_retrieved (p->pid, pid, &w))
+       {
+         /* Change the status of the process that was found.  */
+         p->tick = ++process_tick;
+         p->raw_status = w;
+         p->raw_status_new = 1;
 
-  /* Change the status of the process that was found.  */
-  if (p)
-    {
-      int clear_desc_flag = 0;
+         /* If process has terminated, stop waiting for its output.  */
+         if (WIFSIGNALED (w) || WIFEXITED (w))
+           {
+             int clear_desc_flag = 0;
+             p->alive = 0;
+             if (p->infd >= 0)
+               clear_desc_flag = 1;
 
-      p->tick = ++process_tick;
-      p->raw_status = w;
-      p->raw_status_new = 1;
+             /* clear_desc_flag avoids a compiler bug in Microsoft C.  */
+             if (clear_desc_flag)
+               {
+                 FD_CLR (p->infd, &input_wait_mask);
+                 FD_CLR (p->infd, &non_keyboard_wait_mask);
+               }
+           }
 
-      /* If process has terminated, stop waiting for its output.  */
-      if ((WIFSIGNALED (w) || WIFEXITED (w))
-         && p->infd >= 0)
-       clear_desc_flag = 1;
+         /* 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);
 
-      /* We use clear_desc_flag to avoid a compiler bug in Microsoft C.  */
-      if (clear_desc_flag)
-       {
-         FD_CLR (p->infd, &input_wait_mask);
-         FD_CLR (p->infd, &non_keyboard_wait_mask);
+         if (record_at_most_one_child)
+           return;
        }
-
-      /* 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);
     }
-  /* There was no asynchronous process found for that pid: we have
-     a synchronous process.  */
-  else
+
+  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.  */
@@ -6409,38 +6308,10 @@ record_child_status_change (pid_t pid, int w)
 
 #ifdef SIGCHLD
 
-/* On some systems, the SIGCHLD handler must return right away.  If
-   any more processes want to signal us, we will get another signal.
-   Otherwise, loop around to use up all the processes that have
-   something to tell us.  */
-#if (defined WINDOWSNT \
-     || (defined USG && !defined GNU_LINUX \
-        && !(defined HPUX && defined WNOHANG)))
-enum { CAN_HANDLE_MULTIPLE_CHILDREN = 0 };
-#else
-enum { CAN_HANDLE_MULTIPLE_CHILDREN = 1 };
-#endif
-
 static void
 handle_child_signal (int sig)
 {
-  do
-    {
-      pid_t pid;
-      int status;
-
-      do
-       pid = waitpid (-1, &status, WNOHANG | WUNTRACED);
-      while (pid < 0 && errno == EINTR);
-
-      /* PID == 0 means no processes found, PID == -1 means a real failure.
-        Either way, we have done all our job.  */
-      if (pid <= 0)
-       break;
-
-      record_child_status_change (pid, status);
-    }
-  while (CAN_HANDLE_MULTIPLE_CHILDREN);
+  record_child_status_change (-1, 0);
 }
 
 static void
@@ -6820,14 +6691,14 @@ extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
    see full version for other parameters. We know that wait_proc will
      always be NULL, since `subprocesses' isn't defined.
 
-   DO_DISPLAY != 0 means redisplay should be done to show subprocess
+   DO_DISPLAY means redisplay should be done to show subprocess
    output that arrives.
 
    Return true if we received input from any process.  */
 
 int
 wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
-                            int do_display,
+                            bool do_display,
                             Lisp_Object wait_for_cell,
                             struct Lisp_Process *wait_proc, int just_wait_proc)
 {
@@ -6903,7 +6774,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 
          do
            {
-             int old_timers_run = timers_run;
+             unsigned old_timers_run = timers_run;
              timer_delay = timer_check ();
              if (timers_run != old_timers_run && do_display)
                /* We must retry, since a timer may have requeued itself
@@ -7374,9 +7245,7 @@ init_process_emacs (void)
 #ifdef HAVE_GETSOCKNAME
    ADD_SUBFEATURE (QCservice, Qt);
 #endif
-#if defined (O_NONBLOCK) || defined (O_NDELAY)
    ADD_SUBFEATURE (QCserver, Qt);
-#endif
 
    for (sopt = socket_options; sopt->name; sopt++)
      subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);