]> code.delx.au - gnu-emacs/blobdiff - src/process.c
Fix removal of variables from process-environment
[gnu-emacs] / src / process.c
index 1d935ba8a3ec853ffc75ae53259b1aa862e6360d..14d7b6df1c32f730216dad4838a8d0417e62cea6 100644 (file)
@@ -1,14 +1,14 @@
 /* Asynchronous subprocess control for GNU Emacs.
 
-Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2015 Free Software
+Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2016 Free Software
 Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -103,13 +103,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "coding.h"
 #include "process.h"
 #include "frame.h"
-#include "termhooks.h"
 #include "termopts.h"
-#include "commands.h"
 #include "keyboard.h"
 #include "blockinput.h"
-#include "dispextern.h"
-#include "composite.h"
 #include "atimer.h"
 #include "sysselect.h"
 #include "syssignal.h"
@@ -136,8 +132,8 @@ extern int sys_select (int, fd_set *, fd_set *, fd_set *,
 
 /* 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)
+   This bug appears to be fixed in GCC 5.1, so don't work around it there.  */
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 3
 # pragma GCC diagnostic ignored "-Wstrict-overflow"
 #endif
 \f
@@ -189,30 +185,23 @@ process_socket (int domain, int type, int protocol)
 #define NETCONN1_P(p) (EQ (p->type, Qnetwork))
 #define SERIALCONN_P(p) (EQ (XPROCESS (p)->type, Qserial))
 #define SERIALCONN1_P(p) (EQ (p->type, Qserial))
+#define PIPECONN_P(p) (EQ (XPROCESS (p)->type, Qpipe))
+#define PIPECONN1_P(p) (EQ (p->type, Qpipe))
 
 /* Number of events of change of status of a process.  */
 static EMACS_INT process_tick;
 /* Number of events for which the user or sentinel has been notified.  */
 static EMACS_INT update_tick;
 
-/* Define NON_BLOCKING_CONNECT if we can support non-blocking connects.  */
+/* Define NON_BLOCKING_CONNECT if we can support non-blocking connects.
+   The code can be simplified by assuming NON_BLOCKING_CONNECT once
+   Emacs starts assuming POSIX 1003.1-2001 or later.  */
 
-/* Only W32 has this, it really means that select can't take write mask.  */
-#ifdef BROKEN_NON_BLOCKING_CONNECT
-#undef NON_BLOCKING_CONNECT
-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)
-#if defined (EWOULDBLOCK) || defined (EINPROGRESS)
-#define NON_BLOCKING_CONNECT
-#endif /* EWOULDBLOCK || EINPROGRESS */
-#endif /* HAVE_GETPEERNAME || GNU_LINUX */
-#endif /* HAVE_SELECT */
-#endif /* NON_BLOCKING_CONNECT */
-#endif /* BROKEN_NON_BLOCKING_CONNECT */
+#if (defined HAVE_SELECT                               \
+     && (defined GNU_LINUX || defined HAVE_GETPEERNAME)        \
+     && (defined EWOULDBLOCK || defined EINPROGRESS))
+# define NON_BLOCKING_CONNECT
+#endif
 
 /* Define DATAGRAM_SOCKETS if datagrams can be used safely on
    this system.  We need to read full packets, so we need a
@@ -231,11 +220,6 @@ enum { SELECT_CAN_DO_WRITE_MASK = true };
 # define HAVE_SEQPACKET
 #endif
 
-#if !defined (ADAPTIVE_READ_BUFFERING) && !defined (NO_ADAPTIVE_READ_BUFFERING)
-#define ADAPTIVE_READ_BUFFERING
-#endif
-
-#ifdef ADAPTIVE_READ_BUFFERING
 #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)
@@ -249,10 +233,6 @@ static int process_output_delay_count;
 
 static bool process_output_skip;
 
-#else
-#define process_output_delay_count 0
-#endif
-
 static void create_process (Lisp_Object, char **, Lisp_Object);
 #ifdef USABLE_SIGIO
 static bool keyboard_bit_set (fd_set *);
@@ -420,6 +400,11 @@ pset_write_queue (struct Lisp_Process *p, Lisp_Object val)
 {
   p->write_queue = val;
 }
+static void
+pset_stderrproc (struct Lisp_Process *p, Lisp_Object val)
+{
+  p->stderrproc = val;
+}
 
 \f
 static Lisp_Object
@@ -660,22 +645,24 @@ allocate_pty (char pty_name[PTY_NAME_SIZE])
 
        if (fd >= 0)
          {
-#ifdef PTY_OPEN
+#ifdef PTY_TTY_NAME_SPRINTF
+           PTY_TTY_NAME_SPRINTF
+#else
+           sprintf (pty_name, "/dev/tty%c%x", c, i);
+#endif /* no PTY_TTY_NAME_SPRINTF */
+
            /* 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.
+              Do this after PTY_TTY_NAME_SPRINTF, which on some platforms
+              doesn't work if the close-on-exec flag is set (Bug#20555).
               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
-           PTY_TTY_NAME_SPRINTF
-#else
-           sprintf (pty_name, "/dev/tty%c%x", c, i);
-#endif /* no PTY_TTY_NAME_SPRINTF */
+
+           /* Check to make certain that both sides are available.
+              This avoids a nasty yet stupid bug in rlogins.  */
            if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0)
              {
                emacs_close (fd);
@@ -846,7 +833,7 @@ nil, indicating the current buffer's process.  */)
   p = XPROCESS (process);
 
   p->raw_status_new = 0;
-  if (NETCONN1_P (p) || SERIALCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
     {
       pset_status (p, list2 (Qexit, make_number (0)));
       p->tick = ++process_tick;
@@ -912,7 +899,7 @@ nil, indicating the current buffer's process.  */)
   status = p->status;
   if (CONSP (status))
     status = XCAR (status);
-  if (NETCONN1_P (p) || SERIALCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
     {
       if (EQ (status, Qexit))
        status = Qclosed;
@@ -996,7 +983,7 @@ Return BUFFER.  */)
     CHECK_BUFFER (buffer);
   p = XPROCESS (process);
   pset_buffer (p, buffer);
-  if (NETCONN1_P (p) || SERIALCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
     pset_childp (p, Fplist_put (p->childp, QCbuffer, buffer));
   setup_process_coding_systems (process);
   return buffer;
@@ -1072,7 +1059,7 @@ The string argument is normally a multibyte string, except:
     }
 
   pset_filter (p, filter);
-  if (NETCONN1_P (p) || SERIALCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
     pset_childp (p, Fplist_put (p->childp, QCfilter, filter));
   setup_process_coding_systems (process);
   return filter;
@@ -1104,7 +1091,7 @@ It gets two arguments: the process, and a string describing the change.  */)
     sentinel = Qinternal_default_process_sentinel;
 
   pset_sentinel (p, sentinel);
-  if (NETCONN1_P (p) || SERIALCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p) || PIPECONN1_P (p))
     pset_childp (p, Fplist_put (p->childp, QCsentinel, sentinel));
   return sentinel;
 }
@@ -1121,7 +1108,9 @@ 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.  */)
+       doc: /* Tell PROCESS that it has logical window size WIDTH by HEIGHT.
+Value is t if PROCESS was successfully told about the window size,
+nil otherwise.  */)
   (Lisp_Object process, Lisp_Object height, Lisp_Object width)
 {
   CHECK_PROCESS (process);
@@ -1213,7 +1202,8 @@ list of keywords.  */)
                          Fprocess_datagram_address (process));
 #endif
 
-  if ((!NETCONN_P (process) && !SERIALCONN_P (process)) || EQ (key, Qt))
+  if ((!NETCONN_P (process) && !SERIALCONN_P (process) && !PIPECONN_P (process))
+      || EQ (key, Qt))
     return contact;
   if (NILP (key) && NETCONN_P (process))
     return list2 (Fplist_get (contact, QChost),
@@ -1221,6 +1211,11 @@ list of keywords.  */)
   if (NILP (key) && SERIALCONN_P (process))
     return list2 (Fplist_get (contact, QCport),
                  Fplist_get (contact, QCspeed));
+  /* FIXME: Return a meaningful value (e.g., the child end of the pipe)
+     if the pipe process is useful for purposes other than receiving
+     stderr.  */
+  if (NILP (key) && PIPECONN_P (process))
+    return Qt;
   return Fplist_get (contact, key);
 }
 
@@ -1355,61 +1350,104 @@ DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
 
 static void start_process_unwind (Lisp_Object proc);
 
-DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
+DEFUN ("make-process", Fmake_process, Smake_process, 0, MANY, 0,
        doc: /* Start a program in a subprocess.  Return the process object for it.
-NAME is name for process.  It is modified if necessary to make it unique.
-BUFFER is the buffer (or buffer name) to associate with the process.
 
-Process output (both standard output and standard error streams) goes
-at end of BUFFER, unless you specify an output stream or filter
-function to handle the output.  BUFFER may also be nil, meaning that
-this process is not associated with any buffer.
+This is similar to `start-process', but arguments are specified as
+keyword/argument pairs.  The following arguments are defined:
+
+:name NAME -- NAME is name for process.  It is modified if necessary
+to make it unique.
+
+:buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate
+with the process.  Process output goes at end of that buffer, unless
+you specify an output stream or filter function to handle the output.
+BUFFER may be also nil, meaning that this process is not associated
+with any buffer.
 
-PROGRAM is the program file name.  It is searched for in `exec-path'
-(which see).  If nil, just associate a pty with the buffer.  Remaining
-arguments are strings to give program as arguments.
+:command COMMAND -- COMMAND is a list starting with the program file
+name, followed by strings to give to the program as arguments.
 
-If you want to separate standard output from standard error, invoke
-the command through a shell and redirect one of them using the shell
-syntax.
+:coding CODING -- If CODING is a symbol, it specifies the coding
+system used for both reading and writing for this process.  If CODING
+is a cons (DECODING . ENCODING), DECODING is used for reading, and
+ENCODING is used for writing.
 
-usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
+:noquery BOOL -- When exiting Emacs, query the user if BOOL is nil and
+the process is running.  If BOOL is not given, query before exiting.
+
+:stop BOOL -- Start process in the `stopped' state if BOOL non-nil.
+In the stopped state, a process does not accept incoming data, but you
+can send outgoing data.  The stopped state is cleared by
+`continue-process' and set by `stop-process'.
+
+:connection-type TYPE -- TYPE is control type of device used to
+communicate with subprocesses.  Values are `pipe' to use a pipe, `pty'
+to use a pty, or nil to use the default specified through
+`process-connection-type'.
+
+:filter FILTER -- Install FILTER as the process filter.
+
+:sentinel SENTINEL -- Install SENTINEL as the process sentinel.
+
+:stderr STDERR -- STDERR is either a buffer or a pipe process attached
+to the standard error of subprocess.  Specifying this implies
+`:connection-type' is set to `pipe'.
+
+usage: (make-process &rest ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  Lisp_Object buffer, name, program, proc, current_dir, tem;
-  unsigned char **new_argv;
-  ptrdiff_t i;
+  Lisp_Object buffer, name, command, program, proc, contact, current_dir, tem;
+  Lisp_Object xstderr, stderrproc;
   ptrdiff_t count = SPECPDL_INDEX ();
   USE_SAFE_ALLOCA;
 
-  buffer = args[1];
+  if (nargs == 0)
+    return Qnil;
+
+  /* Save arguments for process-contact and clone-process.  */
+  contact = Flist (nargs, args);
+
+  buffer = Fplist_get (contact, QCbuffer);
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer);
 
   /* Make sure that the child will be able to chdir to the current
      buffer's current directory, or its unhandled equivalent.  We
      can't just have the child check for an error when it does the
-     chdir, since it's in a vfork.
-
-     We have to GCPRO around this because Fexpand_file_name and
-     Funhandled_file_name_directory might call a file name handling
-     function.  The argument list is protected by the caller, so all
-     we really have to worry about is buffer.  */
-  {
-    struct gcpro gcpro1;
-    GCPRO1 (buffer);
-    current_dir = encode_current_directory ();
-    UNGCPRO;
-  }
+     chdir, since it's in a vfork.  */
+  current_dir = encode_current_directory ();
 
-  name = args[0];
+  name = Fplist_get (contact, QCname);
   CHECK_STRING (name);
 
-  program = args[2];
+  command = Fplist_get (contact, QCcommand);
+  if (CONSP (command))
+    program = XCAR (command);
+  else
+    program = Qnil;
 
   if (!NILP (program))
     CHECK_STRING (program);
 
+  stderrproc = Qnil;
+  xstderr = Fplist_get (contact, QCstderr);
+  if (PROCESSP (xstderr))
+    {
+      if (!PIPECONN_P (xstderr))
+       error ("Process is not a pipe process");
+      stderrproc = xstderr;
+    }
+  else if (!NILP (xstderr))
+    {
+      CHECK_STRING (program);
+      stderrproc = CALLN (Fmake_pipe_process,
+                         QCname,
+                         concat2 (name, build_string (" stderr")),
+                         QCbuffer,
+                         Fget_buffer_create (xstderr));
+    }
+
   proc = make_process (name);
   /* If an error occurs and we can't start the process, we want to
      remove it from the process list.  This means that each error
@@ -1421,9 +1459,31 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
   pset_plist (XPROCESS (proc), Qnil);
   pset_type (XPROCESS (proc), Qreal);
   pset_buffer (XPROCESS (proc), buffer);
-  pset_sentinel (XPROCESS (proc), Qinternal_default_process_sentinel);
-  pset_filter (XPROCESS (proc), Qinternal_default_process_filter);
-  pset_command (XPROCESS (proc), Flist (nargs - 2, args + 2));
+  pset_sentinel (XPROCESS (proc), Fplist_get (contact, QCsentinel));
+  pset_filter (XPROCESS (proc), Fplist_get (contact, QCfilter));
+  pset_command (XPROCESS (proc), Fcopy_sequence (command));
+
+  if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
+    XPROCESS (proc)->kill_without_query = 1;
+  if (tem = Fplist_get (contact, QCstop), !NILP (tem))
+    pset_command (XPROCESS (proc), Qt);
+
+  tem = Fplist_get (contact, QCconnection_type);
+  if (EQ (tem, Qpty))
+    XPROCESS (proc)->pty_flag = true;
+  else if (EQ (tem, Qpipe))
+    XPROCESS (proc)->pty_flag = false;
+  else if (NILP (tem))
+    XPROCESS (proc)->pty_flag = !NILP (Vprocess_connection_type);
+  else
+    report_file_error ("Unknown connection type", tem);
+
+  if (!NILP (stderrproc))
+    {
+      pset_stderrproc (XPROCESS (proc), stderrproc);
+
+      XPROCESS (proc)->pty_flag = false;
+    }
 
 #ifdef HAVE_GNUTLS
   /* AKA GNUTLS_INITSTAGE(proc).  */
@@ -1431,11 +1491,9 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
   pset_gnutls_cred_type (XPROCESS (proc), Qnil);
 #endif
 
-#ifdef ADAPTIVE_READ_BUFFERING
   XPROCESS (proc)->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
        : EQ (Vprocess_adaptive_read_buffering, Qt) ? 1 : 2);
-#endif
 
   /* Make the process marker point into the process buffer (if any).  */
   if (BUFFERP (buffer))
@@ -1451,18 +1509,29 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
     /* Qt denotes we have not yet called Ffind_operation_coding_system.  */
     Lisp_Object coding_systems = Qt;
     Lisp_Object val, *args2;
-    struct gcpro gcpro1, gcpro2;
 
-    val = Vcoding_system_for_read;
+    tem = Fplist_get (contact, QCcoding);
+    if (!NILP (tem))
+      {
+       val = tem;
+       if (CONSP (val))
+         val = XCAR (val);
+      }
+    else
+      val = Vcoding_system_for_read;
     if (NILP (val))
       {
-       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);
+       ptrdiff_t nargs2 = 3 + XINT (Flength (command));
+       Lisp_Object tem2;
+       SAFE_ALLOCA_LISP (args2, nargs2);
+       ptrdiff_t i = 0;
+       args2[i++] = Qstart_process;
+       args2[i++] = name;
+       args2[i++] = buffer;
+       for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
+         args2[i++] = XCAR (tem2);
        if (!NILP (program))
-         coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
-       UNGCPRO;
+         coding_systems = Ffind_operation_coding_system (nargs2, args2);
        if (CONSP (coding_systems))
          val = XCAR (coding_systems);
        else if (CONSP (Vdefault_process_coding_system))
@@ -1470,18 +1539,29 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
       }
     pset_decode_coding_system (XPROCESS (proc), val);
 
-    val = Vcoding_system_for_write;
+    if (!NILP (tem))
+      {
+       val = tem;
+       if (CONSP (val))
+         val = XCDR (val);
+      }
+    else
+      val = Vcoding_system_for_write;
     if (NILP (val))
       {
        if (EQ (coding_systems, Qt))
          {
-           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);
+           ptrdiff_t nargs2 = 3 + XINT (Flength (command));
+           Lisp_Object tem2;
+           SAFE_ALLOCA_LISP (args2, nargs2);
+           ptrdiff_t i = 0;
+           args2[i++] = Qstart_process;
+           args2[i++] = name;
+           args2[i++] = buffer;
+           for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
+             args2[i++] = XCAR (tem2);
            if (!NILP (program))
-             coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
-           UNGCPRO;
+             coding_systems = Ffind_operation_coding_system (nargs2, args2);
          }
        if (CONSP (coding_systems))
          val = XCDR (coding_systems);
@@ -1506,19 +1586,17 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
 
   if (!NILP (program))
     {
+      Lisp_Object program_args = XCDR (command);
+
       /* If program file name is not absolute, search our path for it.
         Put the name we will really use in TEM.  */
       if (!IS_DIRECTORY_SEP (SREF (program, 0))
          && !(SCHARS (program) > 1
               && IS_DEVICE_SEP (SREF (program, 1))))
        {
-         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-
          tem = Qnil;
-         GCPRO4 (name, program, buffer, current_dir);
          openp (Vexec_path, program, Vexec_suffixes, &tem,
                 make_number (X_OK), false);
-         UNGCPRO;
          if (NILP (tem))
            report_file_error ("Searching for program", program);
          tem = Fexpand_file_name (tem, Qnil);
@@ -1533,50 +1611,46 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
       /* Remove "/:" from TEM.  */
       tem = remove_slash_colon (tem);
 
-      {
-       Lisp_Object arg_encoding = Qnil;
-       struct gcpro gcpro1;
-       GCPRO1 (tem);
-
-       /* Encode the file name and put it in NEW_ARGV.
-          That's where the child will use it to execute the program.  */
-       tem = list1 (ENCODE_FILE (tem));
+      Lisp_Object arg_encoding = Qnil;
 
-       /* Here we encode arguments by the coding system used for sending
-          data to the process.  We don't support using different coding
-          systems for encoding arguments and for encoding data sent to the
-          process.  */
+      /* Encode the file name and put it in NEW_ARGV.
+        That's where the child will use it to execute the program.  */
+      tem = list1 (ENCODE_FILE (tem));
+      ptrdiff_t new_argc = 1;
 
-       for (i = 3; i < nargs; i++)
-         {
-           tem = Fcons (args[i], tem);
-           CHECK_STRING (XCAR (tem));
-           if (STRING_MULTIBYTE (XCAR (tem)))
-             {
-               if (NILP (arg_encoding))
-                 arg_encoding = (complement_process_encoding_system
-                                 (XPROCESS (proc)->encode_coding_system));
-               XSETCAR (tem,
-                        code_convert_string_norecord
-                        (XCAR (tem), arg_encoding, 1));
-             }
-         }
+      /* Here we encode arguments by the coding system used for sending
+        data to the process.  We don't support using different coding
+        systems for encoding arguments and for encoding data sent to the
+        process.  */
 
-       UNGCPRO;
-      }
+      for (Lisp_Object tem2 = program_args; CONSP (tem2); tem2 = XCDR (tem2))
+       {
+         Lisp_Object arg = XCAR (tem2);
+         CHECK_STRING (arg);
+         if (STRING_MULTIBYTE (arg))
+           {
+             if (NILP (arg_encoding))
+               arg_encoding = (complement_process_encoding_system
+                               (XPROCESS (proc)->encode_coding_system));
+             arg = code_convert_string_norecord (arg, arg_encoding, 1);
+           }
+         tem = Fcons (arg, tem);
+         new_argc++;
+       }
 
       /* Now that everything is encoded we can collect the strings into
         NEW_ARGV.  */
-      SAFE_NALLOCA (new_argv, 1, nargs - 1);
-      new_argv[nargs - 2] = 0;
+      char **new_argv;
+      SAFE_NALLOCA (new_argv, 1, new_argc + 1);
+      new_argv[new_argc] = 0;
 
-      for (i = nargs - 2; i-- != 0; )
+      for (ptrdiff_t i = new_argc - 1; i >= 0; i--)
        {
-         new_argv[i] = SDATA (XCAR (tem));
+         new_argv[i] = SSDATA (XCAR (tem));
          tem = XCDR (tem);
        }
 
-      create_process (proc, (char **) new_argv, current_dir);
+      create_process (proc, new_argv, current_dir);
     }
   else
     create_pty (proc);
@@ -1640,7 +1714,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
   int inchannel, outchannel;
   pid_t pid;
   int vfork_errno;
-  int forkin, forkout;
+  int forkin, forkout, forkerr = -1;
   bool pty_flag = 0;
   char pty_name[PTY_NAME_SIZE];
   Lisp_Object lisp_pty_name = Qnil;
@@ -1648,7 +1722,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 
   inchannel = outchannel = -1;
 
-  if (!NILP (Vprocess_connection_type))
+  if (p->pty_flag)
     outchannel = inchannel = allocate_pty (pty_name);
 
   if (inchannel >= 0)
@@ -1678,6 +1752,17 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       outchannel = p->open_fd[WRITE_TO_SUBPROCESS];
       inchannel = p->open_fd[READ_FROM_SUBPROCESS];
       forkout = p->open_fd[SUBPROCESS_STDOUT];
+
+      if (!NILP (p->stderrproc))
+       {
+         struct Lisp_Process *pp = XPROCESS (p->stderrproc);
+
+         forkerr = pp->open_fd[SUBPROCESS_STDOUT];
+
+         /* Close unnecessary file descriptors.  */
+         close_process_fd (&pp->open_fd[WRITE_TO_SUBPROCESS]);
+         close_process_fd (&pp->open_fd[SUBPROCESS_STDIN]);
+       }
     }
 
 #ifndef WINDOWSNT
@@ -1701,8 +1786,12 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
   p->pty_flag = pty_flag;
   pset_status (p, Qrun);
 
-  FD_SET (inchannel, &input_wait_mask);
-  FD_SET (inchannel, &non_keyboard_wait_mask);
+  if (!EQ (p->command, Qt))
+    {
+      FD_SET (inchannel, &input_wait_mask);
+      FD_SET (inchannel, &non_keyboard_wait_mask);
+    }
+
   if (inchannel > max_process_desc)
     max_process_desc = inchannel;
 
@@ -1714,32 +1803,29 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 
 #ifndef WINDOWSNT
   /* vfork, and prevent local vars from being clobbered by the vfork.  */
-  {
-    Lisp_Object volatile current_dir_volatile = current_dir;
-    Lisp_Object volatile lisp_pty_name_volatile = lisp_pty_name;
-    char **volatile new_argv_volatile = new_argv;
-    int volatile forkin_volatile = forkin;
-    int volatile forkout_volatile = forkout;
-    struct Lisp_Process *p_volatile = p;
-
-    pid = vfork ();
-
-    current_dir = current_dir_volatile;
-    lisp_pty_name = lisp_pty_name_volatile;
-    new_argv = new_argv_volatile;
-    forkin = forkin_volatile;
-    forkout = forkout_volatile;
-    p = p_volatile;
-
-    pty_flag = p->pty_flag;
-  }
+  Lisp_Object volatile current_dir_volatile = current_dir;
+  Lisp_Object volatile lisp_pty_name_volatile = lisp_pty_name;
+  char **volatile new_argv_volatile = new_argv;
+  int volatile forkin_volatile = forkin;
+  int volatile forkout_volatile = forkout;
+  int volatile forkerr_volatile = forkerr;
+  struct Lisp_Process *p_volatile = p;
+
+  pid = vfork ();
+
+  current_dir = current_dir_volatile;
+  lisp_pty_name = lisp_pty_name_volatile;
+  new_argv = new_argv_volatile;
+  forkin = forkin_volatile;
+  forkout = forkout_volatile;
+  forkerr = forkerr_volatile;
+  p = p_volatile;
+
+  pty_flag = p->pty_flag;
 
   if (pid == 0)
 #endif /* not WINDOWSNT */
     {
-      int xforkin = forkin;
-      int xforkout = forkout;
-
       /* Make the pty be the controlling terminal of the process.  */
 #ifdef HAVE_PTYS
       /* First, disconnect its current controlling terminal.  */
@@ -1747,30 +1833,30 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
         process_set_signal to fail on SGI when using a pipe.  */
       setsid ();
       /* Make the pty's terminal the controlling terminal.  */
-      if (pty_flag && xforkin >= 0)
+      if (pty_flag && forkin >= 0)
        {
 #ifdef TIOCSCTTY
          /* We ignore the return value
             because faith@cs.unc.edu says that is necessary on Linux.  */
-         ioctl (xforkin, TIOCSCTTY, 0);
+         ioctl (forkin, TIOCSCTTY, 0);
 #endif
        }
 #if defined (LDISC1)
-      if (pty_flag && xforkin >= 0)
+      if (pty_flag && forkin >= 0)
        {
          struct termios t;
-         tcgetattr (xforkin, &t);
+         tcgetattr (forkin, &t);
          t.c_lflag = LDISC1;
-         if (tcsetattr (xforkin, TCSANOW, &t) < 0)
+         if (tcsetattr (forkin, TCSANOW, &t) < 0)
            emacs_perror ("create_process/tcsetattr LDISC1");
        }
 #else
 #if defined (NTTYDISC) && defined (TIOCSETD)
-      if (pty_flag && xforkin >= 0)
+      if (pty_flag && forkin >= 0)
        {
          /* Use new line discipline.  */
          int ldisc = NTTYDISC;
-         ioctl (xforkin, TIOCSETD, &ldisc);
+         ioctl (forkin, TIOCSETD, &ldisc);
        }
 #endif
 #endif
@@ -1803,11 +1889,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
 
          /* I wonder if emacs_close (emacs_open (SSDATA (lisp_pty_name), ...))
             would work?  */
-         if (xforkin >= 0)
-           emacs_close (xforkin);
-         xforkout = xforkin = emacs_open (SSDATA (lisp_pty_name), O_RDWR, 0);
+         if (forkin >= 0)
+           emacs_close (forkin);
+         forkout = forkin = emacs_open (SSDATA (lisp_pty_name), O_RDWR, 0);
 
-         if (xforkin < 0)
+         if (forkin < 0)
            {
              emacs_perror (SSDATA (lisp_pty_name));
              _exit (EXIT_CANCELED);
@@ -1837,11 +1923,14 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       unblock_child_signal (&oldset);
 
       if (pty_flag)
-       child_setup_tty (xforkout);
+       child_setup_tty (forkout);
+
+      if (forkerr < 0)
+       forkerr = forkout;
 #ifdef WINDOWSNT
-      pid = child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir);
+      pid = child_setup (forkin, forkout, forkerr, new_argv, 1, current_dir);
 #else  /* not WINDOWSNT */
-      child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir);
+      child_setup (forkin, forkout, forkerr, new_argv, 1, current_dir);
 #endif /* not WINDOWSNT */
     }
 
@@ -1886,6 +1975,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
        close_process_fd (&p->open_fd[READ_FROM_EXEC_MONITOR]);
       }
 #endif
+      if (!NILP (p->stderrproc))
+       {
+         struct Lisp_Process *pp = XPROCESS (p->stderrproc);
+         close_process_fd (&pp->open_fd[SUBPROCESS_STDOUT]);
+       }
     }
 }
 
@@ -1894,7 +1988,7 @@ create_pty (Lisp_Object process)
 {
   struct Lisp_Process *p = XPROCESS (process);
   char pty_name[PTY_NAME_SIZE];
-  int pty_fd = NILP (Vprocess_connection_type) ? -1 : allocate_pty (pty_name);
+  int pty_fd = !p->pty_flag ? -1 : allocate_pty (pty_name);
 
   if (pty_fd >= 0)
     {
@@ -1944,6 +2038,182 @@ create_pty (Lisp_Object process)
   p->pid = -2;
 }
 
+DEFUN ("make-pipe-process", Fmake_pipe_process, Smake_pipe_process,
+       0, MANY, 0,
+       doc: /* Create and return a bidirectional pipe process.
+
+In Emacs, pipes are represented by process objects, so input and
+output work as for subprocesses, and `delete-process' closes a pipe.
+However, a pipe process has no process id, it cannot be signaled,
+and the status codes are different from normal processes.
+
+Arguments are specified as keyword/argument pairs.  The following
+arguments are defined:
+
+:name NAME -- NAME is the name of the process.  It is modified if necessary to make it unique.
+
+:buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate
+with the process.  Process output goes at the end of that buffer,
+unless you specify an output stream or filter function to handle the
+output.  If BUFFER is not given, the value of NAME is used.
+
+:coding CODING -- If CODING is a symbol, it specifies the coding
+system used for both reading and writing for this process.  If CODING
+is a cons (DECODING . ENCODING), DECODING is used for reading, and
+ENCODING is used for writing.
+
+:noquery BOOL -- When exiting Emacs, query the user if BOOL is nil and
+the process is running.  If BOOL is not given, query before exiting.
+
+:stop BOOL -- Start process in the `stopped' state if BOOL non-nil.
+In the stopped state, a pipe process does not accept incoming data,
+but you can send outgoing data.  The stopped state is cleared by
+`continue-process' and set by `stop-process'.
+
+:filter FILTER -- Install FILTER as the process filter.
+
+:sentinel SENTINEL -- Install SENTINEL as the process sentinel.
+
+usage:  (make-pipe-process &rest ARGS)  */)
+  (ptrdiff_t nargs, Lisp_Object *args)
+{
+  Lisp_Object proc, contact;
+  struct Lisp_Process *p;
+  Lisp_Object name, buffer;
+  Lisp_Object tem;
+  ptrdiff_t specpdl_count;
+  int inchannel, outchannel;
+
+  if (nargs == 0)
+    return Qnil;
+
+  contact = Flist (nargs, args);
+
+  name = Fplist_get (contact, QCname);
+  CHECK_STRING (name);
+  proc = make_process (name);
+  specpdl_count = SPECPDL_INDEX ();
+  record_unwind_protect (remove_process, proc);
+  p = XPROCESS (proc);
+
+  if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0
+      || emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0)
+    report_file_error ("Creating pipe", Qnil);
+  outchannel = p->open_fd[WRITE_TO_SUBPROCESS];
+  inchannel = p->open_fd[READ_FROM_SUBPROCESS];
+
+  fcntl (inchannel, F_SETFL, O_NONBLOCK);
+  fcntl (outchannel, F_SETFL, O_NONBLOCK);
+
+#ifdef WINDOWSNT
+  register_aux_fd (inchannel);
+#endif
+
+  /* Record this as an active process, with its channels.  */
+  chan_process[inchannel] = proc;
+  p->infd = inchannel;
+  p->outfd = outchannel;
+
+  if (inchannel > max_process_desc)
+    max_process_desc = inchannel;
+
+  buffer = Fplist_get (contact, QCbuffer);
+  if (NILP (buffer))
+    buffer = name;
+  buffer = Fget_buffer_create (buffer);
+  pset_buffer (p, buffer);
+
+  pset_childp (p, contact);
+  pset_plist (p, Fcopy_sequence (Fplist_get (contact, QCplist)));
+  pset_type (p, Qpipe);
+  pset_sentinel (p, Fplist_get (contact, QCsentinel));
+  pset_filter (p, Fplist_get (contact, QCfilter));
+  pset_log (p, Qnil);
+  if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
+    p->kill_without_query = 1;
+  if (tem = Fplist_get (contact, QCstop), !NILP (tem))
+    pset_command (p, Qt);
+  eassert (! p->pty_flag);
+
+  if (!EQ (p->command, Qt))
+    {
+      FD_SET (inchannel, &input_wait_mask);
+      FD_SET (inchannel, &non_keyboard_wait_mask);
+    }
+  p->adaptive_read_buffering
+    = (NILP (Vprocess_adaptive_read_buffering) ? 0
+       : EQ (Vprocess_adaptive_read_buffering, Qt) ? 1 : 2);
+
+  /* Make the process marker point into the process buffer (if any).  */
+  if (BUFFERP (buffer))
+    set_marker_both (p->mark, buffer,
+                    BUF_ZV (XBUFFER (buffer)),
+                    BUF_ZV_BYTE (XBUFFER (buffer)));
+
+  {
+    /* Setup coding systems for communicating with the network stream.  */
+
+    /* Qt denotes we have not yet called Ffind_operation_coding_system.  */
+    Lisp_Object coding_systems = Qt;
+    Lisp_Object val;
+
+    tem = Fplist_get (contact, QCcoding);
+    val = Qnil;
+    if (!NILP (tem))
+      {
+       val = tem;
+       if (CONSP (val))
+         val = XCAR (val);
+      }
+    else if (!NILP (Vcoding_system_for_read))
+      val = Vcoding_system_for_read;
+    else if ((!NILP (buffer) && NILP (BVAR (XBUFFER (buffer), enable_multibyte_characters)))
+            || (NILP (buffer) && NILP (BVAR (&buffer_defaults, enable_multibyte_characters))))
+      /* We dare not decode end-of-line format by setting VAL to
+        Qraw_text, because the existing Emacs Lisp libraries
+        assume that they receive bare code including a sequence of
+        CR LF.  */
+      val = Qnil;
+    else
+      {
+       if (CONSP (coding_systems))
+         val = XCAR (coding_systems);
+       else if (CONSP (Vdefault_process_coding_system))
+         val = XCAR (Vdefault_process_coding_system);
+       else
+         val = Qnil;
+      }
+    pset_decode_coding_system (p, val);
+
+    if (!NILP (tem))
+      {
+       val = tem;
+       if (CONSP (val))
+         val = XCDR (val);
+      }
+    else if (!NILP (Vcoding_system_for_write))
+      val = Vcoding_system_for_write;
+    else if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
+      val = Qnil;
+    else
+      {
+       if (CONSP (coding_systems))
+         val = XCDR (coding_systems);
+       else if (CONSP (Vdefault_process_coding_system))
+         val = XCDR (Vdefault_process_coding_system);
+       else
+         val = Qnil;
+      }
+    pset_encode_coding_system (p, val);
+  }
+  /* This may signal an error.  */
+  setup_process_coding_systems (proc);
+
+  specpdl_ptr = specpdl + specpdl_count;
+
+  return proc;
+}
+
 \f
 /* Convert an internal struct sockaddr to a lisp object (vector or string).
    The address family of sa is not included in the result.  */
@@ -2104,7 +2374,7 @@ conv_lisp_to_sockaddr (int family, Lisp_Object address, struct sockaddr *sa, int
        {
          struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
          uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr;
-         len = sizeof (sin6->sin6_addr) + 1;
+         len = sizeof (sin6->sin6_addr) / 2 + 1;
          hostport = XINT (p->contents[--len]);
          sin6->sin6_port = htons (hostport);
          for (i = 0; i < len; i++)
@@ -2413,7 +2683,7 @@ Examples:
 \(serial-process-configure :process "/dev/ttyS0" :speed 1200)
 
 \(serial-process-configure
-    :buffer "COM1" :stopbits 1 :parity 'odd :flowcontrol 'hw)
+    :buffer "COM1" :stopbits 1 :parity \\='odd :flowcontrol \\='hw)
 
 \(serial-process-configure :port "\\\\.\\COM13" :bytesize 7)
 
@@ -2423,10 +2693,8 @@ usage: (serial-process-configure &rest ARGS)  */)
   struct Lisp_Process *p;
   Lisp_Object contact = Qnil;
   Lisp_Object proc = Qnil;
-  struct gcpro gcpro1;
 
   contact = Flist (nargs, args);
-  GCPRO1 (contact);
 
   proc = Fplist_get (contact, QCprocess);
   if (NILP (proc))
@@ -2441,14 +2709,9 @@ usage: (serial-process-configure &rest ARGS)  */)
     error ("Not a serial process");
 
   if (NILP (Fplist_get (p->childp, QCspeed)))
-    {
-      UNGCPRO;
-      return Qnil;
-    }
+    return Qnil;
 
   serial_configure (p, contact);
-
-  UNGCPRO;
   return Qnil;
 }
 
@@ -2520,7 +2783,7 @@ Examples:
 
 \(make-serial-process :port "COM1" :speed 115200 :stopbits 2)
 
-\(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity 'odd)
+\(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity \\='odd)
 
 \(make-serial-process :port "/dev/tty.BlueConsole-SPP-1" :speed nil)
 
@@ -2530,7 +2793,6 @@ usage:  (make-serial-process &rest ARGS)  */)
   int fd = -1;
   Lisp_Object proc, contact, port;
   struct Lisp_Process *p;
-  struct gcpro gcpro1;
   Lisp_Object name, buffer;
   Lisp_Object tem, val;
   ptrdiff_t specpdl_count;
@@ -2539,7 +2801,6 @@ usage:  (make-serial-process &rest ARGS)  */)
     return Qnil;
 
   contact = Flist (nargs, args);
-  GCPRO1 (contact);
 
   port = Fplist_get (contact, QCport);
   if (NILP (port))
@@ -2642,7 +2903,6 @@ usage:  (make-serial-process &rest ARGS)  */)
 
   specpdl_ptr = specpdl + specpdl_count;
 
-  UNGCPRO;
   return proc;
 }
 
@@ -2833,7 +3093,6 @@ usage: (make-network-process &rest ARGS)  */)
   int ret = 0;
   int xerrno = 0;
   int s = -1, outch, inch;
-  struct gcpro gcpro1;
   ptrdiff_t count = SPECPDL_INDEX ();
   ptrdiff_t count1;
   Lisp_Object colon_address;  /* Either QClocal or QCremote.  */
@@ -2851,7 +3110,6 @@ usage: (make-network-process &rest ARGS)  */)
 
   /* Save arguments for process-contact and clone-process.  */
   contact = Flist (nargs, args);
-  GCPRO1 (contact);
 
 #ifdef WINDOWSNT
   /* Ensure socket support is loaded if available.  */
@@ -2971,8 +3229,7 @@ usage: (make-network-process &rest ARGS)  */)
     {
       if (!NILP (host))
        {
-         message (":family local ignores the :host \"%s\" property",
-                  SDATA (host));
+         message (":family local ignores the :host property");
          contact = Fplist_put (contact, QChost, Qnil);
          host = Qnil;
        }
@@ -3419,7 +3676,6 @@ usage: (make-network-process &rest ARGS)  */)
 
   {
     /* Setup coding systems for communicating with the network stream.  */
-    struct gcpro gcpro1;
     /* Qt denotes we have not yet called Ffind_operation_coding_system.  */
     Lisp_Object coding_systems = Qt;
     Lisp_Object val;
@@ -3444,13 +3700,9 @@ usage: (make-network-process &rest ARGS)  */)
        if (NILP (host) || NILP (service))
          coding_systems = Qnil;
        else
-         {
-           GCPRO1 (proc);
-           coding_systems = CALLN (Ffind_operation_coding_system,
-                                   Qopen_network_stream, name, buffer,
-                                   host, service);
-           UNGCPRO;
-         }
+         coding_systems = CALLN (Ffind_operation_coding_system,
+                                 Qopen_network_stream, name, buffer,
+                                 host, service);
        if (CONSP (coding_systems))
          val = XCAR (coding_systems);
        else if (CONSP (Vdefault_process_coding_system))
@@ -3477,13 +3729,9 @@ usage: (make-network-process &rest ARGS)  */)
            if (NILP (host) || NILP (service))
              coding_systems = Qnil;
            else
-             {
-               GCPRO1 (proc);
-               coding_systems = CALLN (Ffind_operation_coding_system,
-                                       Qopen_network_stream, name, buffer,
-                                       host, service);
-               UNGCPRO;
-             }
+             coding_systems = CALLN (Ffind_operation_coding_system,
+                                     Qopen_network_stream, name, buffer,
+                                     host, service);
          }
        if (CONSP (coding_systems))
          val = XCDR (coding_systems);
@@ -3503,7 +3751,6 @@ usage: (make-network-process &rest ARGS)  */)
   p->inherit_coding_system_flag
     = !(!NILP (tem) || NILP (buffer) || !inherit_process_coding_system);
 
-  UNGCPRO;
   return proc;
 }
 
@@ -3840,19 +4087,6 @@ Data that is unavailable is returned as nil.  */)
 #endif
 }
 
-/* If program file NAME starts with /: for quoting a magic
-   name, remove that, preserving the multibyteness of NAME.  */
-
-Lisp_Object
-remove_slash_colon (Lisp_Object name)
-{
-  return
-    ((SBYTES (name) > 2 && SREF (name, 0) == '/' && SREF (name, 1) == ':')
-     ? make_specified_string (SSDATA (name) + 2, SCHARS (name) - 2,
-                             SBYTES (name) - 2, STRING_MULTIBYTE (name))
-     : name);
-}
-
 /* Turn off input and output for process PROC.  */
 
 static void
@@ -3867,7 +4101,6 @@ deactivate_process (Lisp_Object proc)
   emacs_gnutls_deinit (proc);
 #endif /* HAVE_GNUTLS */
 
-#ifdef ADAPTIVE_READ_BUFFERING
   if (p->read_output_delay > 0)
     {
       if (--process_output_delay_count < 0)
@@ -3875,7 +4108,6 @@ deactivate_process (Lisp_Object proc)
       p->read_output_delay = 0;
       p->read_output_skip = 0;
     }
-#endif
 
   /* Beware SIGCHLD hereabouts.  */
 
@@ -4284,10 +4516,15 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
   bool no_avail;
   int xerrno;
   Lisp_Object proc;
-  struct timespec timeout, end_time;
-  int got_some_input = -1;
+  struct timespec timeout, end_time, timer_delay;
+  struct timespec got_output_end_time = invalid_timespec ();
+  enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
+  int got_some_output = -1;
   ptrdiff_t count = SPECPDL_INDEX ();
 
+  /* Close to the current time if known, an invalid timespec otherwise.  */
+  struct timespec now = invalid_timespec ();
+
   FD_ZERO (&Available);
   FD_ZERO (&Writeok);
 
@@ -4300,25 +4537,23 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                             waiting_for_user_input_p);
   waiting_for_user_input_p = read_kbd;
 
-  if (time_limit < 0)
-    {
-      time_limit = 0;
-      nsecs = -1;
-    }
-  else if (TYPE_MAXIMUM (time_t) < time_limit)
+  if (TYPE_MAXIMUM (time_t) < time_limit)
     time_limit = TYPE_MAXIMUM (time_t);
 
-  /* Since we may need to wait several times,
-     compute the absolute time to return at.  */
-  if (time_limit || nsecs > 0)
+  if (time_limit < 0 || nsecs < 0)
+    wait = MINIMUM;
+  else if (time_limit > 0 || nsecs > 0)
     {
-      timeout = make_timespec (time_limit, nsecs);
-      end_time = timespec_add (current_timespec (), timeout);
+      wait = TIMEOUT;
+      now = current_timespec ();
+      end_time = timespec_add (now, make_timespec (time_limit, nsecs));
     }
+  else
+    wait = INFINITY;
 
   while (1)
     {
-      bool timeout_reduced_for_timers = false;
+      bool process_skipped = false;
 
       /* If calling from keyboard input, do not quit
         since we want to return C-g as an input character.
@@ -4332,31 +4567,18 @@ 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)
+      if (wait == TIMEOUT)
        {
-         /* A negative timeout means
-            gobble output available now
-            but don't wait at all.  */
-
-         timeout = make_timespec (0, 0);
-       }
-      else if (time_limit || nsecs > 0)
-       {
-         struct timespec now = current_timespec ();
+         if (!timespec_valid_p (now))
+           now = current_timespec ();
          if (timespec_cmp (end_time, now) <= 0)
            break;
          timeout = timespec_sub (end_time, now);
        }
       else
-       {
-         timeout = make_timespec (100000, 0);
-       }
+       timeout = make_timespec (wait < TIMEOUT ? 0 : 100000, 0);
 
       /* Normally we run timers here.
         But not if wait_for_cell; in those cases,
@@ -4365,8 +4587,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       if (NILP (wait_for_cell)
          && just_wait_proc >= 0)
        {
-         struct timespec timer_delay;
-
          do
            {
              unsigned old_timers_run = timers_run;
@@ -4397,24 +4617,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              && requeued_events_pending_p ())
            break;
 
-         /* A negative timeout means do not wait at all.  */
-         if (nsecs >= 0)
-           {
-             if (timespec_valid_p (timer_delay))
-               {
-                 if (timespec_cmp (timer_delay, timeout) < 0)
-                   {
-                     timeout = timer_delay;
-                     timeout_reduced_for_timers = true;
-                   }
-               }
-             else
-               {
-                 /* This is so a breakpoint can be put here.  */
-                 wait_reading_process_output_1 ();
-               }
-           }
-       }
+          /* This is so a breakpoint can be put here.  */
+          if (!timespec_valid_p (timer_delay))
+              wait_reading_process_output_1 ();
+        }
 
       /* Cause C-g and alarm signals to take immediate action,
         and cause input available signals to zero out timeout.
@@ -4454,7 +4660,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 ();
-             got_some_input = status_notify (NULL, wait_proc);
+             got_some_output = status_notify (NULL, wait_proc);
              if (do_display) redisplay_preserve_echo_area (13);
            }
        }
@@ -4464,37 +4670,41 @@ 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))
        {
          bool read_some_bytes = false;
 
          clear_waiting_for_input ();
-         XSETPROCESS (proc, wait_proc);
 
-         /* Read data from the process, until we exhaust it.  */
-         while (true)
+         /* If data can be read from the process, do so until exhausted.  */
+         if (wait_proc->infd >= 0)
            {
-             int nread = read_process_output (proc, wait_proc->infd);
-             if (nread < 0)
+             XSETPROCESS (proc, wait_proc);
+
+             while (true)
                {
-                 if (errno == EIO || errno == EAGAIN)
-                   break;
+                 int nread = read_process_output (proc, wait_proc->infd);
+                 if (nread < 0)
+                   {
+                   if (errno == EIO || errno == EAGAIN)
+                     break;
 #ifdef EWOULDBLOCK
-                 if (errno == EWOULDBLOCK)
-                   break;
+                   if (errno == EWOULDBLOCK)
+                     break;
 #endif
-               }
-             else
-               {
-                 if (got_some_input < nread)
-                   got_some_input = nread;
-                 if (nread == 0)
-                   break;
-                 read_some_bytes = true;
+                   }
+                 else
+                   {
+                     if (got_some_output < nread)
+                       got_some_output = nread;
+                     if (nread == 0)
+                       break;
+                     read_some_bytes = true;
+                   }
                }
            }
+
          if (read_some_bytes && do_display)
            redisplay_preserve_echo_area (10);
 
@@ -4525,7 +4735,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
            Available = input_wait_mask;
           Writeok = write_mask;
          check_delay = wait_proc ? 0 : process_output_delay_count;
-         check_write = SELECT_CAN_DO_WRITE_MASK;
+         check_write = true;
        }
 
       /* If frame size has changed or the window is newly mapped,
@@ -4553,11 +4763,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          no_avail = 1;
          FD_ZERO (&Available);
        }
-
-      if (!no_avail)
+      else
        {
-
-#ifdef ADAPTIVE_READ_BUFFERING
          /* 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
@@ -4565,9 +4772,9 @@ 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 = timeout.tv_nsec;
-             if (timeout.tv_sec > 0 || nsecs > READ_OUTPUT_DELAY_MAX)
-               nsecs = READ_OUTPUT_DELAY_MAX;
+             int adaptive_nsecs = timeout.tv_nsec;
+             if (timeout.tv_sec > 0 || adaptive_nsecs > READ_OUTPUT_DELAY_MAX)
+               adaptive_nsecs = READ_OUTPUT_DELAY_MAX;
              for (channel = 0; check_delay > 0 && channel <= max_process_desc; channel++)
                {
                  proc = chan_process[channel];
@@ -4581,15 +4788,42 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                      if (!XPROCESS (proc)->read_output_skip)
                        continue;
                      FD_CLR (channel, &Available);
+                     process_skipped = true;
                      XPROCESS (proc)->read_output_skip = 0;
-                     if (XPROCESS (proc)->read_output_delay < nsecs)
-                       nsecs = XPROCESS (proc)->read_output_delay;
+                     if (XPROCESS (proc)->read_output_delay < adaptive_nsecs)
+                       adaptive_nsecs = XPROCESS (proc)->read_output_delay;
                    }
                }
-             timeout = make_timespec (0, nsecs);
+             timeout = make_timespec (0, adaptive_nsecs);
              process_output_skip = 0;
            }
-#endif
+
+         /* If we've got some output and haven't limited our timeout
+            with adaptive read buffering, limit it. */
+         if (got_some_output > 0 && !process_skipped
+             && (timeout.tv_sec
+                 || timeout.tv_nsec > READ_OUTPUT_DELAY_INCREMENT))
+           timeout = make_timespec (0, READ_OUTPUT_DELAY_INCREMENT);
+
+
+         if (NILP (wait_for_cell) && just_wait_proc >= 0
+             && timespec_valid_p (timer_delay)
+             && timespec_cmp (timer_delay, timeout) < 0)
+           {
+             if (!timespec_valid_p (now))
+               now = current_timespec ();
+             struct timespec timeout_abs = timespec_add (now, timeout);
+             if (!timespec_valid_p (got_output_end_time)
+                 || timespec_cmp (timeout_abs, got_output_end_time) < 0)
+               got_output_end_time = timeout_abs;
+             timeout = timer_delay;
+           }
+         else
+           got_output_end_time = invalid_timespec ();
+
+         /* NOW can become inaccurate if time can pass during pselect.  */
+         if (timeout.tv_sec > 0 || timeout.tv_nsec > 0)
+           now = invalid_timespec ();
 
 #if defined (HAVE_NS)
           nfds = ns_select
@@ -4610,6 +4844,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              data is available in the buffers manually.  */
           if (nfds == 0)
            {
+             fd_set tls_available;
+             int set = 0;
+
+             FD_ZERO (&tls_available);
              if (! wait_proc)
                {
                  /* We're not waiting on a specific process, so loop
@@ -4630,7 +4868,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                          {
                            nfds++;
                            eassert (p->infd == channel);
-                           FD_SET (p->infd, &Available);
+                           FD_SET (p->infd, &tls_available);
+                           set++;
                          }
                      }
                }
@@ -4647,9 +4886,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                      nfds = 1;
                      eassert (0 <= wait_proc->infd);
                      /* Set to Available.  */
-                     FD_SET (wait_proc->infd, &Available);
+                     FD_SET (wait_proc->infd, &tls_available);
+                     set++;
                    }
                }
+             if (set)
+               Available = tls_available;
            }
 #endif
        }
@@ -4662,9 +4904,30 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       /*  If we woke up due to SIGWINCH, actually change size now.  */
       do_pending_window_change (0);
 
-      if ((time_limit || nsecs) && nfds == 0 && ! timeout_reduced_for_timers)
-       /* We waited the full specified time, so return now.  */
-       break;
+      if (nfds == 0)
+       {
+          /* Exit the main loop if we've passed the requested timeout,
+             or aren't skipping processes and got some output and
+             haven't lowered our timeout due to timers or SIGIO and
+             have waited a long amount of time due to repeated
+             timers.  */
+         if (wait < TIMEOUT)
+           break;
+         struct timespec cmp_time
+           = (wait == TIMEOUT
+              ? end_time
+              : (!process_skipped && got_some_output > 0
+                 && (timeout.tv_sec > 0 || timeout.tv_nsec > 0))
+              ? got_output_end_time
+              : invalid_timespec ());
+         if (timespec_valid_p (cmp_time))
+           {
+             now = current_timespec ();
+             if (timespec_cmp (cmp_time, now) <= 0)
+               break;
+           }
+       }
+
       if (nfds < 0)
        {
          if (xerrno == EINTR)
@@ -4787,10 +5050,14 @@ 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 ((!wait_proc || wait_proc == XPROCESS (proc))
+                 && got_some_output < nread)
+               got_some_output = nread;
              if (nread > 0)
                {
+                 /* Vacuum up any leftovers without waiting.  */
+                 if (wait_proc == XPROCESS (proc))
+                   wait = MINIMUM;
                  /* Since read_process_output can run a filter,
                     which can call accept-process-output,
                     don't try to read from any other processes
@@ -4812,7 +5079,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
                 available now and a closed pipe.
                 With luck, a closed pipe will be accompanied by
                 subprocess termination and SIGCHLD.  */
-             else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc))
+             else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc)
+                      && !PIPECONN_P (proc))
                ;
 #endif
 #ifdef HAVE_PTYS
@@ -4844,8 +5112,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 #endif /* HAVE_PTYS */
              /* If we can detect process termination, don't consider the
                 process gone just because its pipe is closed.  */
-             else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc))
+             else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc)
+                      && !PIPECONN_P (proc))
                ;
+             else if (nread == 0 && PIPECONN_P (proc))
+               {
+                 /* Preserve status of processes already terminated.  */
+                 XPROCESS (proc)->tick = ++process_tick;
+                 deactivate_process (proc);
+                 if (EQ (XPROCESS (proc)->status, Qrun))
+                   pset_status (XPROCESS (proc),
+                                list2 (Qexit, make_number (0)));
+               }
              else
                {
                  /* Preserve status of processes already terminated.  */
@@ -4937,7 +5215,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       QUIT;
     }
 
-  return got_some_input;
+  return got_some_output;
 }
 \f
 /* Given a list (FUNCTION ARGS...), apply FUNCTION to the ARGS.  */
@@ -5015,7 +5293,6 @@ read_process_output (Lisp_Object proc, int channel)
 #endif
        nbytes = emacs_read (channel, chars + carryover + buffered,
                             readmax - buffered);
-#ifdef ADAPTIVE_READ_BUFFERING
       if (nbytes > 0 && p->adaptive_read_buffering)
        {
          int delay = p->read_output_delay;
@@ -5041,7 +5318,6 @@ read_process_output (Lisp_Object proc, int channel)
              process_output_skip = 1;
            }
        }
-#endif
       nbytes += buffered;
       nbytes += buffered && nbytes <= 0;
     }
@@ -5085,8 +5361,6 @@ read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars,
   bool outer_running_asynch_code = running_asynch_code;
   int waiting = waiting_for_user_input_p;
 
-  /* No need to gcpro these, because all we do with them later
-     is test them for EQness, and none of them should be a string.  */
 #if 0
   Lisp_Object obuffer, okeymap;
   XSETBUFFER (obuffer, current_buffer);
@@ -5510,7 +5784,6 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
 #endif
                written = emacs_write_sig (outfd, cur_buf, cur_len);
              rv = (written ? 0 : -1);
-#ifdef ADAPTIVE_READ_BUFFERING
              if (p->read_output_delay > 0
                  && p->adaptive_read_buffering == 1)
                {
@@ -5518,7 +5791,6 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
                  process_output_delay_count--;
                  p->read_output_skip = 0;
                }
-#endif
            }
 
          if (rv < 0)
@@ -5658,9 +5930,10 @@ emacs_get_tty_pgrp (struct Lisp_Process *p)
 
 DEFUN ("process-running-child-p", Fprocess_running_child_p,
        Sprocess_running_child_p, 0, 1, 0,
-       doc: /* Return t if PROCESS has given the terminal to a child.
-If the operating system does not make it possible to find out,
-return t unconditionally.  */)
+       doc: /* Return non-nil if PROCESS has given the terminal to a
+child.  If the operating system does not make it possible to find out,
+return t.  If we can find out, return the numeric ID of the foreground
+process group.  */)
   (Lisp_Object process)
 {
   /* Initialize in case ioctl doesn't exist or gives an error,
@@ -5683,6 +5956,8 @@ return t unconditionally.  */)
 
   if (gid == p->pid)
     return Qnil;
+  if (gid != -1)
+    return make_number (gid);
   return Qt;
 }
 \f
@@ -5879,7 +6154,8 @@ If PROCESS is a network or serial process, inhibit handling of incoming
 traffic.  */)
   (Lisp_Object process, Lisp_Object current_group)
 {
-  if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process)))
+  if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process)
+                            || PIPECONN_P (process)))
     {
       struct Lisp_Process *p;
 
@@ -5908,7 +6184,8 @@ If PROCESS is a network or serial process, resume handling of incoming
 traffic.  */)
   (Lisp_Object process, Lisp_Object current_group)
 {
-  if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process)))
+  if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process)
+                            || PIPECONN_P (process)))
     {
       struct Lisp_Process *p;
 
@@ -5977,7 +6254,7 @@ SIGCODE may be an integer, or a symbol whose name is a signal name.  */)
        {
          Lisp_Object process_number
            = string_to_number (SSDATA (process), 10, 1);
-         if (INTEGERP (process_number) || FLOATP (process_number))
+         if (NUMBERP (process_number))
            tem = process_number;
        }
       process = tem;
@@ -6265,8 +6542,6 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
   if (inhibit_sentinels)
     return;
 
-  /* No need to gcpro these, because all we do with them later
-     is test them for EQness, and none of them should be a string.  */
   odeactivate = Vdeactivate_mark;
 #if 0
   Lisp_Object obuffer, okeymap;
@@ -6344,16 +6619,10 @@ status_notify (struct Lisp_Process *deleting_process,
 {
   Lisp_Object proc;
   Lisp_Object tail, msg;
-  struct gcpro gcpro1, gcpro2;
-  int got_some_input = -1;
+  int got_some_output = -1;
 
   tail = Qnil;
   msg = Qnil;
-  /* We need to gcpro tail; if read_process_output calls a filter
-     which deletes a process and removes the cons to which tail points
-     from Vprocess_alist, and then causes a GC, tail is an unprotected
-     reference.  */
-  GCPRO2 (tail, msg);
 
   /* Set this now, so that if new processes are created by sentinels
      that we run, we get called again to handle their status changes.  */
@@ -6378,8 +6647,9 @@ status_notify (struct Lisp_Process *deleting_process,
                 && p != deleting_process)
            {
              int nread = read_process_output (proc, p->infd);
-             if (got_some_input < nread)
-               got_some_input = nread;
+             if ((!wait_proc || wait_proc == XPROCESS (proc))
+                 && got_some_output < nread)
+               got_some_output = nread;
              if (nread <= 0)
                break;
            }
@@ -6409,12 +6679,13 @@ status_notify (struct Lisp_Process *deleting_process,
          p->update_tick = p->tick;
          /* Now output the message suitably.  */
          exec_sentinel (proc, msg);
+         if (BUFFERP (p->buffer))
+           /* In case it uses %s in mode-line-format.  */
+           bset_update_mode_line (XBUFFER (p->buffer));
        }
     } /* end for */
 
-  update_mode_lines = 24;  /* In case buffers use %s in mode-line-format.  */
-  UNGCPRO;
-  return got_some_input;
+  return got_some_output;
 }
 
 DEFUN ("internal-default-process-sentinel", Finternal_default_process_sentinel,
@@ -6628,9 +6899,7 @@ 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 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.  */
+   Return -1 signifying we got no output and did not try.  */
 
 int
 wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
@@ -6640,21 +6909,21 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 {
   register int nfds;
   struct timespec end_time, timeout;
+  enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
 
-  if (time_limit < 0)
-    {
-      time_limit = 0;
-      nsecs = -1;
-    }
-  else if (TYPE_MAXIMUM (time_t) < time_limit)
+  if (TYPE_MAXIMUM (time_t) < time_limit)
     time_limit = TYPE_MAXIMUM (time_t);
 
-  /* What does time_limit really mean?  */
-  if (time_limit || nsecs > 0)
+  if (time_limit < 0 || nsecs < 0)
+    wait = MINIMUM;
+  else if (time_limit > 0 || nsecs > 0)
     {
-      timeout = make_timespec (time_limit, nsecs);
-      end_time = timespec_add (current_timespec (), timeout);
+      wait = TIMEOUT;
+      end_time = timespec_add (current_timespec (),
+                               make_timespec (time_limit, nsecs));
     }
+  else
+    wait = INFINITY;
 
   /* Turn off periodic alarms (in case they are in use)
      and then turn off any other atimers,
@@ -6680,15 +6949,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 
       /* Compute time from now till when time limit is up.  */
       /* Exit if already run out.  */
-      if (nsecs < 0)
-       {
-         /* A negative timeout means
-            gobble output available now
-            but don't wait at all.  */
-
-         timeout = make_timespec (0, 0);
-       }
-      else if (time_limit || nsecs > 0)
+      if (wait == TIMEOUT)
        {
          struct timespec now = current_timespec ();
          if (timespec_cmp (end_time, now) <= 0)
@@ -6696,9 +6957,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
          timeout = timespec_sub (end_time, now);
        }
       else
-       {
-         timeout = make_timespec (100000, 0);
-       }
+       timeout = make_timespec (wait < TIMEOUT ? 0 : 100000, 0);
 
       /* If our caller will not immediately handle keyboard events,
         run timer events directly.
@@ -6726,7 +6985,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
              && requeued_events_pending_p ())
            break;
 
-         if (timespec_valid_p (timer_delay) && nsecs >= 0)
+         if (timespec_valid_p (timer_delay))
            {
              if (timespec_cmp (timer_delay, timeout) < 0)
                {
@@ -6770,7 +7029,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
       /*  If we woke up due to SIGWINCH, actually change size now.  */
       do_pending_window_change (0);
 
-      if ((time_limit || nsecs) && nfds == 0 && ! timeout_reduced_for_timers)
+      if (wait < INFINITY && nfds == 0 && ! timeout_reduced_for_timers)
        /* We waited the full specified time, so return now.  */
        break;
 
@@ -6848,6 +7107,19 @@ add_timer_wait_descriptor (int fd)
 
 #endif /* HAVE_TIMERFD */
 
+/* If program file NAME starts with /: for quoting a magic
+   name, remove that, preserving the multibyteness of NAME.  */
+
+Lisp_Object
+remove_slash_colon (Lisp_Object name)
+{
+  return
+    ((SBYTES (name) > 2 && SREF (name, 0) == '/' && SREF (name, 1) == ':')
+     ? make_specified_string (SSDATA (name) + 2, SCHARS (name) - 2,
+                             SBYTES (name) - 2, STRING_MULTIBYTE (name))
+     : name);
+}
+
 /* Add DESC to the set of keyboard input descriptors.  */
 
 void
@@ -6906,8 +7178,10 @@ setup_process_coding_systems (Lisp_Object process)
 }
 
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
-       doc: /* Return the (or a) process associated with BUFFER.
-BUFFER may be a buffer or the name of one.  */)
+       doc: /* Return the (or a) live process associated with BUFFER.
+BUFFER may be a buffer or the name of one.
+Return nil if all processes associated with BUFFER have been
+deleted or killed.  */)
   (register Lisp_Object buffer)
 {
 #ifdef subprocesses
@@ -6955,7 +7229,7 @@ kill_buffer_processes (Lisp_Object buffer)
   FOR_EACH_PROCESS (tail, proc)
     if (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer))
       {
-       if (NETCONN_P (proc) || SERIALCONN_P (proc))
+       if (NETCONN_P (proc) || SERIALCONN_P (proc) || PIPECONN_P (proc))
          Fdelete_process (proc);
        else if (XPROCESS (proc)->infd >= 0)
          process_send_signal (proc, SIGHUP, Qnil, 1);
@@ -7022,7 +7296,7 @@ DEFUN ("process-attributes", Fprocess_attributes,
 
 Value is an alist where each element is a cons cell of the form
 
-    \(KEY . VALUE)
+    (KEY . VALUE)
 
 If this functionality is unsupported, the value is nil.
 
@@ -7136,10 +7410,8 @@ init_process_emacs (void)
   num_pending_connects = 0;
 #endif
 
-#ifdef ADAPTIVE_READ_BUFFERING
   process_output_delay_count = 0;
   process_output_skip = 0;
-#endif
 
   /* Don't do this, it caused infinite select loops.  The display
      method should call add_keyboard_wait_descriptor on stdin if it
@@ -7161,40 +7433,6 @@ init_process_emacs (void)
   memset (datagram_address, 0, sizeof datagram_address);
 #endif
 
- {
-   Lisp_Object subfeatures = Qnil;
-   const struct socket_options *sopt;
-
-#define ADD_SUBFEATURE(key, val) \
-  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
-
-#ifdef NON_BLOCKING_CONNECT
-   ADD_SUBFEATURE (QCnowait, Qt);
-#endif
-#ifdef DATAGRAM_SOCKETS
-   ADD_SUBFEATURE (QCtype, Qdatagram);
-#endif
-#ifdef HAVE_SEQPACKET
-   ADD_SUBFEATURE (QCtype, Qseqpacket);
-#endif
-#ifdef HAVE_LOCAL_SOCKETS
-   ADD_SUBFEATURE (QCfamily, Qlocal);
-#endif
-   ADD_SUBFEATURE (QCfamily, Qipv4);
-#ifdef AF_INET6
-   ADD_SUBFEATURE (QCfamily, Qipv6);
-#endif
-#ifdef HAVE_GETSOCKNAME
-   ADD_SUBFEATURE (QCservice, Qt);
-#endif
-   ADD_SUBFEATURE (QCserver, Qt);
-
-   for (sopt = socket_options; sopt->name; sopt++)
-     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
-
-   Fprovide (intern_c_string ("make-network-process"), subfeatures);
- }
-
 #if defined (DARWIN_OS)
   /* PTYs are broken on Darwin < 6, but are sometimes useful for interactive
      processes.  As such, we only change the default value.  */
@@ -7255,6 +7493,7 @@ syms_of_process (void)
   DEFSYM (Qreal, "real");
   DEFSYM (Qnetwork, "network");
   DEFSYM (Qserial, "serial");
+  DEFSYM (Qpipe, "pipe");
   DEFSYM (QCbuffer, ":buffer");
   DEFSYM (QChost, ":host");
   DEFSYM (QCservice, ":service");
@@ -7267,8 +7506,12 @@ syms_of_process (void)
   DEFSYM (QClog, ":log");
   DEFSYM (QCnoquery, ":noquery");
   DEFSYM (QCstop, ":stop");
-  DEFSYM (QCoptions, ":options");
   DEFSYM (QCplist, ":plist");
+  DEFSYM (QCcommand, ":command");
+  DEFSYM (QCconnection_type, ":connection-type");
+  DEFSYM (QCstderr, ":stderr");
+  DEFSYM (Qpty, "pty");
+  DEFSYM (Qpipe, "pipe");
 
   DEFSYM (Qlast_nonmenu_event, "last-nonmenu-event");
 
@@ -7333,7 +7576,6 @@ then a pipe is used in any case.
 The value takes effect when `start-process' is called.  */);
   Vprocess_connection_type = Qt;
 
-#ifdef ADAPTIVE_READ_BUFFERING
   DEFVAR_LISP ("process-adaptive-read-buffering", Vprocess_adaptive_read_buffering,
               doc: /* If non-nil, improve receive buffering by delaying after short reads.
 On some systems, when Emacs reads the output from a subprocess, the output data
@@ -7345,7 +7587,6 @@ If the value is t, the delay is reset after each write to the process; any other
 non-nil value means that the delay is not reset on write.
 The variable takes effect when `start-process' is called.  */);
   Vprocess_adaptive_read_buffering = Qt;
-#endif
 
   defsubr (&Sprocessp);
   defsubr (&Sget_process);
@@ -7371,7 +7612,8 @@ The variable takes effect when `start-process' is called.  */);
   defsubr (&Sprocess_plist);
   defsubr (&Sset_process_plist);
   defsubr (&Sprocess_list);
-  defsubr (&Sstart_process);
+  defsubr (&Smake_process);
+  defsubr (&Smake_pipe_process);
   defsubr (&Sserial_process_configure);
   defsubr (&Smake_serial_process);
   defsubr (&Sset_network_process_option);
@@ -7403,6 +7645,40 @@ The variable takes effect when `start-process' is called.  */);
   defsubr (&Sset_process_filter_multibyte);
   defsubr (&Sprocess_filter_multibyte_p);
 
+ {
+   Lisp_Object subfeatures = Qnil;
+   const struct socket_options *sopt;
+
+#define ADD_SUBFEATURE(key, val) \
+  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
+
+#ifdef NON_BLOCKING_CONNECT
+   ADD_SUBFEATURE (QCnowait, Qt);
+#endif
+#ifdef DATAGRAM_SOCKETS
+   ADD_SUBFEATURE (QCtype, Qdatagram);
+#endif
+#ifdef HAVE_SEQPACKET
+   ADD_SUBFEATURE (QCtype, Qseqpacket);
+#endif
+#ifdef HAVE_LOCAL_SOCKETS
+   ADD_SUBFEATURE (QCfamily, Qlocal);
+#endif
+   ADD_SUBFEATURE (QCfamily, Qipv4);
+#ifdef AF_INET6
+   ADD_SUBFEATURE (QCfamily, Qipv6);
+#endif
+#ifdef HAVE_GETSOCKNAME
+   ADD_SUBFEATURE (QCservice, Qt);
+#endif
+   ADD_SUBFEATURE (QCserver, Qt);
+
+   for (sopt = socket_options; sopt->name; sopt++)
+     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
+
+   Fprovide (intern_c_string ("make-network-process"), subfeatures);
+ }
+
 #endif /* subprocesses */
 
   defsubr (&Sget_buffer_process);