Another merge from trunk.
[bpt/emacs.git] / src / process.c
index bdab1f8..7050bf9 100644 (file)
@@ -1,7 +1,7 @@
 /* Asynchronous subprocess control for GNU Emacs.
 
-Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2013 Free Software
-Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2013
+  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,8 +21,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
-#define PROCESS_INLINE EXTERN_INLINE
-
 #include <stdio.h>
 #include <errno.h>
 #include <sys/types.h>         /* Some typedefs are used in sys/file.h.  */
@@ -92,6 +90,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <c-ctype.h>
 #include <sig2str.h>
+#include <verify.h>
 
 #endif /* subprocesses */
 
@@ -131,8 +130,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 
 #ifdef WINDOWSNT
-extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
-                      EMACS_TIME *, void *);
+extern int sys_select (int, fd_set *, fd_set *, fd_set *,
+                      struct timespec *, void *);
 #endif
 
 #ifndef SOCK_CLOEXEC
@@ -260,7 +259,7 @@ static EMACS_INT update_tick;
 #endif
 
 #ifdef ADAPTIVE_READ_BUFFERING
-#define READ_OUTPUT_DELAY_INCREMENT (EMACS_TIME_RESOLUTION / 100)
+#define READ_OUTPUT_DELAY_INCREMENT (TIMESPEC_RESOLUTION / 100)
 #define READ_OUTPUT_DELAY_MAX       (READ_OUTPUT_DELAY_INCREMENT * 5)
 #define READ_OUTPUT_DELAY_MAX_MAX   (READ_OUTPUT_DELAY_INCREMENT * 7)
 
@@ -279,7 +278,7 @@ static bool process_output_skip;
 
 static void create_process (Lisp_Object, char **, Lisp_Object);
 #ifdef USABLE_SIGIO
-static bool keyboard_bit_set (SELECT_TYPE *);
+static bool keyboard_bit_set (fd_set *);
 #endif
 static void deactivate_process (Lisp_Object);
 static void status_notify (struct Lisp_Process *);
@@ -298,39 +297,39 @@ static void exec_sentinel (Lisp_Object proc, Lisp_Object reason);
 
 /* Mask of bits indicating the descriptors that we wait for input on.  */
 
-static SELECT_TYPE input_wait_mask;
+static fd_set input_wait_mask;
 
 /* Mask that excludes keyboard input descriptor(s).  */
 
-static SELECT_TYPE non_keyboard_wait_mask;
+static fd_set non_keyboard_wait_mask;
 
 /* Mask that excludes process input descriptor(s).  */
 
-static SELECT_TYPE non_process_wait_mask;
+static fd_set non_process_wait_mask;
 
 /* Mask for selecting for write.  */
 
-static SELECT_TYPE write_mask;
+static fd_set write_mask;
 
 #ifdef NON_BLOCKING_CONNECT
 /* Mask of bits indicating the descriptors that we wait for connect to
    complete on.  Once they complete, they are removed from this mask
    and added to the input_wait_mask and non_keyboard_wait_mask.  */
 
-static SELECT_TYPE connect_wait_mask;
+static fd_set connect_wait_mask;
 
 /* Number of bits set in connect_wait_mask.  */
 static int num_pending_connects;
 #endif /* NON_BLOCKING_CONNECT */
 
-/* The largest descriptor currently in use for a process object.  */
+/* The largest descriptor currently in use for a process object; -1 if none.  */
 static int max_process_desc;
 
-/* The largest descriptor currently in use for input.  */
+/* The largest descriptor currently in use for input; -1 if none.  */
 static int max_input_desc;
 
 /* Indexed by descriptor, gives the process (if any) for that descriptor */
-static Lisp_Object chan_process[MAXDESC];
+static Lisp_Object chan_process[FD_SETSIZE];
 
 /* Alist of elements (NAME . PROCESS) */
 static Lisp_Object Vprocess_alist;
@@ -341,18 +340,18 @@ static Lisp_Object Vprocess_alist;
    output from the process is to read at least one char.
    Always -1 on systems that support FIONREAD.  */
 
-static int proc_buffered_char[MAXDESC];
+static int proc_buffered_char[FD_SETSIZE];
 
 /* Table of `struct coding-system' for each process.  */
-static struct coding_system *proc_decode_coding_system[MAXDESC];
-static struct coding_system *proc_encode_coding_system[MAXDESC];
+static struct coding_system *proc_decode_coding_system[FD_SETSIZE];
+static struct coding_system *proc_encode_coding_system[FD_SETSIZE];
 
 #ifdef DATAGRAM_SOCKETS
 /* Table of `partner address' for datagram sockets.  */
 static struct sockaddr_and_len {
   struct sockaddr *sa;
   int len;
-} datagram_address[MAXDESC];
+} datagram_address[FD_SETSIZE];
 #define DATAGRAM_CHAN_P(chan)  (datagram_address[chan].sa != 0)
 #define DATAGRAM_CONN_P(proc)  (PROCESSP (proc) && datagram_address[XPROCESS (proc)->infd].sa != 0)
 #else
@@ -360,6 +359,12 @@ static struct sockaddr_and_len {
 #define DATAGRAM_CONN_P(proc)  (0)
 #endif
 
+/* FOR_EACH_PROCESS (LIST_VAR, PROC_VAR) followed by a statement is
+   a `for' loop which iterates over processes from Vprocess_alist.  */
+
+#define FOR_EACH_PROCESS(list_var, proc_var)                   \
+  FOR_EACH_ALIST_VALUE (Vprocess_alist, list_var, proc_var)
+
 /* These setters are used only in this file, so they can be private.  */
 static void
 pset_buffer (struct Lisp_Process *p, Lisp_Object val)
@@ -451,7 +456,7 @@ static struct fd_callback_data
 #define FOR_READ  1
 #define FOR_WRITE 2
   int condition; /* mask of the defines above.  */
-} fd_callback_info[MAXDESC];
+} fd_callback_info[FD_SETSIZE];
 
 
 /* Add a file descriptor FD to be monitored for when read is possible.
@@ -460,7 +465,7 @@ static struct fd_callback_data
 void
 add_read_fd (int fd, fd_callback func, void *data)
 {
-  eassert (fd < MAXDESC);
+  eassert (fd < FD_SETSIZE);
   add_keyboard_wait_descriptor (fd);
 
   fd_callback_info[fd].func = func;
@@ -473,7 +478,7 @@ add_read_fd (int fd, fd_callback func, void *data)
 void
 delete_read_fd (int fd)
 {
-  eassert (fd < MAXDESC);
+  eassert (fd < FD_SETSIZE);
   delete_keyboard_wait_descriptor (fd);
 
   fd_callback_info[fd].condition &= ~FOR_READ;
@@ -490,7 +495,7 @@ delete_read_fd (int fd)
 void
 add_write_fd (int fd, fd_callback func, void *data)
 {
-  eassert (fd < MAXDESC);
+  eassert (fd < FD_SETSIZE);
   FD_SET (fd, &write_mask);
   if (fd > max_input_desc)
     max_input_desc = fd;
@@ -500,29 +505,35 @@ add_write_fd (int fd, fd_callback func, void *data)
   fd_callback_info[fd].condition |= FOR_WRITE;
 }
 
+/* FD is no longer an input descriptor; update max_input_desc accordingly.  */
+
+static void
+delete_input_desc (int fd)
+{
+  if (fd == max_input_desc)
+    {
+      do
+       fd--;
+      while (0 <= fd && ! (FD_ISSET (fd, &input_wait_mask)
+                          || FD_ISSET (fd, &write_mask)));
+
+      max_input_desc = fd;
+    }
+}
+
 /* Stop monitoring file descriptor FD for when write is possible.  */
 
 void
 delete_write_fd (int fd)
 {
-  int lim = max_input_desc;
-
-  eassert (fd < MAXDESC);
+  eassert (fd < FD_SETSIZE);
   FD_CLR (fd, &write_mask);
   fd_callback_info[fd].condition &= ~FOR_WRITE;
   if (fd_callback_info[fd].condition == 0)
     {
       fd_callback_info[fd].func = 0;
       fd_callback_info[fd].data = 0;
-
-      if (fd == max_input_desc)
-        for (fd = lim; fd >= 0; fd--)
-          if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
-            {
-              max_input_desc = fd;
-              break;
-            }
-
+      delete_input_desc (fd);
     }
 }
 
@@ -640,19 +651,16 @@ status_message (struct Lisp_Process *p)
     return Fcopy_sequence (Fsymbol_name (symbol));
 }
 \f
-#ifdef HAVE_PTYS
-
-/* The file name of the pty opened by allocate_pty.  */
-static char pty_name[24];
+enum { PTY_NAME_SIZE = 24 };
 
 /* Open an available pty, returning a file descriptor.
-   Return -1 on failure.
-   The file name of the terminal corresponding to the pty
-   is left in the variable pty_name.  */
+   Store into PTY_NAME the file name of the terminal corresponding to the pty.
+   Return -1 on failure.  */
 
 static int
-allocate_pty (void)
+allocate_pty (char pty_name[PTY_NAME_SIZE])
 {
+#ifdef HAVE_PTYS
   int fd;
 
 #ifdef PTY_ITERATION
@@ -677,6 +685,15 @@ allocate_pty (void)
 
        if (fd >= 0)
          {
+#ifdef PTY_OPEN
+           /* Set FD's close-on-exec flag.  This is needed even if
+              PT_OPEN calls posix_openpt with O_CLOEXEC, since POSIX
+              doesn't require support for that combination.
+              Multithreaded platforms where posix_openpt ignores
+              O_CLOEXEC (or where PTY_OPEN doesn't call posix_openpt)
+              have a race condition between the PTY_OPEN and here.  */
+           fcntl (fd, F_SETFD, FD_CLOEXEC);
+#endif
            /* check to make certain that both sides are available
               this avoids a nasty yet stupid bug in rlogins */
 #ifdef PTY_TTY_NAME_SPRINTF
@@ -697,9 +714,9 @@ allocate_pty (void)
            return fd;
          }
       }
+#endif /* HAVE_PTYS */
   return -1;
 }
-#endif /* HAVE_PTYS */
 \f
 static Lisp_Object
 make_process (Lisp_Object name)
@@ -719,6 +736,8 @@ make_process (Lisp_Object name)
      non-Lisp data, so do it only for slots which should not be zero.  */
   p->infd = -1;
   p->outfd = -1;
+  for (i = 0; i < PROCESS_OPEN_FDS; i++)
+    p->open_fd[i] = -1;
 
 #ifdef HAVE_GNUTLS
   p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
@@ -793,13 +812,14 @@ get_process (register Lisp_Object name)
   else
     obj = name;
 
-  /* Now obj should be either a buffer object or a process object.
-   */
+  /* Now obj should be either a buffer object or a process object.  */
   if (BUFFERP (obj))
     {
+      if (NILP (BVAR (XBUFFER (obj), name)))
+        error ("Attempt to get process for a dead buffer");
       proc = Fget_buffer_process (obj);
       if (NILP (proc))
-       error ("Buffer %s has no process", SDATA (BVAR (XBUFFER (obj), name)));
+        error ("Buffer %s has no process", SDATA (BVAR (XBUFFER (obj), name)));
     }
   else
     {
@@ -815,13 +835,17 @@ get_process (register Lisp_Object name)
    treated by the SIGCHLD handler and waitpid has been invoked on them;
    otherwise they might fill up the kernel's process table.
 
-   Some processes created by call-process are also put onto this list.  */
+   Some processes created by call-process are also put onto this list.
+
+   Members of this list are (process-ID . filename) pairs.  The
+   process-ID is a number; the filename, if a string, is a file that
+   needs to be removed after the process exits.  */
 static Lisp_Object deleted_pid_list;
 
 void
-record_deleted_pid (pid_t pid)
+record_deleted_pid (pid_t pid, Lisp_Object filename)
 {
-  deleted_pid_list = Fcons (make_fixnum_or_float (pid),
+  deleted_pid_list = Fcons (Fcons (make_fixnum_or_float (pid), filename),
                            /* GC treated elements set to nil.  */
                            Fdelq (Qnil, deleted_pid_list));
 
@@ -841,7 +865,7 @@ nil, indicating the current buffer's process.  */)
   p->raw_status_new = 0;
   if (NETCONN1_P (p) || SERIALCONN1_P (p))
     {
-      pset_status (p, Fcons (Qexit, Fcons (make_number (0), Qnil)));
+      pset_status (p, list2 (Qexit, make_number (0)));
       p->tick = ++process_tick;
       status_notify (p);
       redisplay_preserve_echo_area (13);
@@ -849,7 +873,7 @@ nil, indicating the current buffer's process.  */)
   else
     {
       if (p->alive)
-       record_kill_process (p);
+       record_kill_process (p, Qnil);
 
       if (p->infd >= 0)
        {
@@ -1115,15 +1139,18 @@ See `set-process-sentinel' for more info on sentinels.  */)
 DEFUN ("set-process-window-size", Fset_process_window_size,
        Sset_process_window_size, 3, 3, 0,
        doc: /* Tell PROCESS that it has logical window size HEIGHT and WIDTH.  */)
-  (register Lisp_Object process, Lisp_Object height, Lisp_Object width)
+  (Lisp_Object process, Lisp_Object height, Lisp_Object width)
 {
   CHECK_PROCESS (process);
-  CHECK_RANGED_INTEGER (height, 0, INT_MAX);
-  CHECK_RANGED_INTEGER (width, 0, INT_MAX);
+
+  /* All known platforms store window sizes as 'unsigned short'.  */
+  CHECK_RANGED_INTEGER (height, 0, USHRT_MAX);
+  CHECK_RANGED_INTEGER (width, 0, USHRT_MAX);
 
   if (XPROCESS (process)->infd < 0
-      || set_window_size (XPROCESS (process)->infd,
-                         XINT (height), XINT (width)) <= 0)
+      || (set_window_size (XPROCESS (process)->infd,
+                          XINT (height), XINT (width))
+         < 0))
     return Qnil;
   else
     return Qt;
@@ -1206,11 +1233,11 @@ list of keywords.  */)
   if ((!NETCONN_P (process) && !SERIALCONN_P (process)) || EQ (key, Qt))
     return contact;
   if (NILP (key) && NETCONN_P (process))
-    return Fcons (Fplist_get (contact, QChost),
-                 Fcons (Fplist_get (contact, QCservice), Qnil));
+    return list2 (Fplist_get (contact, QChost),
+                 Fplist_get (contact, QCservice));
   if (NILP (key) && SERIALCONN_P (process))
-    return Fcons (Fplist_get (contact, QCport),
-                 Fcons (Fplist_get (contact, QCspeed), Qnil));
+    return list2 (Fplist_get (contact, QCport),
+                 Fplist_get (contact, QCspeed));
   return Fplist_get (contact, key);
 }
 
@@ -1333,7 +1360,7 @@ Returns nil if format of ADDRESS is invalid.  */)
 }
 
 DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
-       doc: /* Return a list of all processes.  */)
+       doc: /* Return a list of all processes that are Emacs sub-processes.  */)
   (void)
 {
   return Fmapcar (Qcdr, Vprocess_alist);
@@ -1341,7 +1368,7 @@ DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
 \f
 /* Starting asynchronous inferior processes.  */
 
-static Lisp_Object start_process_unwind (Lisp_Object proc);
+static void start_process_unwind (Lisp_Object proc);
 
 DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
        doc: /* Start a program in a subprocess.  Return the process object for it.
@@ -1383,22 +1410,9 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
      function.  The argument list is protected by the caller, so all
      we really have to worry about is buffer.  */
   {
-    struct gcpro gcpro1, gcpro2;
-
-    current_dir = BVAR (current_buffer, directory);
-
-    GCPRO2 (buffer, current_dir);
-
-    current_dir = Funhandled_file_name_directory (current_dir);
-    if (NILP (current_dir))
-      /* If the file name handler says that current_dir is unreachable, use
-        a sensible default. */
-      current_dir = build_string ("~/");
-    current_dir = expand_and_dir_to_file (current_dir, Qnil);
-    if (NILP (Ffile_accessible_directory_p (current_dir)))
-      report_file_error ("Setting current directory",
-                        Fcons (BVAR (current_buffer, directory), Qnil));
-
+    struct gcpro gcpro1;
+    GCPRO1 (buffer);
+    current_dir = encode_current_directory ();
     UNGCPRO;
   }
 
@@ -1519,7 +1533,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
          openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK));
          UNGCPRO;
          if (NILP (tem))
-           report_file_error ("Searching for program", Fcons (program, Qnil));
+           report_file_error ("Searching for program", program);
          tem = Fexpand_file_name (tem, Qnil);
        }
       else
@@ -1542,7 +1556,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
 
        /* Encode the file name and put it in NEW_ARGV.
           That's where the child will use it to execute the program.  */
-       tem = Fcons (ENCODE_FILE (tem), Qnil);
+       tem = list1 (ENCODE_FILE (tem));
 
        /* Here we encode arguments by the coding system used for sending
           data to the process.  We don't support using different coding
@@ -1590,7 +1604,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
    PROC doesn't have its pid set, then we know someone has signaled
    an error and the process wasn't started successfully, so we should
    remove it from the process list.  */
-static Lisp_Object
+static void
 start_process_unwind (Lisp_Object proc)
 {
   if (!PROCESSP (proc))
@@ -1600,39 +1614,60 @@ start_process_unwind (Lisp_Object proc)
      -2 is used for a pty with no process, eg for gdb.  */
   if (XPROCESS (proc)->pid <= 0 && XPROCESS (proc)->pid != -2)
     remove_process (proc);
-
-  return Qnil;
 }
 
+/* If *FD_ADDR is nonnegative, close it, and mark it as closed.  */
+
 static void
-create_process_1 (struct atimer *timer)
+close_process_fd (int *fd_addr)
 {
-  /* Nothing to do.  */
+  int fd = *fd_addr;
+  if (0 <= fd)
+    {
+      *fd_addr = -1;
+      emacs_close (fd);
+    }
 }
 
+/* Indexes of file descriptors in open_fds.  */
+enum
+  {
+    /* The pipe from Emacs to its subprocess.  */
+    SUBPROCESS_STDIN,
+    WRITE_TO_SUBPROCESS,
+
+    /* The main pipe from the subprocess to Emacs.  */
+    READ_FROM_SUBPROCESS,
+    SUBPROCESS_STDOUT,
+
+    /* The pipe from the subprocess to Emacs that is closed when the
+       subprocess execs.  */
+    READ_FROM_EXEC_MONITOR,
+    EXEC_MONITOR_OUTPUT
+  };
+
+verify (PROCESS_OPEN_FDS == EXEC_MONITOR_OUTPUT + 1);
 
 static void
 create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 {
+  struct Lisp_Process *p = XPROCESS (process);
   int inchannel, outchannel;
   pid_t pid;
-  int sv[2];
-#ifndef WINDOWSNT
-  int wait_child_setup[2];
-#endif
+  int vfork_errno;
   int forkin, forkout;
   bool pty_flag = 0;
+  char pty_name[PTY_NAME_SIZE];
   Lisp_Object lisp_pty_name = Qnil;
-  Lisp_Object encoded_current_dir;
 
   inchannel = outchannel = -1;
 
-#ifdef HAVE_PTYS
   if (!NILP (Vprocess_connection_type))
-    outchannel = inchannel = allocate_pty ();
+    outchannel = inchannel = allocate_pty (pty_name);
 
   if (inchannel >= 0)
     {
+      p->open_fd[READ_FROM_SUBPROCESS] = inchannel;
 #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.  */
@@ -1641,6 +1676,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
       if (forkin < 0)
        report_file_error ("Opening pty", Qnil);
+      p->open_fd[SUBPROCESS_STDIN] = forkin;
 #else
       forkin = forkout = -1;
 #endif /* not USG, or USG_SUBTTY_WORKS */
@@ -1648,24 +1684,18 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       lisp_pty_name = build_string (pty_name);
     }
   else
-#endif /* HAVE_PTYS */
     {
-      if (pipe2 (sv, O_CLOEXEC) != 0)
+      if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0
+         || emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0)
        report_file_error ("Creating pipe", Qnil);
-      inchannel = sv[0];
-      forkout = sv[1];
-      if (pipe2 (sv, O_CLOEXEC) != 0)
-       {
-         emacs_close (inchannel);
-         emacs_close (forkout);
-         report_file_error ("Creating pipe", Qnil);
-       }
-      outchannel = sv[1];
-      forkin = sv[0];
+      forkin = p->open_fd[SUBPROCESS_STDIN];
+      outchannel = p->open_fd[WRITE_TO_SUBPROCESS];
+      inchannel = p->open_fd[READ_FROM_SUBPROCESS];
+      forkout = p->open_fd[SUBPROCESS_STDOUT];
     }
 
 #ifndef WINDOWSNT
-  if (pipe2 (wait_child_setup, O_CLOEXEC) != 0)
+  if (emacs_pipe (p->open_fd + READ_FROM_EXEC_MONITOR) != 0)
     report_file_error ("Creating pipe", Qnil);
 #endif
 
@@ -1674,16 +1704,16 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 
   /* Record this as an active process, with its channels.  */
   chan_process[inchannel] = process;
-  XPROCESS (process)->infd = inchannel;
-  XPROCESS (process)->outfd = outchannel;
+  p->infd = inchannel;
+  p->outfd = outchannel;
 
   /* Previously we recorded the tty descriptor used in the subprocess.
      It was only used for getting the foreground tty process, so now
      we just reopen the device (see emacs_get_tty_pgrp) as this is
      more portable (see USG_SUBTTY_WORKS above).  */
 
-  XPROCESS (process)->pty_flag = pty_flag;
-  pset_status (XPROCESS (process), Qrun);
+  p->pty_flag = pty_flag;
+  pset_status (p, Qrun);
 
   FD_SET (inchannel, &input_wait_mask);
   FD_SET (inchannel, &non_keyboard_wait_mask);
@@ -1693,35 +1723,29 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
   /* This may signal an error. */
   setup_process_coding_systems (process);
 
-  encoded_current_dir = ENCODE_FILE (current_dir);
-
   block_input ();
   block_child_signal ();
 
 #ifndef WINDOWSNT
   /* vfork, and prevent local vars from being clobbered by the vfork.  */
   {
-    Lisp_Object volatile encoded_current_dir_volatile = encoded_current_dir;
+    Lisp_Object volatile current_dir_volatile = current_dir;
     Lisp_Object volatile lisp_pty_name_volatile = lisp_pty_name;
-    Lisp_Object volatile process_volatile = process;
-    bool volatile pty_flag_volatile = pty_flag;
     char **volatile new_argv_volatile = new_argv;
     int volatile forkin_volatile = forkin;
     int volatile forkout_volatile = forkout;
-    int volatile wait_child_setup_0_volatile = wait_child_setup[0];
-    int volatile wait_child_setup_1_volatile = wait_child_setup[1];
+    struct Lisp_Process *p_volatile = p;
 
     pid = vfork ();
 
-    encoded_current_dir = encoded_current_dir_volatile;
+    current_dir = current_dir_volatile;
     lisp_pty_name = lisp_pty_name_volatile;
-    process = process_volatile;
-    pty_flag = pty_flag_volatile;
     new_argv = new_argv_volatile;
     forkin = forkin_volatile;
     forkout = forkout_volatile;
-    wait_child_setup[0] = wait_child_setup_0_volatile;
-    wait_child_setup[1] = wait_child_setup_1_volatile;
+    p = p_volatile;
+
+    pty_flag = p->pty_flag;
   }
 
   if (pid == 0)
@@ -1791,15 +1815,15 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       if (pty_flag)
        {
 
-         /* I wonder if emacs_close (emacs_open (pty_name, ...))
+         /* I wonder if emacs_close (emacs_open (SSDATA (lisp_pty_name), ...))
             would work?  */
          if (xforkin >= 0)
            emacs_close (xforkin);
-         xforkout = xforkin = emacs_open (pty_name, O_RDWR, 0);
+         xforkout = xforkin = emacs_open (SSDATA (lisp_pty_name), O_RDWR, 0);
 
          if (xforkin < 0)
            {
-             emacs_perror (pty_name);
+             emacs_perror (SSDATA (lisp_pty_name));
              _exit (EXIT_CANCELED);
            }
 
@@ -1812,12 +1836,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
          SETUP_SLAVE_PTY;
        }
 #endif /* SETUP_SLAVE_PTY */
-#ifdef AIX
-      /* On AIX, we've disabled SIGHUP above once we start a child on a pty.
-        Now reenable it in the child, so it will die when we want it to.  */
-      if (pty_flag)
-       signal (SIGHUP, SIG_DFL);
-#endif
 #endif /* HAVE_PTYS */
 
       signal (SIGINT, SIG_DFL);
@@ -1832,96 +1850,66 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       if (pty_flag)
        child_setup_tty (xforkout);
 #ifdef WINDOWSNT
-      pid = child_setup (xforkin, xforkout, xforkout,
-                        new_argv, 1, encoded_current_dir);
+      pid = child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir);
 #else  /* not WINDOWSNT */
-      emacs_close (wait_child_setup[0]);
-      child_setup (xforkin, xforkout, xforkout,
-                  new_argv, 1, encoded_current_dir);
+      child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir);
 #endif /* not WINDOWSNT */
     }
 
   /* Back in the parent process.  */
 
-  XPROCESS (process)->pid = pid;
+  vfork_errno = errno;
+  p->pid = pid;
   if (pid >= 0)
-    XPROCESS (process)->alive = 1;
+    p->alive = 1;
 
   /* Stop blocking in the parent.  */
   unblock_child_signal ();
   unblock_input ();
 
   if (pid < 0)
-    {
-      if (forkin >= 0)
-       emacs_close (forkin);
-      if (forkin != forkout && forkout >= 0)
-       emacs_close (forkout);
-    }
+    report_file_errno ("Doing vfork", Qnil, vfork_errno);
   else
     {
       /* vfork succeeded.  */
 
+      /* Close the pipe ends that the child uses, or the child's pty.  */
+      close_process_fd (&p->open_fd[SUBPROCESS_STDIN]);
+      close_process_fd (&p->open_fd[SUBPROCESS_STDOUT]);
+
 #ifdef WINDOWSNT
       register_child (pid, inchannel);
 #endif /* WINDOWSNT */
 
-      /* If the subfork execv fails, and it exits,
-        this close hangs.  I don't know why.
-        So have an interrupt jar it loose.  */
-      {
-       struct atimer *timer;
-       EMACS_TIME offset = make_emacs_time (1, 0);
-
-       stop_polling ();
-       timer = start_atimer (ATIMER_RELATIVE, offset, create_process_1, 0);
-
-       if (forkin >= 0)
-         emacs_close (forkin);
-
-       cancel_atimer (timer);
-       start_polling ();
-      }
-
-      if (forkin != forkout && forkout >= 0)
-       emacs_close (forkout);
-
-      pset_tty_name (XPROCESS (process), lisp_pty_name);
+      pset_tty_name (p, lisp_pty_name);
 
 #ifndef WINDOWSNT
       /* Wait for child_setup to complete in case that vfork is
-        actually defined as fork.  The descriptor wait_child_setup[1]
+        actually defined as fork.  The descriptor
+        XPROCESS (proc)->open_fd[EXEC_MONITOR_OUTPUT]
         of a pipe is closed at the child side either by close-on-exec
         on successful execve or the _exit call in child_setup.  */
       {
        char dummy;
 
-       emacs_close (wait_child_setup[1]);
-       emacs_read (wait_child_setup[0], &dummy, 1);
-       emacs_close (wait_child_setup[0]);
+       close_process_fd (&p->open_fd[EXEC_MONITOR_OUTPUT]);
+       emacs_read (p->open_fd[READ_FROM_EXEC_MONITOR], &dummy, 1);
+       close_process_fd (&p->open_fd[READ_FROM_EXEC_MONITOR]);
       }
 #endif
     }
-
-  /* Now generate the error if vfork failed.  */
-  if (pid < 0)
-    report_file_error ("Doing vfork", Qnil);
 }
 
-void
+static void
 create_pty (Lisp_Object process)
 {
-  int inchannel, outchannel;
-  bool pty_flag = 0;
-
-  inchannel = outchannel = -1;
-
-#ifdef HAVE_PTYS
-  if (!NILP (Vprocess_connection_type))
-    outchannel = inchannel = allocate_pty ();
+  struct Lisp_Process *p = XPROCESS (process);
+  char pty_name[PTY_NAME_SIZE];
+  int pty_fd = NILP (Vprocess_connection_type) ? -1 : allocate_pty (pty_name);
 
-  if (inchannel >= 0)
+  if (pty_fd >= 0)
     {
+      p->open_fd[SUBPROCESS_STDIN] = pty_fd;
 #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.  */
@@ -1930,6 +1918,7 @@ create_pty (Lisp_Object process)
       int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
       if (forkout < 0)
        report_file_error ("Opening pty", Qnil);
+      p->open_fd[WRITE_TO_SUBPROCESS] = forkout;
 #if defined (DONT_REOPEN_PTY)
       /* In the case that vfork is defined as fork, the parent process
         (Emacs) may send some data before the child process completes
@@ -1937,47 +1926,43 @@ create_pty (Lisp_Object process)
       child_setup_tty (forkout);
 #endif /* DONT_REOPEN_PTY */
 #endif /* not USG, or USG_SUBTTY_WORKS */
-      pty_flag = 1;
-    }
-#endif /* HAVE_PTYS */
 
-  fcntl (inchannel, F_SETFL, O_NONBLOCK);
-  fcntl (outchannel, F_SETFL, O_NONBLOCK);
+      fcntl (pty_fd, F_SETFL, O_NONBLOCK);
 
-  /* Record this as an active process, with its channels.
-     As a result, child_setup will close Emacs's side of the pipes.  */
-  chan_process[inchannel] = process;
-  XPROCESS (process)->infd = inchannel;
-  XPROCESS (process)->outfd = outchannel;
+      /* Record this as an active process, with its channels.
+        As a result, child_setup will close Emacs's side of the pipes.  */
+      chan_process[pty_fd] = process;
+      p->infd = pty_fd;
+      p->outfd = pty_fd;
 
-  /* Previously we recorded the tty descriptor used in the subprocess.
-     It was only used for getting the foreground tty process, so now
-     we just reopen the device (see emacs_get_tty_pgrp) as this is
-     more portable (see USG_SUBTTY_WORKS above).  */
+      /* Previously we recorded the tty descriptor used in the subprocess.
+        It was only used for getting the foreground tty process, so now
+        we just reopen the device (see emacs_get_tty_pgrp) as this is
+        more portable (see USG_SUBTTY_WORKS above).  */
 
-  XPROCESS (process)->pty_flag = pty_flag;
-  pset_status (XPROCESS (process), Qrun);
-  setup_process_coding_systems (process);
+      p->pty_flag = 1;
+      pset_status (p, Qrun);
+      setup_process_coding_systems (process);
 
-  FD_SET (inchannel, &input_wait_mask);
-  FD_SET (inchannel, &non_keyboard_wait_mask);
-  if (inchannel > max_process_desc)
-    max_process_desc = inchannel;
+      FD_SET (pty_fd, &input_wait_mask);
+      FD_SET (pty_fd, &non_keyboard_wait_mask);
+      if (pty_fd > max_process_desc)
+       max_process_desc = pty_fd;
 
-  XPROCESS (process)->pid = -2;
-#ifdef HAVE_PTYS
-  if (pty_flag)
-    pset_tty_name (XPROCESS (process), build_string (pty_name));
-  else
-#endif
-    pset_tty_name (XPROCESS (process), Qnil);
+      pset_tty_name (p, build_string (pty_name));
+    }
+
+  p->pid = -2;
 }
 
 \f
 /* Convert an internal struct sockaddr to a lisp object (vector or string).
    The address family of sa is not included in the result.  */
 
-static Lisp_Object
+#ifndef WINDOWSNT
+static
+#endif
+Lisp_Object
 conv_sockaddr_to_lisp (struct sockaddr *sa, int len)
 {
   Lisp_Object address;
@@ -2330,8 +2315,12 @@ set_socket_option (int s, Lisp_Object opt, Lisp_Object val)
     }
 
   if (ret < 0)
-    report_file_error ("Cannot set network option",
-                      Fcons (opt, Fcons (val, Qnil)));
+    {
+      int setsockopt_errno = errno;
+      report_file_errno ("Cannot set network option", list2 (opt, val),
+                        setsockopt_errno);
+    }
+
   return (1 << sopt->optbit);
 }
 
@@ -2463,16 +2452,6 @@ usage: (serial-process-configure &rest ARGS)  */)
   return Qnil;
 }
 
-/* Used by make-serial-process to recover from errors.  */
-static Lisp_Object
-make_serial_process_unwind (Lisp_Object proc)
-{
-  if (!PROCESSP (proc))
-    emacs_abort ();
-  remove_process (proc);
-  return Qnil;
-}
-
 DEFUN ("make-serial-process", Fmake_serial_process, Smake_serial_process,
        0, MANY, 0,
        doc: /* Create and return a serial port process.
@@ -2578,10 +2557,11 @@ usage:  (make-serial-process &rest ARGS)  */)
   CHECK_STRING (name);
   proc = make_process (name);
   specpdl_count = SPECPDL_INDEX ();
-  record_unwind_protect (make_serial_process_unwind, proc);
+  record_unwind_protect (remove_process, proc);
   p = XPROCESS (proc);
 
-  fd = serial_open (SSDATA (port));
+  fd = serial_open (port);
+  p->open_fd[SUBPROCESS_STDIN] = fd;
   p->infd = fd;
   p->outfd = fd;
   if (fd > max_process_desc)
@@ -2604,7 +2584,7 @@ usage:  (make-serial-process &rest ARGS)  */)
     p->kill_without_query = 1;
   if (tem = Fplist_get (contact, QCstop), !NILP (tem))
     pset_command (p, Qt);
-  p->pty_flag = 0;
+  eassert (! p->pty_flag);
 
   if (!EQ (p->command, Qt))
     {
@@ -3014,7 +2994,7 @@ usage: (make-network-process &rest ARGS)  */)
 #ifdef POLL_FOR_INPUT
   if (socktype != SOCK_DGRAM)
     {
-      record_unwind_protect (unwind_stop_other_atimers, Qnil);
+      record_unwind_protect_void (run_all_atimers);
       bind_polling_period (10);
     }
 #endif
@@ -3174,7 +3154,7 @@ usage: (make-network-process &rest ARGS)  */)
 #endif
 
       /* Make us close S if quit.  */
-      record_unwind_protect (close_file_unwind, make_number (s));
+      record_unwind_protect_int (close_file_unwind, s);
 
       /* Parse network options in the arg list.
         We simply ignore anything which isn't a known option (including other keywords).
@@ -3254,7 +3234,7 @@ usage: (make-network-process &rest ARGS)  */)
             wait for completion is pselect(). */
          int sc;
          socklen_t len;
-         SELECT_TYPE fdset;
+         fd_set fdset;
        retry_select:
          FD_ZERO (&fdset);
          FD_SET (s, &fdset);
@@ -3265,18 +3245,17 @@ usage: (make-network-process &rest ARGS)  */)
              if (errno == EINTR)
                goto retry_select;
              else
-               report_file_error ("select failed", Qnil);
+               report_file_error ("Failed select", Qnil);
            }
          eassert (sc > 0);
 
          len = sizeof xerrno;
          eassert (FD_ISSET (s, &fdset));
-         if (getsockopt (s, SOL_SOCKET, SO_ERROR, &xerrno, &len) == -1)
-           report_file_error ("getsockopt failed", Qnil);
+         if (getsockopt (s, SOL_SOCKET, SO_ERROR, &xerrno, &len) < 0)
+           report_file_error ("Failed getsockopt", Qnil);
          if (xerrno)
-           errno = xerrno, report_file_error ("error during connect", Qnil);
-         else
-           break;
+           report_file_errno ("Failed connect", Qnil, xerrno);
+         break;
        }
 #endif /* !WINDOWSNT */
 
@@ -3345,12 +3324,6 @@ usage: (make-network-process &rest ARGS)  */)
     }
 #endif
 
-  /* Discard the unwind protect for closing S, if any.  */
-  specpdl_ptr = specpdl + count1;
-
-  /* Unwind bind_polling_period and request_sigio.  */
-  unbind_to (count, Qnil);
-
   if (s < 0)
     {
       /* If non-blocking got this far - and failed - assume non-blocking is
@@ -3360,11 +3333,10 @@ usage: (make-network-process &rest ARGS)  */)
       if (is_non_blocking_client)
          return Qnil;
 
-      errno = xerrno;
-      if (is_server)
-       report_file_error ("make server process failed", contact);
-      else
-       report_file_error ("make client process failed", contact);
+      report_file_errno ((is_server
+                         ? "make server process failed"
+                         : "make client process failed"),
+                        contact, xerrno);
     }
 
   inch = s;
@@ -3393,8 +3365,17 @@ usage: (make-network-process &rest ARGS)  */)
   if ((tem = Fplist_get (contact, QCstop), !NILP (tem)))
     pset_command (p, Qt);
   p->pid = 0;
+
+  p->open_fd[SUBPROCESS_STDIN] = inch;
   p->infd  = inch;
   p->outfd = outch;
+
+  /* Discard the unwind protect for closing S, if any.  */
+  specpdl_ptr = specpdl + count1;
+
+  /* Unwind bind_polling_period and request_sigio.  */
+  unbind_to (count, Qnil);
+
   if (is_server && socktype != SOCK_DGRAM)
     pset_status (p, Qlisten);
 
@@ -3527,15 +3508,11 @@ usage: (make-network-process &rest ARGS)  */)
 }
 
 \f
-#if defined (HAVE_NET_IF_H)
+#ifdef HAVE_NET_IF_H
 
 #ifdef SIOCGIFCONF
-DEFUN ("network-interface-list", Fnetwork_interface_list, Snetwork_interface_list, 0, 0, 0,
-       doc: /* Return an alist of all network interfaces and their network address.
-Each element is a cons, the car of which is a string containing the
-interface name, and the cdr is the network address in internal
-format; see the description of ADDRESS in `make-network-process'.  */)
-  (void)
+static Lisp_Object
+network_interface_list (void)
 {
   struct ifconf ifconf;
   struct ifreq *ifreq;
@@ -3543,10 +3520,13 @@ format; see the description of ADDRESS in `make-network-process'.  */)
   ptrdiff_t buf_size = 512;
   int s;
   Lisp_Object res;
+  ptrdiff_t count;
 
   s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
+  count = SPECPDL_INDEX ();
+  record_unwind_protect_int (close_file_unwind, s);
 
   do
     {
@@ -3562,9 +3542,7 @@ format; see the description of ADDRESS in `make-network-process'.  */)
     }
   while (ifconf.ifc_len == buf_size);
 
-  emacs_close (s);
-
-  res = Qnil;
+  res = unbind_to (count, Qnil);
   ifreq = ifconf.ifc_req;
   while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len)
     {
@@ -3676,19 +3654,15 @@ static const struct ifflag_def ifflag_table[] = {
   { 0, 0 }
 };
 
-DEFUN ("network-interface-info", Fnetwork_interface_info, Snetwork_interface_info, 1, 1, 0,
-       doc: /* Return information about network interface named IFNAME.
-The return value is a list (ADDR BCAST NETMASK HWADDR FLAGS),
-where ADDR is the layer 3 address, BCAST is the layer 3 broadcast address,
-NETMASK is the layer 3 network mask, HWADDR is the layer 2 address, and
-FLAGS is the current flags of the interface.  */)
-  (Lisp_Object ifname)
+static Lisp_Object
+network_interface_info (Lisp_Object ifname)
 {
   struct ifreq rq;
   Lisp_Object res = Qnil;
   Lisp_Object elt;
   int s;
   bool any = 0;
+  ptrdiff_t count;
 #if (! (defined SIOCGIFHWADDR && defined HAVE_STRUCT_IFREQ_IFR_HWADDR) \
      && defined HAVE_GETIFADDRS && defined LLADDR)
   struct ifaddrs *ifap;
@@ -3703,6 +3677,8 @@ FLAGS is the current flags of the interface.  */)
   s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
+  count = SPECPDL_INDEX ();
+  record_unwind_protect_int (close_file_unwind, s);
 
   elt = Qnil;
 #if defined (SIOCGIFFLAGS) && defined (HAVE_STRUCT_IFREQ_IFR_FLAGS)
@@ -3748,7 +3724,9 @@ FLAGS is the current flags of the interface.  */)
 
       any = 1;
       for (n = 0; n < 6; n++)
-       p->contents[n] = make_number (((unsigned char *)&rq.ifr_hwaddr.sa_data[0])[n]);
+       p->contents[n] = make_number (((unsigned char *)
+                                      &rq.ifr_hwaddr.sa_data[0])
+                                     [n]);
       elt = Fcons (make_number (rq.ifr_hwaddr.sa_family), hwaddr);
     }
 #elif defined (HAVE_GETIFADDRS) && defined (LLADDR)
@@ -3819,29 +3797,64 @@ FLAGS is the current flags of the interface.  */)
 #endif
   res = Fcons (elt, res);
 
-  emacs_close (s);
+  return unbind_to (count, any ? res : Qnil);
+}
+#endif /* !SIOCGIFADDR && !SIOCGIFHWADDR && !SIOCGIFFLAGS */
+#endif /* defined (HAVE_NET_IF_H) */
+
+DEFUN ("network-interface-list", Fnetwork_interface_list,
+       Snetwork_interface_list, 0, 0, 0,
+       doc: /* Return an alist of all network interfaces and their network address.
+Each element is a cons, the car of which is a string containing the
+interface name, and the cdr is the network address in internal
+format; see the description of ADDRESS in `make-network-process'.
 
-  return any ? res : Qnil;
+If the information is not available, return nil.  */)
+  (void)
+{
+#if (defined HAVE_NET_IF_H && defined SIOCGIFCONF) || defined WINDOWSNT
+  return network_interface_list ();
+#else
+  return Qnil;
+#endif
 }
+
+DEFUN ("network-interface-info", Fnetwork_interface_info,
+       Snetwork_interface_info, 1, 1, 0,
+       doc: /* Return information about network interface named IFNAME.
+The return value is a list (ADDR BCAST NETMASK HWADDR FLAGS),
+where ADDR is the layer 3 address, BCAST is the layer 3 broadcast address,
+NETMASK is the layer 3 network mask, HWADDR is the layer 2 address, and
+FLAGS is the current flags of the interface.
+
+Data that is unavailable is returned as nil.  */)
+  (Lisp_Object ifname)
+{
+#if ((defined HAVE_NET_IF_H                           \
+      && (defined SIOCGIFADDR || defined SIOCGIFHWADDR \
+         || defined SIOCGIFFLAGS))                    \
+     || defined WINDOWSNT)
+  return network_interface_info (ifname);
+#else
+  return Qnil;
 #endif
-#endif /* defined (HAVE_NET_IF_H) */
+}
+
 
 /* Turn off input and output for process PROC.  */
 
 static void
 deactivate_process (Lisp_Object proc)
 {
-  register int inchannel, outchannel;
-  register struct Lisp_Process *p = XPROCESS (proc);
+  int inchannel;
+  struct Lisp_Process *p = XPROCESS (proc);
+  int i;
 
 #ifdef HAVE_GNUTLS
   /* Delete GnuTLS structures in PROC, if any.  */
   emacs_gnutls_deinit (proc);
 #endif /* HAVE_GNUTLS */
 
-  inchannel  = p->infd;
-  outchannel = p->outfd;
-
 #ifdef ADAPTIVE_READ_BUFFERING
   if (p->read_output_delay > 0)
     {
@@ -3852,14 +3865,14 @@ deactivate_process (Lisp_Object proc)
     }
 #endif
 
+  /* Beware SIGCHLD hereabouts. */
+
+  for (i = 0; i < PROCESS_OPEN_FDS; i++)
+    close_process_fd (&p->open_fd[i]);
+
+  inchannel = p->infd;
   if (inchannel >= 0)
     {
-      /* Beware SIGCHLD hereabouts. */
-      flush_pending_output (inchannel);
-      emacs_close (inchannel);
-      if (outchannel >= 0 && outchannel != inchannel)
-       emacs_close (outchannel);
-
       p->infd  = -1;
       p->outfd = -1;
 #ifdef DATAGRAM_SOCKETS
@@ -3884,13 +3897,14 @@ deactivate_process (Lisp_Object proc)
 #endif
       if (inchannel == max_process_desc)
        {
-         int i;
          /* We just closed the highest-numbered process input descriptor,
             so recompute the highest-numbered one now.  */
-         max_process_desc = 0;
-         for (i = 0; i < MAXDESC; i++)
-           if (!NILP (chan_process[i]))
-             max_process_desc = i;
+         int i = inchannel;
+         do
+           i--;
+         while (0 <= i && NILP (chan_process[i]));
+
+         max_process_desc = i;
        }
     }
 }
@@ -3952,9 +3966,9 @@ Return non-nil if we received any output before the timeout expired.  */)
        {
          if (XFLOAT_DATA (seconds) > 0)
            {
-             EMACS_TIME t = EMACS_TIME_FROM_DOUBLE (XFLOAT_DATA (seconds));
-             secs = min (EMACS_SECS (t), WAIT_READING_MAX);
-             nsecs = EMACS_NSECS (t);
+             struct timespec t = dtotimespec (XFLOAT_DATA (seconds));
+             secs = min (t.tv_sec, WAIT_READING_MAX);
+             nsecs = t.tv_nsec;
            }
        }
       else
@@ -3995,6 +4009,7 @@ server_accept_connection (Lisp_Object server, int channel)
 #endif
   } saddr;
   socklen_t len = sizeof saddr;
+  ptrdiff_t count;
 
   s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC);
 
@@ -4017,6 +4032,9 @@ server_accept_connection (Lisp_Object server, int channel)
       return;
     }
 
+  count = SPECPDL_INDEX ();
+  record_unwind_protect_int (close_file_unwind, s);
+
   connect_counter++;
 
   /* Setup a new process to handle the connection.  */
@@ -4133,6 +4151,11 @@ server_accept_connection (Lisp_Object server, int channel)
   pset_filter (p, ps->filter);
   pset_command (p, Qnil);
   p->pid = 0;
+
+  /* Discard the unwind protect for closing S.  */
+  specpdl_ptr = specpdl + count;
+
+  p->open_fd[SUBPROCESS_STDIN] = s;
   p->infd  = s;
   p->outfd = s;
   pset_status (p, Qrun);
@@ -4186,11 +4209,10 @@ server_accept_connection (Lisp_Object server, int channel)
    when not inside wait_reading_process_output.  */
 static int waiting_for_user_input_p;
 
-static Lisp_Object
-wait_reading_process_output_unwind (Lisp_Object data)
+static void
+wait_reading_process_output_unwind (int data)
 {
-  waiting_for_user_input_p = XINT (data);
-  return Qnil;
+  waiting_for_user_input_p = data;
 }
 
 /* This is here so breakpoints can be put on it.  */
@@ -4244,14 +4266,14 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                             struct Lisp_Process *wait_proc, int just_wait_proc)
 {
   int channel, nfds;
-  SELECT_TYPE Available;
-  SELECT_TYPE Writeok;
+  fd_set Available;
+  fd_set Writeok;
   bool check_write;
   int check_delay;
   bool no_avail;
   int xerrno;
   Lisp_Object proc;
-  EMACS_TIME timeout, end_time;
+  struct timespec timeout, end_time;
   int wait_channel = -1;
   bool got_some_input = 0;
   ptrdiff_t count = SPECPDL_INDEX ();
@@ -4268,8 +4290,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
   if (wait_proc != NULL)
     wait_channel = wait_proc->infd;
 
-  record_unwind_protect (wait_reading_process_output_unwind,
-                        make_number (waiting_for_user_input_p));
+  record_unwind_protect_int (wait_reading_process_output_unwind,
+                            waiting_for_user_input_p);
   waiting_for_user_input_p = read_kbd;
 
   if (time_limit < 0)
@@ -4284,8 +4306,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
      compute the absolute time to return at.  */
   if (time_limit || nsecs > 0)
     {
-      timeout = make_emacs_time (time_limit, nsecs);
-      end_time = add_emacs_time (current_emacs_time (), timeout);
+      timeout = make_timespec (time_limit, nsecs);
+      end_time = timespec_add (current_timespec (), timeout);
     }
 
   while (1)
@@ -4312,18 +4334,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
             gobble output available now
             but don't wait at all. */
 
-         timeout = make_emacs_time (0, 0);
+         timeout = make_timespec (0, 0);
        }
       else if (time_limit || nsecs > 0)
        {
-         EMACS_TIME now = current_emacs_time ();
-         if (EMACS_TIME_LE (end_time, now))
+         struct timespec now = current_timespec ();
+         if (timespec_cmp (end_time, now) <= 0)
            break;
-         timeout = sub_emacs_time (end_time, now);
+         timeout = timespec_sub (end_time, now);
        }
       else
        {
-         timeout = make_emacs_time (100000, 0);
+         timeout = make_timespec (100000, 0);
        }
 
       /* Normally we run timers here.
@@ -4333,7 +4355,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       if (NILP (wait_for_cell)
          && just_wait_proc >= 0)
        {
-         EMACS_TIME timer_delay;
+         struct timespec timer_delay;
 
          do
            {
@@ -4368,9 +4390,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          /* A negative timeout means do not wait at all.  */
          if (nsecs >= 0)
            {
-             if (EMACS_TIME_VALID_P (timer_delay))
+             if (timespec_valid_p (timer_delay))
                {
-                 if (EMACS_TIME_LT (timer_delay, timeout))
+                 if (timespec_cmp (timer_delay, timeout) < 0)
                    {
                      timeout = timer_delay;
                      timeout_reduced_for_timers = 1;
@@ -4399,8 +4421,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
         timeout to get our attention.  */
       if (update_tick != process_tick)
        {
-         SELECT_TYPE Atemp;
-         SELECT_TYPE Ctemp;
+         fd_set Atemp;
+         fd_set Ctemp;
 
           if (kbd_on_hold_p ())
             FD_ZERO (&Atemp);
@@ -4408,7 +4430,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
             Atemp = input_wait_mask;
          Ctemp = write_mask;
 
-         timeout = make_emacs_time (0, 0);
+         timeout = make_timespec (0, 0);
          if ((pselect (max (max_process_desc, max_input_desc) + 1,
                        &Atemp,
 #ifdef NON_BLOCKING_CONNECT
@@ -4530,8 +4552,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
             Vprocess_adaptive_read_buffering is nil.  */
          if (process_output_skip && check_delay > 0)
            {
-             int nsecs = EMACS_NSECS (timeout);
-             if (EMACS_SECS (timeout) > 0 || nsecs > READ_OUTPUT_DELAY_MAX)
+             int nsecs = timeout.tv_nsec;
+             if (timeout.tv_sec > 0 || nsecs > READ_OUTPUT_DELAY_MAX)
                nsecs = READ_OUTPUT_DELAY_MAX;
              for (channel = 0; check_delay > 0 && channel <= max_process_desc; channel++)
                {
@@ -4551,7 +4573,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                        nsecs = XPROCESS (proc)->read_output_delay;
                    }
                }
-             timeout = make_emacs_time (0, nsecs);
+             timeout = make_timespec (0, nsecs);
              process_output_skip = 0;
            }
 #endif
@@ -4565,7 +4587,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 #endif
             (max (max_process_desc, max_input_desc) + 1,
              &Available,
-             (check_write ? &Writeok : (SELECT_TYPE *)0),
+             (check_write ? &Writeok : 0),
              NULL, &timeout, NULL);
 
 #ifdef HAVE_GNUTLS
@@ -4583,12 +4605,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                     the gnutls library -- 2.12.14 has been confirmed
                     to need it.  See
                     http://comments.gmane.org/gmane.emacs.devel/145074 */
-                 for (channel = 0; channel < MAXDESC; ++channel)
+                 for (channel = 0; channel < FD_SETSIZE; ++channel)
                    if (! NILP (chan_process[channel]))
                      {
                        struct Lisp_Process *p =
                          XPROCESS (chan_process[channel]);
-                       if (p && p->gnutls_p && p->infd
+                       if (p && p->gnutls_p && p->gnutls_state && p->infd
                            && ((emacs_gnutls_record_check_pending
                                 (p->gnutls_state))
                                > 0))
@@ -4602,6 +4624,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                {
                  /* Check this specific channel. */
                  if (wait_proc->gnutls_p /* Check for valid process.  */
+                     && wait_proc->gnutls_state
                      /* Do we have pending data?  */
                      && ((emacs_gnutls_record_check_pending
                           (wait_proc->gnutls_state))
@@ -4632,22 +4655,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          if (xerrno == EINTR)
            no_avail = 1;
          else if (xerrno == EBADF)
-           {
-#ifdef AIX
-             /* AIX doesn't handle PTY closure the same way BSD does.  On AIX,
-                the child's closure of the pts gives the parent a SIGHUP, and
-                the ptc file descriptor is automatically closed,
-                yielding EBADF here or at select() call above.
-                So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF
-                in m/ibmrt-aix.h), and here we just ignore the select error.
-                Cleanup occurs c/o status_notify after SIGCHLD. */
-             no_avail = 1; /* Cannot depend on values returned */
-#else
-             emacs_abort ();
-#endif
-           }
+           emacs_abort ();
          else
-           error ("select error: %s", emacs_strerror (xerrno));
+           report_file_errno ("Failed select", Qnil, xerrno);
        }
 
       if (no_avail)
@@ -4874,7 +4884,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 #else
              {
                struct sockaddr pname;
-               int pnamelen = sizeof (pname);
+               socklen_t pnamelen = sizeof (pname);
 
                /* If connection failed, getpeername will fail.  */
                xerrno = 0;
@@ -4996,7 +5006,7 @@ read_process_output (Lisp_Object proc, register int channel)
          proc_buffered_char[channel] = -1;
        }
 #ifdef HAVE_GNUTLS
-      if (p->gnutls_p)
+      if (p->gnutls_p && p->gnutls_state)
        nbytes = emacs_gnutls_read (p, chars + carryover + buffered,
                                    readmax - buffered);
       else
@@ -5146,9 +5156,7 @@ read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars,
        sometimes it's simply wrong to wrap (e.g. when called from
        accept-process-output).  */
     internal_condition_case_1 (read_process_output_call,
-                              Fcons (outstream,
-                                     Fcons (make_lisp_proc (p),
-                                            Fcons (text, Qnil))),
+                              list3 (outstream, make_lisp_proc (p), text),
                               !NILP (Vdebug_on_error) ? Qnil : Qerror,
                               read_process_output_error_handler);
 
@@ -5205,15 +5213,10 @@ DEFUN ("internal-default-process-filter", Finternal_default_process_filter,
 
       bset_read_only (current_buffer, Qnil);
 
-      /* Insert new output into buffer
-        at the current end-of-output marker,
-        thus preserving logical ordering of input and output.  */
+      /* Insert new output into buffer at the current end-of-output
+        marker, thus preserving logical ordering of input and output.  */
       if (XMARKER (p->mark)->buffer)
-       SET_PT_BOTH (clip_to_bounds (BEGV,
-                                    marker_position (p->mark), ZV),
-                    clip_to_bounds (BEGV_BYTE,
-                                    marker_byte_position (p->mark),
-                                    ZV_BYTE));
+       set_point_from_marker (p->mark);
       else
        SET_PT_BOTH (ZV, ZV_BYTE);
       before = PT;
@@ -5244,7 +5247,7 @@ DEFUN ("internal-default-process-filter", Finternal_default_process_filter,
       else
        set_marker_both (p->mark, p->buffer, PT, PT_BYTE);
 
-      update_mode_lines++;
+      update_mode_lines = 23;
 
       /* Make sure opoint and the old restrictions
         float ahead of any new text just as point would.  */
@@ -5318,7 +5321,7 @@ write_queue_push (struct Lisp_Process *p, Lisp_Object input_obj,
   if (front)
     pset_write_queue (p, Fcons (entry, p->write_queue));
   else
-    pset_write_queue (p, nconc2 (p->write_queue, Fcons (entry, Qnil)));
+    pset_write_queue (p, nconc2 (p->write_queue, list1 (entry)));
 }
 
 /* Remove the first element in the write_queue of process P, put its
@@ -5491,13 +5494,13 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
              if (rv >= 0)
                written = rv;
              else if (errno == EMSGSIZE)
-               report_file_error ("sending datagram", Fcons (proc, Qnil));
+               report_file_error ("Sending datagram", proc);
            }
          else
 #endif
            {
 #ifdef HAVE_GNUTLS
-             if (p->gnutls_p)
+             if (p->gnutls_p && p->gnutls_state)
                written = emacs_gnutls_write (p, cur_buf, cur_len);
              else
 #endif
@@ -5568,7 +5571,7 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
                }
              else
                /* This is a real error.  */
-               report_file_error ("writing to process", Fcons (proc, Qnil));
+               report_file_error ("Writing to process", proc);
            }
          cur_buf += written;
          cur_len -= written;
@@ -5794,10 +5797,9 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
        return;
     }
 
-  switch (signo)
-    {
 #ifdef SIGCONT
-    case SIGCONT:
+  if (signo == SIGCONT)
+    {
       p->raw_status_new = 0;
       pset_status (p, Qrun);
       p->tick = ++process_tick;
@@ -5806,14 +5808,8 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
          status_notify (NULL);
          redisplay_preserve_echo_area (13);
        }
-      break;
-#endif /* ! defined (SIGCONT) */
-    case SIGINT:
-    case SIGQUIT:
-    case SIGKILL:
-      flush_pending_output (p->infd);
-      break;
     }
+#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
@@ -6062,13 +6058,14 @@ process has been transmitted to the serial port.  */)
     {
 #ifndef WINDOWSNT
       if (tcdrain (XPROCESS (proc)->outfd) != 0)
-       error ("tcdrain() failed: %s", emacs_strerror (errno));
+       report_file_error ("Failed tcdrain", Qnil);
 #endif /* not WINDOWSNT */
       /* Do nothing on Windows because writes are blocking.  */
     }
   else
     {
-      int old_outfd, new_outfd;
+      int old_outfd = XPROCESS (proc)->outfd;
+      int new_outfd;
 
 #ifdef HAVE_SHUTDOWN
       /* If this is a network connection, or socketpair is used
@@ -6076,18 +6073,15 @@ process has been transmitted to the serial port.  */)
         (In some old system, shutdown to socketpair doesn't work.
         Then we just can't win.)  */
       if (EQ (XPROCESS (proc)->type, Qnetwork)
-         || XPROCESS (proc)->outfd == XPROCESS (proc)->infd)
-       shutdown (XPROCESS (proc)->outfd, 1);
-      /* In case of socketpair, outfd == infd, so don't close it.  */
-      if (XPROCESS (proc)->outfd != XPROCESS (proc)->infd)
-       emacs_close (XPROCESS (proc)->outfd);
-#else /* not HAVE_SHUTDOWN */
-      emacs_close (XPROCESS (proc)->outfd);
-#endif /* not HAVE_SHUTDOWN */
+         || XPROCESS (proc)->infd == old_outfd)
+       shutdown (old_outfd, 1);
+#endif
+      close_process_fd (&XPROCESS (proc)->open_fd[WRITE_TO_SUBPROCESS]);
       new_outfd = emacs_open (NULL_DEVICE, O_WRONLY, 0);
       if (new_outfd < 0)
-       emacs_abort ();
-      old_outfd = XPROCESS (proc)->outfd;
+       report_file_error ("Opening null device", Qnil);
+      XPROCESS (proc)->open_fd[WRITE_TO_SUBPROCESS] = new_outfd;
+      XPROCESS (proc)->outfd = new_outfd;
 
       if (!proc_encode_coding_system[new_outfd])
        proc_encode_coding_system[new_outfd]
@@ -6096,8 +6090,6 @@ process has been transmitted to the serial port.  */)
        = *proc_encode_coding_system[old_outfd];
       memset (proc_encode_coding_system[old_outfd], 0,
              sizeof (struct coding_system));
-
-      XPROCESS (proc)->outfd = new_outfd;
     }
   return process;
 }
@@ -6163,7 +6155,7 @@ static signal_handler_t volatile lib_child_handler;
 static void
 handle_child_signal (int sig)
 {
-  Lisp_Object tail;
+  Lisp_Object tail, proc;
 
   /* Find the process that signaled us, and record its status.  */
 
@@ -6174,7 +6166,11 @@ handle_child_signal (int sig)
       bool all_pids_are_fixnums
        = (MOST_NEGATIVE_FIXNUM <= TYPE_MINIMUM (pid_t)
           && TYPE_MAXIMUM (pid_t) <= MOST_POSITIVE_FIXNUM);
-      Lisp_Object xpid = XCAR (tail);
+      Lisp_Object head = XCAR (tail);
+      Lisp_Object xpid;
+      if (! CONSP (head))
+       continue;
+      xpid = XCAR (head);
       if (all_pids_are_fixnums ? INTEGERP (xpid) : NUMBERP (xpid))
        {
          pid_t deleted_pid;
@@ -6183,14 +6179,17 @@ handle_child_signal (int sig)
          else
            deleted_pid = XFLOAT_DATA (xpid);
          if (child_status_changed (deleted_pid, 0, 0))
-           XSETCAR (tail, Qnil);
+           {
+             if (STRINGP (XCDR (head)))
+               unlink (SSDATA (XCDR (head)));
+             XSETCAR (tail, Qnil);
+           }
        }
     }
 
   /* Otherwise, if it is asynchronous, it is in Vprocess_alist.  */
-  for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+  FOR_EACH_PROCESS (tail, proc)
     {
-      Lisp_Object proc = XCDR (XCAR (tail));
       struct Lisp_Process *p = XPROCESS (proc);
       int status;
 
@@ -6294,8 +6293,7 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
   running_asynch_code = 1;
 
   internal_condition_case_1 (read_process_output_call,
-                            Fcons (sentinel,
-                                   Fcons (proc, Fcons (reason, Qnil))),
+                            list3 (sentinel, proc, reason),
                             !NILP (Vdebug_on_error) ? Qnil : Qerror,
                             exec_sentinel_error_handler);
 
@@ -6346,13 +6344,10 @@ status_notify (struct Lisp_Process *deleting_process)
      that we run, we get called again to handle their status changes.  */
   update_tick = process_tick;
 
-  for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+  FOR_EACH_PROCESS (tail, proc)
     {
       Lisp_Object symbol;
-      register struct Lisp_Process *p;
-
-      proc = Fcdr (XCAR (tail));
-      p = XPROCESS (proc);
+      register struct Lisp_Process *p = XPROCESS (proc);
 
       if (p->tick != p->update_tick)
        {
@@ -6396,7 +6391,7 @@ status_notify (struct Lisp_Process *deleting_process)
        }
     } /* end for */
 
-  update_mode_lines++;  /* In case buffers use %s in mode-line-format.  */
+  update_mode_lines = 24;  /* In case buffers use %s in mode-line-format.  */
   UNGCPRO;
 }
 
@@ -6577,8 +6572,8 @@ keyboard_bit_set (fd_set *mask)
 #else  /* not subprocesses */
 
 /* Defined on msdos.c.  */
-extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
-                      EMACS_TIME *, void *);
+extern int sys_select (int, fd_set *, fd_set *, fd_set *,
+                      struct timespec *, void *);
 
 /* Implementation of wait_reading_process_output, assuming that there
    are no subprocesses.  Used only by the MS-DOS build.
@@ -6617,7 +6612,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                             struct Lisp_Process *wait_proc, int just_wait_proc)
 {
   register int nfds;
-  EMACS_TIME end_time, timeout;
+  struct timespec end_time, timeout;
 
   if (time_limit < 0)
     {
@@ -6630,8 +6625,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
   /* What does time_limit really mean?  */
   if (time_limit || nsecs > 0)
     {
-      timeout = make_emacs_time (time_limit, nsecs);
-      end_time = add_emacs_time (current_emacs_time (), timeout);
+      timeout = make_timespec (time_limit, nsecs);
+      end_time = timespec_add (current_timespec (), timeout);
     }
 
   /* Turn off periodic alarms (in case they are in use)
@@ -6643,7 +6638,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
   while (1)
     {
       bool timeout_reduced_for_timers = 0;
-      SELECT_TYPE waitchannels;
+      fd_set waitchannels;
       int xerrno;
 
       /* If calling from keyboard input, do not quit
@@ -6664,18 +6659,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
             gobble output available now
             but don't wait at all.  */
 
-         timeout = make_emacs_time (0, 0);
+         timeout = make_timespec (0, 0);
        }
       else if (time_limit || nsecs > 0)
        {
-         EMACS_TIME now = current_emacs_time ();
-         if (EMACS_TIME_LE (end_time, now))
+         struct timespec now = current_timespec ();
+         if (timespec_cmp (end_time, now) <= 0)
            break;
-         timeout = sub_emacs_time (end_time, now);
+         timeout = timespec_sub (end_time, now);
        }
       else
        {
-         timeout = make_emacs_time (100000, 0);
+         timeout = make_timespec (100000, 0);
        }
 
       /* If our caller will not immediately handle keyboard events,
@@ -6684,7 +6679,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
         call timer_delay on their own.)  */
       if (NILP (wait_for_cell))
        {
-         EMACS_TIME timer_delay;
+         struct timespec timer_delay;
 
          do
            {
@@ -6704,9 +6699,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              && requeued_events_pending_p ())
            break;
 
-         if (EMACS_TIME_VALID_P (timer_delay) && nsecs >= 0)
+         if (timespec_valid_p (timer_delay) && nsecs >= 0)
            {
-             if (EMACS_TIME_LT (timer_delay, timeout))
+             if (timespec_cmp (timer_delay, timeout) < 0)
                {
                  timeout = timer_delay;
                  timeout_reduced_for_timers = 1;
@@ -6759,7 +6754,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          if (xerrno == EINTR)
            FD_ZERO (&waitchannels);
          else
-           error ("select error: %s", emacs_strerror (xerrno));
+           report_file_errno ("Failed select", Qnil, xerrno);
        }
 
       /* Check for keyboard input */
@@ -6825,16 +6820,9 @@ void
 delete_keyboard_wait_descriptor (int desc)
 {
 #ifdef subprocesses
-  int fd;
-  int lim = max_input_desc;
-
   FD_CLR (desc, &input_wait_mask);
   FD_CLR (desc, &non_process_wait_mask);
-
-  if (desc == max_input_desc)
-    for (fd = 0; fd < lim; fd++)
-      if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
-        max_input_desc = fd;
+  delete_input_desc (desc);
 #endif
 }
 
@@ -6882,12 +6870,9 @@ BUFFER may be a buffer or the name of one.  */)
   buf = Fget_buffer (buffer);
   if (NILP (buf)) return Qnil;
 
-  for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
-    {
-      proc = Fcdr (XCAR (tail));
-      if (PROCESSP (proc) && EQ (XPROCESS (proc)->buffer, buf))
-       return proc;
-    }
+  FOR_EACH_PROCESS (tail, proc)
+    if (EQ (XPROCESS (proc)->buffer, buf))
+      return proc;
 #endif /* subprocesses */
   return Qnil;
 }
@@ -6920,18 +6905,14 @@ kill_buffer_processes (Lisp_Object buffer)
 #ifdef subprocesses
   Lisp_Object tail, proc;
 
-  for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
-    {
-      proc = XCDR (XCAR (tail));
-      if (PROCESSP (proc)
-         && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
-       {
-         if (NETCONN_P (proc) || SERIALCONN_P (proc))
-           Fdelete_process (proc);
-         else if (XPROCESS (proc)->infd >= 0)
-           process_send_signal (proc, SIGHUP, Qnil, 1);
-       }
-    }
+  FOR_EACH_PROCESS (tail, proc)
+    if (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer))
+      {
+       if (NETCONN_P (proc) || SERIALCONN_P (proc))
+         Fdelete_process (proc);
+       else if (XPROCESS (proc)->infd >= 0)
+         process_send_signal (proc, SIGHUP, Qnil, 1);
+      }
 #else  /* subprocesses */
   /* Since we have no subprocesses, this does nothing.  */
 #endif /* subprocesses */
@@ -7099,7 +7080,7 @@ init_process_emacs (void)
   FD_ZERO (&non_keyboard_wait_mask);
   FD_ZERO (&non_process_wait_mask);
   FD_ZERO (&write_mask);
-  max_process_desc = 0;
+  max_process_desc = max_input_desc = -1;
   memset (fd_callback_info, 0, sizeof (fd_callback_info));
 
 #ifdef NON_BLOCKING_CONNECT
@@ -7121,7 +7102,7 @@ init_process_emacs (void)
 
   Vprocess_alist = Qnil;
   deleted_pid_list = Qnil;
-  for (i = 0; i < MAXDESC; i++)
+  for (i = 0; i < FD_SETSIZE; i++)
     {
       chan_process[i] = Qnil;
       proc_buffered_char[i] = -1;
@@ -7349,14 +7330,8 @@ The variable takes effect when `start-process' is called.  */);
   defsubr (&Sset_network_process_option);
   defsubr (&Smake_network_process);
   defsubr (&Sformat_network_address);
-#if defined (HAVE_NET_IF_H)
-#ifdef SIOCGIFCONF
   defsubr (&Snetwork_interface_list);
-#endif
-#if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS)
   defsubr (&Snetwork_interface_info);
-#endif
-#endif /* defined (HAVE_NET_IF_H) */
 #ifdef DATAGRAM_SOCKETS
   defsubr (&Sprocess_datagram_address);
   defsubr (&Sset_process_datagram_address);