use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / process.c
index fdb0501..3f5ad06 100644 (file)
@@ -224,8 +224,9 @@ static EMACS_INT update_tick;
 /* Only W32 has this, it really means that select can't take write mask.  */
 #ifdef BROKEN_NON_BLOCKING_CONNECT
 #undef NON_BLOCKING_CONNECT
-#define SELECT_CANT_DO_WRITE_MASK
+enum { SELECT_CAN_DO_WRITE_MASK = false };
 #else
+enum { SELECT_CAN_DO_WRITE_MASK = true };
 #ifndef NON_BLOCKING_CONNECT
 #ifdef HAVE_SELECT
 #if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
@@ -281,17 +282,11 @@ static void create_process (Lisp_Object, char **, Lisp_Object);
 static bool keyboard_bit_set (fd_set *);
 #endif
 static void deactivate_process (Lisp_Object);
-static void status_notify (struct Lisp_Process *);
+static int status_notify (struct Lisp_Process *, struct Lisp_Process *);
 static int read_process_output (Lisp_Object, int);
 static void handle_child_signal (int);
 static void create_pty (Lisp_Object);
 
-/* If we support a window system, turn on the code to poll periodically
-   to detect C-g.  It isn't actually used when doing interrupt input.  */
-#ifdef HAVE_WINDOW_SYSTEM
-#define POLL_FOR_INPUT
-#endif
-
 static Lisp_Object get_process (register Lisp_Object name);
 static void exec_sentinel (Lisp_Object proc, Lisp_Object reason);
 
@@ -468,7 +463,6 @@ static struct fd_callback_data
 void
 add_read_fd (int fd, fd_callback func, void *data)
 {
-  eassert (fd < FD_SETSIZE);
   add_keyboard_wait_descriptor (fd);
 
   fd_callback_info[fd].func = func;
@@ -481,7 +475,6 @@ add_read_fd (int fd, fd_callback func, void *data)
 void
 delete_read_fd (int fd)
 {
-  eassert (fd < FD_SETSIZE);
   delete_keyboard_wait_descriptor (fd);
 
   fd_callback_info[fd].condition &= ~FOR_READ;
@@ -498,7 +491,6 @@ delete_read_fd (int fd)
 void
 add_write_fd (int fd, fd_callback func, void *data)
 {
-  eassert (fd < FD_SETSIZE);
   FD_SET (fd, &write_mask);
   if (fd > max_input_desc)
     max_input_desc = fd;
@@ -529,7 +521,6 @@ delete_input_desc (int fd)
 void
 delete_write_fd (int fd)
 {
-  eassert (fd < FD_SETSIZE);
   FD_CLR (fd, &write_mask);
   fd_callback_info[fd].condition &= ~FOR_WRITE;
   if (fd_callback_info[fd].condition == 0)
@@ -870,7 +861,7 @@ nil, indicating the current buffer's process.  */)
     {
       pset_status (p, list2 (Qexit, make_number (0)));
       p->tick = ++process_tick;
-      status_notify (p);
+      status_notify (p, NULL);
       redisplay_preserve_echo_area (13);
     }
   else
@@ -890,7 +881,7 @@ nil, indicating the current buffer's process.  */)
            pset_status (p, list2 (Qsignal, make_number (SIGKILL)));
 
          p->tick = ++process_tick;
-         status_notify (p);
+         status_notify (p, NULL);
          redisplay_preserve_echo_area (13);
        }
     }
@@ -1397,7 +1388,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
   Lisp_Object buffer, name, program, proc, current_dir, tem;
   register unsigned char **new_argv;
   ptrdiff_t i;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   buffer = args[1];
   if (!NILP (buffer))
@@ -1601,7 +1592,8 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
   else
     create_pty (proc);
 
-  return unbind_to (count, proc);
+  dynwind_end ();
+  return proc;
 }
 
 /* This function is the unwind_protect form for Fstart_process.  If
@@ -1967,9 +1959,6 @@ create_pty (Lisp_Object process)
 /* Convert an internal struct sockaddr to a lisp object (vector or string).
    The address family of sa is not included in the result.  */
 
-#ifndef WINDOWSNT
-static
-#endif
 Lisp_Object
 conv_sockaddr_to_lisp (struct sockaddr *sa, int len)
 {
@@ -2576,8 +2565,8 @@ usage:  (make-serial-process &rest ARGS)  */)
     name = port;
   CHECK_STRING (name);
   proc = make_process (name);
-  specpdl_count = SPECPDL_INDEX ();
-  record_unwind_protect (remove_process, proc);
+  dynwind_begin ();
+  record_unwind_protect_1 (remove_process, proc, false);
   p = XPROCESS (proc);
 
   fd = serial_open (port);
@@ -2660,7 +2649,7 @@ usage:  (make-serial-process &rest ARGS)  */)
 
   Fserial_process_configure (nargs, args);
 
-  specpdl_ptr = specpdl + specpdl_count;
+  dynwind_end ();
 
   UNGCPRO;
   return proc;
@@ -2854,9 +2843,7 @@ usage: (make-network-process &rest ARGS)  */)
   int xerrno = 0;
   int s = -1, outch, inch;
   struct gcpro gcpro1;
-  ptrdiff_t count = SPECPDL_INDEX ();
-  ptrdiff_t count1;
-  Lisp_Object QCaddress;  /* one of QClocal or QCremote */
+  Lisp_Object colon_address;  /* Either QClocal or QCremote.  */
   Lisp_Object tem;
   Lisp_Object name, buffer, host, service, address;
   Lisp_Object filter, sentinel;
@@ -2869,6 +2856,8 @@ usage: (make-network-process &rest ARGS)  */)
   if (nargs == 0)
     return Qnil;
 
+  dynwind_begin ();
+
   /* Save arguments for process-contact and clone-process.  */
   contact = Flist (nargs, args);
   GCPRO1 (contact);
@@ -2904,8 +2893,8 @@ usage: (make-network-process &rest ARGS)  */)
        backlog = XINT (tem);
     }
 
-  /* Make QCaddress an alias for :local (server) or :remote (client).  */
-  QCaddress = is_server ? QClocal : QCremote;
+  /* Make colon_address an alias for :local (server) or :remote (client).  */
+  colon_address = is_server ? QClocal : QCremote;
 
   /* :nowait BOOL */
   if (!is_server && socktype != SOCK_DGRAM
@@ -2932,7 +2921,7 @@ usage: (make-network-process &rest ARGS)  */)
   res = &ai;
 
   /* :local ADDRESS or :remote ADDRESS */
-  address = Fplist_get (contact, QCaddress);
+  address = Fplist_get (contact, colon_address);
   if (!NILP (address))
     {
       host = service = Qnil;
@@ -3134,7 +3123,7 @@ usage: (make-network-process &rest ARGS)  */)
  open_socket:
 
   /* Do this in case we never enter the for-loop below.  */
-  count1 = SPECPDL_INDEX ();
+  dynwind_begin ();
   s = -1;
 
   for (lres = res; lres; lres = lres->ai_next)
@@ -3174,7 +3163,7 @@ usage: (make-network-process &rest ARGS)  */)
 #endif
 
       /* Make us close S if quit.  */
-      record_unwind_protect_int (close_file_unwind, s);
+      record_unwind_protect_int_1 (close_file_unwind, s, false);
 
       /* Parse network options in the arg list.
         We simply ignore anything which isn't a known option (including other keywords).
@@ -3281,8 +3270,8 @@ usage: (make-network-process &rest ARGS)  */)
 
       immediate_quit = 0;
 
-      /* Discard the unwind protect closing S.  */
-      specpdl_ptr = specpdl + count1;
+      dynwind_end ();
+      dynwind_begin ();
       emacs_close (s);
       s = -1;
 
@@ -3319,7 +3308,7 @@ usage: (make-network-process &rest ARGS)  */)
            memcpy (datagram_address[s].sa, lres->ai_addr, lres->ai_addrlen);
        }
 #endif
-      contact = Fplist_put (contact, QCaddress,
+      contact = Fplist_put (contact, colon_address,
                            conv_sockaddr_to_lisp (lres->ai_addr, lres->ai_addrlen));
 #ifdef HAVE_GETSOCKNAME
       if (!is_server)
@@ -3351,7 +3340,11 @@ usage: (make-network-process &rest ARGS)  */)
         the normal blocking calls to open-network-stream handles this error
         better.  */
       if (is_non_blocking_client)
+        {
+          dynwind_end ();
+          dynwind_end ();
          return Qnil;
+        }
 
       report_file_errno ((is_server
                          ? "make server process failed"
@@ -3390,11 +3383,10 @@ usage: (make-network-process &rest ARGS)  */)
   p->infd  = inch;
   p->outfd = outch;
 
-  /* Discard the unwind protect for closing S, if any.  */
-  specpdl_ptr = specpdl + count1;
+  dynwind_end ();
 
   /* Unwind bind_polling_period and request_sigio.  */
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   if (is_server && socktype != SOCK_DGRAM)
     pset_status (p, Qlisten);
@@ -3539,13 +3531,13 @@ network_interface_list (void)
   void *buf = NULL;
   ptrdiff_t buf_size = 512;
   int s;
-  Lisp_Object res;
+  Lisp_Object res = Qnil;
   ptrdiff_t count;
 
   s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
-  count = SPECPDL_INDEX ();
+  dynwind_begin ();
   record_unwind_protect_int (close_file_unwind, s);
 
   do
@@ -3557,12 +3549,13 @@ network_interface_list (void)
        {
          emacs_close (s);
          xfree (buf);
+         dynwind_end ();
          return Qnil;
        }
     }
   while (ifconf.ifc_len == buf_size);
 
-  res = unbind_to (count, Qnil);
+  dynwind_end ();
   ifreq = ifconf.ifc_req;
   while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len)
     {
@@ -3697,7 +3690,7 @@ network_interface_info (Lisp_Object ifname)
   s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
-  count = SPECPDL_INDEX ();
+  dynwind_begin ();
   record_unwind_protect_int (close_file_unwind, s);
 
   elt = Qnil;
@@ -3817,7 +3810,9 @@ network_interface_info (Lisp_Object ifname)
 #endif
   res = Fcons (elt, res);
 
-  return unbind_to (count, any ? res : Qnil);
+  Lisp_Object tem0 = any ? res : Qnil;
+  dynwind_end ();
+  return tem0;
 }
 #endif /* !SIOCGIFADDR && !SIOCGIFHWADDR && !SIOCGIFFLAGS */
 #endif /* defined (HAVE_NET_IF_H) */
@@ -3934,19 +3929,20 @@ DEFUN ("accept-process-output", Faccept_process_output, Saccept_process_output,
        0, 4, 0,
        doc: /* Allow any pending output from subprocesses to be read by Emacs.
 It is given to their filter functions.
-Non-nil arg PROCESS means do not return until some output has been received
-from PROCESS.
+Optional argument PROCESS means do not return until output has been
+received from PROCESS.
 
-Non-nil second arg SECONDS and third arg MILLISEC are number of seconds
-and milliseconds to wait; return after that much time whether or not
-there is any subprocess output.  If SECONDS is a floating point number,
+Optional second argument SECONDS and third argument MILLISEC
+specify a timeout; return after that much time even if there is
+no subprocess output.  If SECONDS is a floating point number,
 it specifies a fractional number of seconds to wait.
 The MILLISEC argument is obsolete and should be avoided.
 
-If optional fourth arg JUST-THIS-ONE is non-nil, only accept output
-from PROCESS, suspending reading output from other processes.
+If optional fourth argument JUST-THIS-ONE is non-nil, accept output
+from PROCESS only, suspending reading output from other processes.
 If JUST-THIS-ONE is an integer, don't run any timers either.
-Return non-nil if we received any output before the timeout expired.  */)
+Return non-nil if we received any output from PROCESS (or, if PROCESS
+is nil, from any process) before the timeout expired.  */)
   (register Lisp_Object process, Lisp_Object seconds, Lisp_Object millisec, Lisp_Object just_this_one)
 {
   intmax_t secs;
@@ -3998,12 +3994,13 @@ Return non-nil if we received any output before the timeout expired.  */)
     nsecs = 0;
 
   return
-    (wait_reading_process_output (secs, nsecs, 0, 0,
+    ((wait_reading_process_output (secs, nsecs, 0, 0,
                                  Qnil,
                                  !NILP (process) ? XPROCESS (process) : NULL,
                                  NILP (just_this_one) ? 0 :
                                  !INTEGERP (just_this_one) ? 1 : -1)
-     ? Qt : Qnil);
+      <= 0)
+     ? Qnil : Qt);
 }
 
 /* Accept a connection for server process SERVER on CHANNEL.  */
@@ -4052,8 +4049,8 @@ server_accept_connection (Lisp_Object server, int channel)
       return;
     }
 
-  count = SPECPDL_INDEX ();
-  record_unwind_protect_int (close_file_unwind, s);
+  dynwind_begin ();
+  record_unwind_protect_int_1 (close_file_unwind, s, false);
 
   connect_counter++;
 
@@ -4172,8 +4169,7 @@ server_accept_connection (Lisp_Object server, int channel)
   pset_command (p, Qnil);
   p->pid = 0;
 
-  /* Discard the unwind protect for closing S.  */
-  specpdl_ptr = specpdl + count;
+  dynwind_end ();
 
   p->open_fd[SUBPROCESS_STDIN] = s;
   p->infd  = s;
@@ -4268,18 +4264,17 @@ wait_reading_process_output_1 (void)
      (and gobble terminal input into the buffer if any arrives).
 
    If WAIT_PROC is specified, wait until something arrives from that
-     process.  The return value is true if we read some input from
-     that process.
+     process.
 
    If JUST_WAIT_PROC is nonzero, handle only output from WAIT_PROC
      (suspending output from other processes).  A negative value
      means don't run any timers either.
 
-   If WAIT_PROC is specified, then the function returns true if we
-     received input from that process before the timeout elapsed.
-   Otherwise, return true if we received input from any process.  */
+   Return positive if we received input from WAIT_PROC (or from any
+   process if WAIT_PROC is null), zero if we attempted to receive
+   input but got none, and negative if we didn't even try.  */
 
-bool
+int
 wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                             bool do_display,
                             Lisp_Object wait_for_cell,
@@ -4294,9 +4289,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
   int xerrno;
   Lisp_Object proc;
   struct timespec timeout, end_time;
-  int wait_channel = -1;
-  bool got_some_input = 0;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  int got_some_input = -1;
+  dynwind_begin ();
 
   FD_ZERO (&Available);
   FD_ZERO (&Writeok);
@@ -4306,10 +4300,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
           && EQ (XCAR (wait_proc->status), Qexit)))
     message1 ("Blocking call to accept-process-output with quit inhibited!!");
 
-  /* If wait_proc is a process to watch, set wait_channel accordingly.  */
-  if (wait_proc != NULL)
-    wait_channel = wait_proc->infd;
-
   record_unwind_protect_int (wait_reading_process_output_unwind,
                             waiting_for_user_input_p);
   waiting_for_user_input_p = read_kbd;
@@ -4346,6 +4336,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
        break;
 
+      /* After reading input, vacuum up any leftovers without waiting.  */
+      if (0 <= got_some_input)
+       nsecs = -1;
+
       /* Compute time from now till when time limit is up.  */
       /* Exit if already run out.  */
       if (nsecs < 0)
@@ -4464,7 +4458,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              /* It's okay for us to do this and then continue with
                 the loop, since timeout has already been zeroed out.  */
              clear_waiting_for_input ();
-             status_notify (NULL);
+             got_some_input = status_notify (NULL, wait_proc);
              if (do_display) redisplay_preserve_echo_area (13);
            }
        }
@@ -4486,18 +4480,23 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          while (wait_proc->infd >= 0)
            {
              int nread = read_process_output (proc, wait_proc->infd);
-
-             if (nread == 0)
-               break;
-
-             if (nread > 0)
-               got_some_input = read_some_bytes = 1;
-             else if (nread == -1 && (errno == EIO || errno == EAGAIN))
-               break;
+             if (nread < 0)
+               {
+                 if (errno == EIO || errno == EAGAIN)
+                   break;
 #ifdef EWOULDBLOCK
-             else if (nread == -1 && EWOULDBLOCK == errno)
-               break;
+                 if (errno == EWOULDBLOCK)
+                   break;
 #endif
+               }
+             else
+               {
+                 if (got_some_input < nread)
+                   got_some_input = nread;
+                 if (nread == 0)
+                   break;
+                 read_some_bytes = true;
+               }
            }
          if (read_some_bytes && do_display)
            redisplay_preserve_echo_area (10);
@@ -4528,12 +4527,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          else
            Available = input_wait_mask;
           Writeok = write_mask;
-#ifdef SELECT_CANT_DO_WRITE_MASK
-          check_write = 0;
-#else
-          check_write = 1;
-#endif
-         check_delay = wait_channel >= 0 ? 0 : process_output_delay_count;
+         check_delay = wait_proc ? 0 : process_output_delay_count;
+         check_write = SELECT_CAN_DO_WRITE_MASK;
        }
 
       /* If frame size has changed or the window is newly mapped,
@@ -4559,6 +4554,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
        {
          nfds = read_kbd ? 0 : 1;
          no_avail = 1;
+         FD_ZERO (&Available);
        }
 
       if (!no_avail)
@@ -4568,7 +4564,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          /* Set the timeout for adaptive read buffering if any
             process has non-zero read_output_skip and non-zero
             read_output_delay, and we are not reading output for a
-            specific wait_channel.  It is not executed if
+            specific process.  It is not executed if
             Vprocess_adaptive_read_buffering is nil.  */
          if (process_output_skip && check_delay > 0)
            {
@@ -4599,16 +4595,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 #endif
 
 #if defined (HAVE_NS)
-          nfds = ns_select
+# define SELECT ns_select
 #elif defined (HAVE_GLIB)
-         nfds = xg_select
+# define SELECT xg_select
 #else
-         nfds = pselect
+# define SELECT pselect
 #endif
+          nfds = SELECT
             (max (max_process_desc, max_input_desc) + 1,
              &Available,
              (check_write ? &Writeok : 0),
              NULL, &timeout, NULL);
+#undef SELECT
 
 #ifdef HAVE_GNUTLS
           /* GnuTLS buffers data internally.  In lowat mode it leaves
@@ -4630,12 +4628,13 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                      {
                        struct Lisp_Process *p =
                          XPROCESS (chan_process[channel]);
-                       if (p && p->gnutls_p && p->gnutls_state && p->infd
+                       if (p && p->gnutls_p && p->gnutls_state
                            && ((emacs_gnutls_record_check_pending
                                 (p->gnutls_state))
                                > 0))
                          {
                            nfds++;
+                           eassert (p->infd == channel);
                            FD_SET (p->infd, &Available);
                          }
                      }
@@ -4680,12 +4679,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
            report_file_errno ("Failed select", Qnil, xerrno);
        }
 
-      if (no_avail)
-       {
-         FD_ZERO (&Available);
-         check_write = 0;
-       }
-
       /* Check for keyboard input */
       /* If there is any, return immediately
         to give it higher priority than subprocesses */
@@ -4752,9 +4745,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
        handle_input_available_signal (SIGIO);
 #endif
 
-      if (! wait_proc)
-       got_some_input |= nfds > 0;
-
       /* If checking input just got us a size-change event from X,
         obey it now if we should.  */
       if (read_kbd || ! NILP (wait_for_cell))
@@ -4786,12 +4776,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              /* If waiting for this channel, arrange to return as
                 soon as no more input to be processed.  No more
                 waiting.  */
-             if (wait_channel == channel)
-               {
-                 wait_channel = -1;
-                 nsecs = -1;
-                 got_some_input = 1;
-               }
              proc = chan_process[channel];
              if (NILP (proc))
                continue;
@@ -4807,6 +4791,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                 buffered-ahead character if we have one.  */
 
              nread = read_process_output (proc, channel);
+             if ((!wait_proc || wait_proc == XPROCESS (proc)) && got_some_input < nread)
+               got_some_input = nread;
              if (nread > 0)
                {
                  /* Since read_process_output can run a filter,
@@ -4942,7 +4928,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
        }                       /* End for each file descriptor.  */
     }                          /* End while exit conditions not met.  */
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   /* If calling from keyboard input, do not quit
      since we want to return C-g as an input character.
@@ -5000,7 +4986,7 @@ read_process_output (Lisp_Object proc, register int channel)
   struct coding_system *coding = proc_decode_coding_system[channel];
   int carryover = p->decoding_carryover;
   int readmax = 4096;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object odeactivate;
 
   chars = alloca (carryover + readmax);
@@ -5070,8 +5056,10 @@ read_process_output (Lisp_Object proc, register int channel)
      (including the one in proc_buffered_char[channel]).  */
   if (nbytes <= 0)
     {
-      if (nbytes < 0 || coding->mode & CODING_MODE_LAST_BLOCK)
-       return nbytes;
+      if (nbytes < 0 || coding->mode & CODING_MODE_LAST_BLOCK) {
+        dynwind_end ();
+        return nbytes;
+      }
       coding->mode |= CODING_MODE_LAST_BLOCK;
     }
 
@@ -5089,7 +5077,7 @@ read_process_output (Lisp_Object proc, register int channel)
   /* Handling the process output should not deactivate the mark.  */
   Vdeactivate_mark = odeactivate;
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
   return nbytes;
 }
 
@@ -5827,36 +5815,31 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
       p->tick = ++process_tick;
       if (!nomsg)
        {
-         status_notify (NULL);
+         status_notify (NULL, NULL);
          redisplay_preserve_echo_area (13);
        }
     }
 #endif
 
+#ifdef TIOCSIGSEND
+  /* Work around a HP-UX 7.0 bug that mishandles signals to subjobs.
+     We don't know whether the bug is fixed in later HP-UX versions.  */
+  if (! NILP (current_group) && ioctl (p->infd, TIOCSIGSEND, signo) != -1)
+    return;
+#endif
+
   /* If we don't have process groups, send the signal to the immediate
      subprocess.  That isn't really right, but it's better than any
      obvious alternative.  */
-  if (no_pgrp)
-    {
-      kill (p->pid, signo);
-      return;
-    }
+  pid_t pid = no_pgrp ? gid : - gid;
 
-  /* gid may be a pid, or minus a pgrp's number */
-#ifdef TIOCSIGSEND
-  if (!NILP (current_group))
-    {
-      if (ioctl (p->infd, TIOCSIGSEND, signo) == -1)
-       kill (-gid, signo);
-    }
-  else
-    {
-      gid = - p->pid;
-      kill (gid, signo);
-    }
-#else /* ! defined (TIOCSIGSEND) */
-  kill (-gid, signo);
-#endif /* ! defined (TIOCSIGSEND) */
+  /* Do not kill an already-reaped process, as that could kill an
+     innocent bystander that happens to have the same process ID.  */
+  sigset_t oldset;
+  block_child_signal (&oldset);
+  if (p->alive)
+    kill (pid, signo);
+  unblock_child_signal (&oldset);
 }
 
 DEFUN ("interrupt-process", Finterrupt_process, Sinterrupt_process, 0, 2, 0,
@@ -6281,12 +6264,14 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
 {
   Lisp_Object sentinel, odeactivate;
   struct Lisp_Process *p = XPROCESS (proc);
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   bool outer_running_asynch_code = running_asynch_code;
   int waiting = waiting_for_user_input_p;
 
-  if (inhibit_sentinels)
+  if (inhibit_sentinels) {
+    dynwind_end ();
     return;
+  }
 
   /* No need to gcpro these, because all we do with them later
      is test them for EQness, and none of them should be a string.  */
@@ -6349,20 +6334,26 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
     if (waiting_for_user_input_p == -1)
       record_asynch_buffer_change ();
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 }
 
 /* Report all recent events of a change in process status
    (either run the sentinel or output a message).
    This is usually done while Emacs is waiting for keyboard input
-   but can be done at other times.  */
+   but can be done at other times.
 
-static void
-status_notify (struct Lisp_Process *deleting_process)
+   Return positive if any input was received from WAIT_PROC (or from
+   any process if WAIT_PROC is null), zero if input was attempted but
+   none received, and negative if we didn't even try.  */
+
+static int
+status_notify (struct Lisp_Process *deleting_process,
+              struct Lisp_Process *wait_proc)
 {
-  register Lisp_Object proc;
+  Lisp_Object proc;
   Lisp_Object tail, msg;
   struct gcpro gcpro1, gcpro2;
+  int got_some_input = -1;
 
   tail = Qnil;
   msg = Qnil;
@@ -6392,8 +6383,14 @@ status_notify (struct Lisp_Process *deleting_process)
                 /* Network or serial process not stopped:  */
                 && ! EQ (p->command, Qt)
                 && p->infd >= 0
-                && p != deleting_process
-                && read_process_output (proc, p->infd) > 0);
+                && p != deleting_process)
+           {
+             int nread = read_process_output (proc, p->infd);
+             if (got_some_input < nread)
+               got_some_input = nread;
+             if (nread <= 0)
+               break;
+           }
 
          /* Get the text to use for the message.  */
          if (p->raw_status_new)
@@ -6425,6 +6422,7 @@ status_notify (struct Lisp_Process *deleting_process)
 
   update_mode_lines = 24;  /* In case buffers use %s in mode-line-format.  */
   UNGCPRO;
+  return got_some_input;
 }
 
 DEFUN ("internal-default-process-sentinel", Finternal_default_process_sentinel,
@@ -6636,9 +6634,11 @@ extern int sys_select (int, fd_set *, fd_set *, fd_set *,
    DO_DISPLAY means redisplay should be done to show subprocess
    output that arrives.
 
-   Return true if we received input from any process.  */
+   Return positive if we received input from WAIT_PROC (or from any
+   process if WAIT_PROC is null), zero if we attempted to receive
+   input but got none, and negative if we didn't even try.  */
 
-bool
+int
 wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                             bool do_display,
                             Lisp_Object wait_for_cell,
@@ -6826,7 +6826,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 
   start_polling ();
 
-  return 0;
+  return -1;
 }
 
 #endif /* not subprocesses */
@@ -7065,9 +7065,6 @@ integer or floating point values.
    futz with the SIGCHLD handler, but before Emacs forks any children.
    This function's caller should block SIGCHLD.  */
 
-#ifndef NS_IMPL_GNUSTEP
-static
-#endif
 void
 catch_child_signal (void)
 {
@@ -7203,6 +7200,8 @@ init_process_emacs (void)
 void
 syms_of_process (void)
 {
+#include "process.x"
+
 #ifdef subprocesses
 
   DEFSYM (Qprocessp, "processp");
@@ -7337,67 +7336,5 @@ non-nil value means that the delay is not reset on write.
 The variable takes effect when `start-process' is called.  */);
   Vprocess_adaptive_read_buffering = Qt;
 #endif
-
-  defsubr (&Sprocessp);
-  defsubr (&Sget_process);
-  defsubr (&Sdelete_process);
-  defsubr (&Sprocess_status);
-  defsubr (&Sprocess_exit_status);
-  defsubr (&Sprocess_id);
-  defsubr (&Sprocess_name);
-  defsubr (&Sprocess_tty_name);
-  defsubr (&Sprocess_command);
-  defsubr (&Sset_process_buffer);
-  defsubr (&Sprocess_buffer);
-  defsubr (&Sprocess_mark);
-  defsubr (&Sset_process_filter);
-  defsubr (&Sprocess_filter);
-  defsubr (&Sset_process_sentinel);
-  defsubr (&Sprocess_sentinel);
-  defsubr (&Sset_process_window_size);
-  defsubr (&Sset_process_inherit_coding_system_flag);
-  defsubr (&Sset_process_query_on_exit_flag);
-  defsubr (&Sprocess_query_on_exit_flag);
-  defsubr (&Sprocess_contact);
-  defsubr (&Sprocess_plist);
-  defsubr (&Sset_process_plist);
-  defsubr (&Sprocess_list);
-  defsubr (&Sstart_process);
-  defsubr (&Sserial_process_configure);
-  defsubr (&Smake_serial_process);
-  defsubr (&Sset_network_process_option);
-  defsubr (&Smake_network_process);
-  defsubr (&Sformat_network_address);
-  defsubr (&Snetwork_interface_list);
-  defsubr (&Snetwork_interface_info);
-#ifdef DATAGRAM_SOCKETS
-  defsubr (&Sprocess_datagram_address);
-  defsubr (&Sset_process_datagram_address);
-#endif
-  defsubr (&Saccept_process_output);
-  defsubr (&Sprocess_send_region);
-  defsubr (&Sprocess_send_string);
-  defsubr (&Sinterrupt_process);
-  defsubr (&Skill_process);
-  defsubr (&Squit_process);
-  defsubr (&Sstop_process);
-  defsubr (&Scontinue_process);
-  defsubr (&Sprocess_running_child_p);
-  defsubr (&Sprocess_send_eof);
-  defsubr (&Ssignal_process);
-  defsubr (&Swaiting_for_user_input_p);
-  defsubr (&Sprocess_type);
-  defsubr (&Sinternal_default_process_sentinel);
-  defsubr (&Sinternal_default_process_filter);
-  defsubr (&Sset_process_coding_system);
-  defsubr (&Sprocess_coding_system);
-  defsubr (&Sset_process_filter_multibyte);
-  defsubr (&Sprocess_filter_multibyte_p);
-
 #endif /* subprocesses */
-
-  defsubr (&Sget_buffer_process);
-  defsubr (&Sprocess_inherit_coding_system_flag);
-  defsubr (&Slist_system_processes);
-  defsubr (&Sprocess_attributes);
 }