]> code.delx.au - gnu-emacs/blobdiff - src/process.c
Merge from emacs-24; up to 2014-07-27T09:41:59Z!ttn@gnu.org
[gnu-emacs] / src / process.c
index 5a5ce0ce67481ead74352126e93b5e6e56c3521f..06fc918cf54c1dd946b79526c7c90a7ad3fc7699 100644 (file)
@@ -134,6 +134,29 @@ extern int sys_select (int, fd_set *, fd_set *, fd_set *,
                       struct timespec *, void *);
 #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.  */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+# pragma GCC diagnostic ignored "-Wstrict-overflow"
+#endif
+
+Lisp_Object Qeuid, Qegid, Qcomm, Qstate, Qppid, Qpgrp, Qsess, Qttname, Qtpgid;
+Lisp_Object Qminflt, Qmajflt, Qcminflt, Qcmajflt, Qutime, Qstime, Qcstime;
+Lisp_Object Qcutime, Qpri, Qnice, Qthcount, Qstart, Qvsize, Qrss, Qargs;
+Lisp_Object Quser, Qgroup, Qetime, Qpcpu, Qpmem, Qtime, Qctime;
+Lisp_Object QCname, QCtype;
+\f
+/* True if keyboard input is on hold, zero otherwise.  */
+
+static bool kbd_is_on_hold;
+
+/* Nonzero means don't run process sentinels.  This is used
+   when exiting.  */
+bool inhibit_sentinels;
+
+#ifdef subprocesses
+
 #ifndef SOCK_CLOEXEC
 # define SOCK_CLOEXEC 0
 #endif
@@ -150,6 +173,9 @@ close_on_exec (int fd)
   return fd;
 }
 
+# undef accept4
+# define accept4(sockfd, addr, addrlen, flags) \
+    process_accept4 (sockfd, addr, addrlen, flags)
 static int
 accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
 {
@@ -165,29 +191,6 @@ process_socket (int domain, int type, int protocol)
 # define socket(domain, type, protocol) process_socket (domain, type, protocol)
 #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.  */
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
-# pragma GCC diagnostic ignored "-Wstrict-overflow"
-#endif
-
-Lisp_Object Qeuid, Qegid, Qcomm, Qstate, Qppid, Qpgrp, Qsess, Qttname, Qtpgid;
-Lisp_Object Qminflt, Qmajflt, Qcminflt, Qcmajflt, Qutime, Qstime, Qcstime;
-Lisp_Object Qcutime, Qpri, Qnice, Qthcount, Qstart, Qvsize, Qrss, Qargs;
-Lisp_Object Quser, Qgroup, Qetime, Qpcpu, Qpmem, Qtime, Qctime;
-Lisp_Object QCname, QCtype;
-\f
-/* True if keyboard input is on hold, zero otherwise.  */
-
-static bool kbd_is_on_hold;
-
-/* Nonzero means don't run process sentinels.  This is used
-   when exiting.  */
-bool inhibit_sentinels;
-
-#ifdef subprocesses
-
 Lisp_Object Qprocessp;
 static Lisp_Object Qrun, Qstop, Qsignal;
 static Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten;
@@ -224,8 +227,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 +285,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 +466,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 +478,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 +494,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 +524,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)
@@ -605,7 +599,7 @@ status_message (struct Lisp_Process *p)
   Lisp_Object symbol;
   int code;
   bool coredump;
-  Lisp_Object string, string2;
+  Lisp_Object string;
 
   decode_status (status, &symbol, &code, &coredump);
 
@@ -629,8 +623,8 @@ status_message (struct Lisp_Process *p)
          if (c1 != c2)
            Faset (string, make_number (0), make_number (c2));
        }
-      string2 = build_string (coredump ? " (core dumped)\n" : "\n");
-      return concat2 (string, string2);
+      AUTO_STRING (suffix, coredump ? " (core dumped)\n" : "\n");
+      return concat2 (string, suffix);
     }
   else if (EQ (symbol, Qexit))
     {
@@ -638,17 +632,17 @@ status_message (struct Lisp_Process *p)
        return build_string (code == 0 ? "deleted\n" : "connection broken by remote peer\n");
       if (code == 0)
        return build_string ("finished\n");
+      AUTO_STRING (prefix, "exited abnormally with code ");
       string = Fnumber_to_string (make_number (code));
-      string2 = build_string (coredump ? " (core dumped)\n" : "\n");
-      return concat3 (build_string ("exited abnormally with code "),
-                     string, string2);
+      AUTO_STRING (suffix, coredump ? " (core dumped)\n" : "\n");
+      return concat3 (prefix, string, suffix);
     }
   else if (EQ (symbol, Qfailed))
     {
+      AUTO_STRING (prefix, "failed with code ");
       string = Fnumber_to_string (make_number (code));
-      string2 = build_string ("\n");
-      return concat3 (build_string ("failed with code "),
-                     string, string2);
+      AUTO_STRING (suffix, "\n");
+      return concat3 (prefix, string, suffix);
     }
   else
     return Fcopy_sequence (Fsymbol_name (symbol));
@@ -870,7 +864,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 +884,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);
        }
     }
@@ -1311,30 +1305,34 @@ Returns nil if format of ADDRESS is invalid.  */)
       ptrdiff_t size = p->header.size;
       Lisp_Object args[10];
       int nargs, i;
+      char const *format;
 
       if (size == 4 || (size == 5 && !NILP (omit_port)))
        {
-         args[0] = build_string ("%d.%d.%d.%d");
+         format = "%d.%d.%d.%d";
          nargs = 4;
        }
       else if (size == 5)
        {
-         args[0] = build_string ("%d.%d.%d.%d:%d");
+         format = "%d.%d.%d.%d:%d";
          nargs = 5;
        }
       else if (size == 8 || (size == 9 && !NILP (omit_port)))
        {
-         args[0] = build_string ("%x:%x:%x:%x:%x:%x:%x:%x");
+         format = "%x:%x:%x:%x:%x:%x:%x:%x";
          nargs = 8;
        }
       else if (size == 9)
        {
-         args[0] = build_string ("[%x:%x:%x:%x:%x:%x:%x:%x]:%d");
+         format = "[%x:%x:%x:%x:%x:%x:%x:%x]:%d";
          nargs = 9;
        }
       else
        return Qnil;
 
+      AUTO_STRING (format_obj, format);
+      args[0] = format_obj;
+
       for (i = 0; i < nargs; i++)
        {
          if (! RANGED_INTEGERP (0, p->contents[i], 65535))
@@ -1348,15 +1346,13 @@ Returns nil if format of ADDRESS is invalid.  */)
          args[i+1] = p->contents[i];
        }
 
-      return Fformat (nargs+1, args);
+      return Fformat (nargs + 1, args);
     }
 
   if (CONSP (address))
     {
-      Lisp_Object args[2];
-      args[0] = build_string ("<Family %d>");
-      args[1] = Fcar (address);
-      return Fformat (2, args);
+      AUTO_STRING (format, "<Family %d>");
+      return Fformat (2, (Lisp_Object []) {format, Fcar (address)});
     }
 
   return Qnil;
@@ -1395,9 +1391,10 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object buffer, name, program, proc, current_dir, tem;
-  register unsigned char **new_argv;
+  unsigned char **new_argv;
   ptrdiff_t i;
   ptrdiff_t count = SPECPDL_INDEX ();
+  USE_SAFE_ALLOCA;
 
   buffer = args[1];
   if (!NILP (buffer))
@@ -1473,7 +1470,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
     val = Vcoding_system_for_read;
     if (NILP (val))
       {
-       args2 = alloca ((nargs + 1) * sizeof *args2);
+       SAFE_ALLOCA_LISP (args2, nargs + 1);
        args2[0] = Qstart_process;
        for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
        GCPRO2 (proc, current_dir);
@@ -1492,7 +1489,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
       {
        if (EQ (coding_systems, Qt))
          {
-           args2 = alloca ((nargs + 1) * sizeof *args2);
+           SAFE_ALLOCA_LISP (args2, nargs + 1);
            args2[0] = Qstart_process;
            for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
            GCPRO2 (proc, current_dir);
@@ -1587,7 +1584,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
 
       /* Now that everything is encoded we can collect the strings into
         NEW_ARGV.  */
-      new_argv = alloca ((nargs - 1) * sizeof *new_argv);
+      SAFE_NALLOCA (new_argv, 1, nargs - 1);
       new_argv[nargs - 2] = 0;
 
       for (i = nargs - 2; i-- != 0; )
@@ -1601,6 +1598,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
   else
     create_pty (proc);
 
+  SAFE_FREE ();
   return unbind_to (count, proc);
 }
 
@@ -1967,9 +1965,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)
 {
@@ -2083,8 +2078,10 @@ get_lisp_to_sockaddr_size (Lisp_Object address, int *familyp)
           && VECTORP (XCDR (address)))
     {
       struct sockaddr *sa;
-      *familyp = XINT (XCAR (address));
       p = XVECTOR (XCDR (address));
+      if (MAX_ALLOCA - sizeof sa->sa_family < p->header.size)
+       return 0;
+      *familyp = XINT (XCAR (address));
       return p->header.size + sizeof (sa->sa_family);
     }
   return 0;
@@ -2856,7 +2853,7 @@ usage: (make-network-process &rest ARGS)  */)
   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;
@@ -2904,8 +2901,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 +2929,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;
@@ -3001,7 +2998,7 @@ usage: (make-network-process &rest ARGS)  */)
       address_un.sun_family = AF_LOCAL;
       if (sizeof address_un.sun_path <= SBYTES (service))
        error ("Service name too long");
-      strcpy (address_un.sun_path, SSDATA (service));
+      lispstpcpy (address_un.sun_path, service);
       ai.ai_addr = (struct sockaddr *) &address_un;
       ai.ai_addrlen = sizeof address_un;
       goto open_socket;
@@ -3319,7 +3316,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)
@@ -3692,7 +3689,7 @@ network_interface_info (Lisp_Object ifname)
 
   if (sizeof rq.ifr_name <= SBYTES (ifname))
     error ("interface name too long");
-  strcpy (rq.ifr_name, SSDATA (ifname));
+  lispstpcpy (rq.ifr_name, ifname);
 
   s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
@@ -3934,19 +3931,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 +3996,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.  */
@@ -4067,20 +4066,15 @@ server_accept_connection (Lisp_Object server, int channel)
     {
     case AF_INET:
       {
-       Lisp_Object args[5];
        unsigned char *ip = (unsigned char *)&saddr.in.sin_addr.s_addr;
-       args[0] = build_string ("%d.%d.%d.%d");
-       args[1] = make_number (*ip++);
-       args[2] = make_number (*ip++);
-       args[3] = make_number (*ip++);
-       args[4] = make_number (*ip++);
-       host = Fformat (5, args);
-       service = make_number (ntohs (saddr.in.sin_port));
 
-       args[0] = build_string (" <%s:%d>");
-       args[1] = host;
-       args[2] = service;
-       caller = Fformat (3, args);
+       AUTO_STRING (ipv4_format, "%d.%d.%d.%d");
+       host = Fformat (5, ((Lisp_Object [])
+         { ipv4_format, make_number (ip[0]),
+           make_number (ip[1]), make_number (ip[2]), make_number (ip[3]) }));
+       service = make_number (ntohs (saddr.in.sin_port));
+       AUTO_STRING (caller_format, " <%s:%d>");
+       caller = Fformat (3, (Lisp_Object []) {caller_format, host, service});
       }
       break;
 
@@ -4090,16 +4084,15 @@ server_accept_connection (Lisp_Object server, int channel)
        Lisp_Object args[9];
        uint16_t *ip6 = (uint16_t *)&saddr.in6.sin6_addr;
        int i;
-       args[0] = build_string ("%x:%x:%x:%x:%x:%x:%x:%x");
+
+       AUTO_STRING (ipv6_format, "%x:%x:%x:%x:%x:%x:%x:%x");
+       args[0] = ipv6_format;
        for (i = 0; i < 8; i++)
-         args[i+1] = make_number (ntohs (ip6[i]));
+         args[i + 1] = make_number (ntohs (ip6[i]));
        host = Fformat (9, args);
        service = make_number (ntohs (saddr.in.sin_port));
-
-       args[0] = build_string (" <[%s]:%d>");
-       args[1] = host;
-       args[2] = service;
-       caller = Fformat (3, args);
+       AUTO_STRING (caller_format, " <[%s]:%d>");
+       caller = Fformat (3, (Lisp_Object []) {caller_format, host, service});
       }
       break;
 #endif
@@ -4109,7 +4102,9 @@ server_accept_connection (Lisp_Object server, int channel)
 #endif
     default:
       caller = Fnumber_to_string (make_number (connect_counter));
-      caller = concat3 (build_string (" <"), caller, build_string (">"));
+      AUTO_STRING (space_less_than, " <");
+      AUTO_STRING (greater_than, ">");
+      caller = concat3 (space_less_than, caller, greater_than);
       break;
     }
 
@@ -4206,16 +4201,18 @@ server_accept_connection (Lisp_Object server, int channel)
   p->inherit_coding_system_flag
     = (NILP (buffer) ? 0 : ps->inherit_coding_system_flag);
 
+  AUTO_STRING (dash, "-");
+  AUTO_STRING (nl, "\n");
+  Lisp_Object host_string = STRINGP (host) ? host : dash;
+
   if (!NILP (ps->log))
-      call3 (ps->log, server, proc,
-            concat3 (build_string ("accept from "),
-                     (STRINGP (host) ? host : build_string ("-")),
-                     build_string ("\n")));
+    {
+      AUTO_STRING (accept_from, "accept from ");
+      call3 (ps->log, server, proc, concat3 (accept_from, host_string, nl));
+    }
 
-  exec_sentinel (proc,
-                concat3 (build_string ("open from "),
-                         (STRINGP (host) ? host : build_string ("-")),
-                         build_string ("\n")));
+  AUTO_STRING (open_from, "open from ");
+  exec_sentinel (proc, concat3 (open_from, host_string, nl));
 }
 
 /* This variable is different from waiting_for_input in keyboard.c.
@@ -4268,18 +4265,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,8 +4290,7 @@ 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;
+  int got_some_input = -1;
   ptrdiff_t count = SPECPDL_INDEX ();
 
   FD_ZERO (&Available);
@@ -4306,10 +4301,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 +4337,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 +4459,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);
            }
        }
@@ -4474,6 +4469,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       if (wait_proc && wait_proc->raw_status_new)
        update_status (wait_proc);
       if (wait_proc
+         && wait_proc->infd >= 0
          && ! EQ (wait_proc->status, Qrun)
          && ! EQ (wait_proc->status, Qconnect))
        {
@@ -4483,21 +4479,26 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          XSETPROCESS (proc, wait_proc);
 
          /* Read data from the process, until we exhaust it.  */
-         while (wait_proc->infd >= 0)
+         while (true)
            {
              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 +4529,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 +4556,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 +4566,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)
            {
@@ -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);
                          }
                      }
@@ -4651,6 +4650,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                          > 0))
                    {
                      nfds = 1;
+                     eassert (0 <= wait_proc->infd);
                      /* Set to Available.  */
                      FD_SET (wait_proc->infd, &Available);
                    }
@@ -4680,12 +4680,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 +4746,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 +4777,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 +4792,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,
@@ -4931,7 +4918,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                     status_notify to do it later, it will read input
                     from the process before calling the sentinel.  */
                  exec_sentinel (proc, build_string ("open\n"));
-                 if (!EQ (p->filter, Qt) && !EQ (p->command, Qt))
+                 if (0 <= p->infd && !EQ (p->filter, Qt)
+                     && !EQ (p->command, Qt))
                    {
                      FD_SET (p->infd, &input_wait_mask);
                      FD_SET (p->infd, &non_keyboard_wait_mask);
@@ -4992,18 +4980,17 @@ read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars,
    for decoding.  */
 
 static int
-read_process_output (Lisp_Object proc, register int channel)
+read_process_output (Lisp_Object proc, int channel)
 {
-  register ssize_t nbytes;
-  char *chars;
-  register struct Lisp_Process *p = XPROCESS (proc);
+  ssize_t nbytes;
+  struct Lisp_Process *p = XPROCESS (proc);
   struct coding_system *coding = proc_decode_coding_system[channel];
   int carryover = p->decoding_carryover;
-  int readmax = 4096;
+  enum { readmax = 4096 };
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object odeactivate;
+  char chars[sizeof coding->carryover + readmax];
 
-  chars = alloca (carryover + readmax);
   if (carryover)
     /* See the comment above.  */
     memcpy (chars, SDATA (p->decoding_buf), carryover);
@@ -5153,7 +5140,7 @@ read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars,
         proc_encode_coding_system[p->outfd] surely points to a
         valid memory because p->outfd will be changed once EOF is
         sent to the process.  */
-      if (NILP (p->encode_coding_system)
+      if (NILP (p->encode_coding_system) && p->outfd >= 0
          && proc_encode_coding_system[p->outfd])
        {
          pset_encode_coding_system
@@ -5827,36 +5814,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,
@@ -6098,8 +6080,8 @@ process has been transmitted to the serial port.  */)
         for communication with the subprocess, call shutdown to cause EOF.
         (In some old system, shutdown to socketpair doesn't work.
         Then we just can't win.)  */
-      if (EQ (p->type, Qnetwork)
-         || p->infd == old_outfd)
+      if (0 <= old_outfd
+         && (EQ (p->type, Qnetwork) || p->infd == old_outfd))
        shutdown (old_outfd, 1);
 #endif
       close_process_fd (&p->open_fd[WRITE_TO_SUBPROCESS]);
@@ -6355,14 +6337,20 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
 /* 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 +6380,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 +6419,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,
@@ -6560,6 +6555,8 @@ DEFUN ("process-filter-multibyte-p", Fprocess_filter_multibyte_p,
 
   CHECK_PROCESS (process);
   p = XPROCESS (process);
+  if (p->infd < 0)
+    return Qnil;
   coding = proc_decode_coding_system[p->infd];
   return (CODING_FOR_UNIBYTE (coding) ? Qnil : Qt);
 }
@@ -6604,7 +6601,7 @@ keyboard_bit_set (fd_set *mask)
 
 #else  /* not subprocesses */
 
-/* Defined on msdos.c.  */
+/* Defined in msdos.c.  */
 extern int sys_select (int, fd_set *, fd_set *, fd_set *,
                       struct timespec *, void *);
 
@@ -6636,9 +6633,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 +6825,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 
   start_polling ();
 
-  return 0;
+  return -1;
 }
 
 #endif /* not subprocesses */
@@ -6834,6 +6833,26 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 /* The following functions are needed even if async subprocesses are
    not supported.  Some of them are no-op stubs in that case.  */
 
+#ifdef HAVE_TIMERFD
+
+/* Add FD, which is a descriptor returned by timerfd_create,
+   to the set of non-keyboard input descriptors.  */
+
+void
+add_timer_wait_descriptor (int fd)
+{
+  FD_SET (fd, &input_wait_mask);
+  FD_SET (fd, &non_keyboard_wait_mask);
+  FD_SET (fd, &non_process_wait_mask);
+  fd_callback_info[fd].func = timerfd_callback;
+  fd_callback_info[fd].data = NULL;
+  fd_callback_info[fd].condition |= FOR_READ;
+  if (fd > max_input_desc)
+    max_input_desc = fd;
+}
+
+#endif /* HAVE_TIMERFD */
+
 /* Add DESC to the set of keyboard input descriptors.  */
 
 void
@@ -7059,14 +7078,12 @@ integer or floating point values.
   return system_process_attributes (pid);
 }
 
+#ifdef subprocesses
 /* Arrange to catch SIGCHLD if this hasn't already been arranged.
    Invoke this after init_process_emacs, and after glib and/or GNUstep
    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)
 {
@@ -7084,6 +7101,7 @@ catch_child_signal (void)
         : old_action.sa_handler);
   unblock_child_signal (&oldset);
 }
+#endif /* subprocesses */
 
 \f
 /* This is not called "init_process" because that is the name of a
@@ -7290,10 +7308,12 @@ syms_of_process (void)
   DEFSYM (Qcutime, "cutime");
   DEFSYM (Qcstime, "cstime");
   DEFSYM (Qctime, "ctime");
+#ifdef subprocesses
   DEFSYM (Qinternal_default_process_sentinel,
          "internal-default-process-sentinel");
   DEFSYM (Qinternal_default_process_filter,
          "internal-default-process-filter");
+#endif
   DEFSYM (Qpri, "pri");
   DEFSYM (Qnice, "nice");
   DEFSYM (Qthcount, "thcount");