(gud-mode): Doc fix.
[bpt/emacs.git] / src / process.c
index 018adf1..fda6e5e 100644 (file)
@@ -1,11 +1,12 @@
 /* Asynchronous subprocess control for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 1996
+      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 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -15,12 +16,13 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <signal.h>
 
-#include "config.h"
+#include <config.h>
 
 /* This file is split into two parts by the following preprocessor
    conditional.  The 'then' clause contains all of the support for
@@ -38,68 +40,60 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/types.h>         /* some typedefs are used in sys/file.h */
 #include <sys/file.h>
 #include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WINDOWSNT
+#include <stdlib.h>
+#include <fcntl.h>
+#endif /* not WINDOWSNT */
 
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#ifdef NEED_NET_ERRNO_H
+#include <net/errno.h>
+#endif /* NEED_NET_ERRNO_H */
 #endif /* HAVE_SOCKETS */
 
+/* TERM is a poor-man's SLIP, used on Linux.  */
+#ifdef TERM
+#include <client.h>
+#endif
+
+/* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */
+#ifdef HAVE_BROKEN_INET_ADDR
+#define IN_ADDR struct in_addr
+#define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
+#else
+#define IN_ADDR unsigned long
+#define NUMERIC_ADDR_ERROR (numeric_addr == -1)
+#endif
+
 #if defined(BSD) || defined(STRIDE)
 #include <sys/ioctl.h>
-#if !defined (O_NDELAY) && defined (HAVE_PTYS)
+#if !defined (O_NDELAY) && defined (HAVE_PTYS) && !defined(USG5)
 #include <fcntl.h>
 #endif /* HAVE_PTYS and no O_NDELAY */
 #endif /* BSD or STRIDE */
-#ifdef USG
-#ifdef HAVE_TERMIOS
-#include <termios.h>
-#else
-#include <termio.h>
-#endif
-#include <fcntl.h>
-#endif /* USG */
+
+#ifdef BROKEN_O_NONBLOCK
+#undef O_NONBLOCK
+#endif /* BROKEN_O_NONBLOCK */
 
 #ifdef NEED_BSDTTY
 #include <bsdtty.h>
 #endif
 
-#ifdef HPUX
-#undef TIOCGPGRP
-#endif
-
 #ifdef IRIS
 #include <sys/sysmacros.h>     /* for "minor" */
 #endif /* not IRIS */
 
 #include "systime.h"
-
-#if defined (HPUX) && defined (HAVE_PTYS)
-#include <sys/ptyio.h>
-#endif
-
-#ifdef AIX
-#include <sys/pty.h>
-#include <unistd.h>
-#endif
-
-#ifdef SYSV_PTYS
-#include <sys/tty.h>
-#ifdef titan
-#include <sys/ttyhw.h>
-#include <sys/stream.h>
-#endif
-#include <sys/pty.h>
-#endif
-
-#ifdef XENIX
-#undef TIOCGETC  /* Avoid confusing some conditionals that test this.  */
-#endif
-
-#ifdef BROKEN_TIOCGETC
-#undef TIOCGETC
-#endif
+#include "systty.h"
 
 #include "lisp.h"
 #include "window.h"
@@ -108,10 +102,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "termhooks.h"
 #include "termopts.h"
 #include "commands.h"
+#include "frame.h"
 
-extern int screen_garbaged;
-
+Lisp_Object Qprocessp;
 Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
+Lisp_Object Qlast_nonmenu_event;
 /* Qexit is declared and initialized in eval.c.  */
 
 /* a process object is a network connection when its childp field is neither
@@ -121,7 +116,7 @@ Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
 #ifdef HAVE_SOCKETS
 static Lisp_Object stream_process;
 
-#define NETCONN_P(p) (XGCTYPE (XPROCESS (p)->childp) == Lisp_String)
+#define NETCONN_P(p) (GC_STRINGP (XPROCESS (p)->childp))
 #else
 #define NETCONN_P(p) 0
 #endif /* HAVE_SOCKETS */
@@ -142,78 +137,26 @@ static Lisp_Object stream_process;
 
 #include "syssignal.h"
 
-/* Define the structure that the wait system call stores.
-   On many systems, there is a structure defined for this.
-   But on vanilla-ish USG systems there is not.  */
+#include "syswait.h"
 
-#ifndef VMS
-#ifndef WAITTYPE
-#if !defined (BSD) && !defined (UNIPLUS) && !defined (STRIDE) && !(defined (HPUX) && !defined (NOMULTIPLEJOBS)) && !defined (HAVE_WAIT_HEADER)
-mis;tak-+;;:
-#define WAITTYPE int
-#define WIFSTOPPED(w) ((w&0377) == 0177)
-#define WIFSIGNALED(w) ((w&0377) != 0177 && (w&~0377) == 0)
-#define WIFEXITED(w) ((w&0377) == 0)
-#define WRETCODE(w) (w >> 8)
-#define WSTOPSIG(w) (w >> 8)
-#define WCOREDUMP(w) ((w&0200) != 0)
-#define WTERMSIG(w) (w & 0377)
-#else 
-#ifdef BSD4_1
-#include <wait.h>
-#else
-#include <sys/wait.h>
-#endif /* not BSD 4.1 */
-
-#define WAITTYPE union wait
-#define WRETCODE(w) w.w_retcode
-#define WCOREDUMP(w) w.w_coredump
-
-#ifdef HPUX
-/* HPUX version 7 has broken definitions of these.  */
-#undef WTERMSIG
-#undef WSTOPSIG
-#undef WIFSTOPPED
-#undef WIFSIGNALED
-#undef WIFEXITED
+extern int errno;
+extern char *strerror ();
+#ifdef VMS
+extern char *sys_errlist[];
 #endif
 
-#ifndef WTERMSIG
-#define WTERMSIG(w) w.w_termsig
-#endif
-#ifndef WSTOPSIG
-#define WSTOPSIG(w) w.w_stopsig
+#ifndef HAVE_H_ERRNO
+extern int h_errno;
 #endif
-#ifndef WIFSTOPPED
-#define WIFSTOPPED(w) (WTERMSIG (w) == 0177)
-#endif
-#ifndef WIFSIGNALED
-#define WIFSIGNALED(w) (WTERMSIG (w) != 0177 && (WSTOPSIG (w)) == 0)
-#endif
-#ifndef WIFEXITED
-#define WIFEXITED(w) (WTERMSIG (w) == 0)
-#endif
-#endif /* BSD or UNIPLUS or STRIDE */
-#endif /* no WAITTYPE */
-#else /* VMS */
-
-/* For the CMU PTY driver + */
-#define DCL_PROMPT "$ "
-
-#include <ssdef.h>
-#include <iodef.h>
-#include <clidef.h>
-#include "vmsproc.h"
-#endif /* VMS */
-
-extern errno;
-extern sys_nerr;
-extern char *sys_errlist[];
 
+#ifndef SYS_SIGLIST_DECLARED
 #ifndef VMS
 #ifndef BSD4_1
+#ifndef WINDOWSNT
+#ifndef LINUX
 extern char *sys_siglist[];
-#else
+#endif /* not LINUX */
+#else /* BSD4_1 */
 char *sys_siglist[] =
   {
     "bum signal!!",
@@ -243,19 +186,14 @@ char *sys_siglist[] =
     "exceeded CPU time limit",
     "exceeded file size limit"
     };
+#endif /* not WINDOWSNT */
 #endif
 #endif /* VMS */
-
-#ifdef vipc
-
-#include "vipc.h"
-extern int comm_server;
-extern int net_listen_address;
-#endif /* vipc */
+#endif /* ! SYS_SIGLIST_DECLARED */
 
 /* t means use pty, nil means use a pipe,
    maybe other values to come.  */
-Lisp_Object Vprocess_connection_type;
+static Lisp_Object Vprocess_connection_type;
 
 #ifdef SKTPAIR
 #ifndef HAVE_SOCKETS
@@ -263,34 +201,37 @@ Lisp_Object Vprocess_connection_type;
 #endif
 #endif /* SKTPAIR */
 
+/* These next two vars are non-static since sysdep.c uses them in the
+   emulation of `select'.  */
 /* Number of events of change of status of a process.  */
 int process_tick;
-
 /* Number of events for which the user or sentinel has been notified.  */
 int update_tick;
 
-#ifdef FD_SET
-/* We could get this from param.h, but better not to depend on finding that.
-   And better not to risk that it might define other symbols used in this
-   file.  */
-#define MAXDESC 64
-#define SELECT_TYPE fd_set
-#else /* no FD_SET */
-#define MAXDESC 32
-#define SELECT_TYPE int
+#include "sysselect.h"
+
+/* If we support a window system, turn on the code to poll periodically
+   to detect C-g.  It isn't actually used when doing interrupt input.  */
+#ifdef HAVE_WINDOW_SYSTEM
+#define POLL_FOR_INPUT
+#endif
+
+/* Mask of bits indicating the descriptors that we wait for input on.  */
+
+static SELECT_TYPE input_wait_mask;
+
+/* Mask that excludes keyboard input descriptor (s).  */
 
-/* Define the macros to access a single-int bitmap of descriptors.  */
-#define FD_SET(n, p) (*(p) |= (1 << (n)))
-#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
-#define FD_ISSET(n, p) (*(p) & (1 << (n)))
-#define FD_ZERO(p) (*(p) = 0)
-#endif /* no FD_SET */
+static SELECT_TYPE non_keyboard_wait_mask;
 
-/* Mask of bits indicating the descriptors that we wait for input on */
+/* The largest descriptor currently in use for a process object.  */
+static int max_process_desc;
 
-SELECT_TYPE input_wait_mask;
+/* The largest descriptor currently in use for keyboard input.  */
+static int max_keyboard_desc;
 
-int delete_exited_processes;
+/* Nonzero means delete a process right away if it exits.  */
+static int delete_exited_processes;
 
 /* Indexed by descriptor, gives the process (if any) for that descriptor */
 Lisp_Object chan_process[MAXDESC];
@@ -298,21 +239,34 @@ Lisp_Object chan_process[MAXDESC];
 /* Alist of elements (NAME . PROCESS) */
 Lisp_Object Vprocess_alist;
 
-Lisp_Object Qprocessp;
-
-Lisp_Object get_process ();
-
 /* Buffered-ahead input char from process, indexed by channel.
    -1 means empty (no char is buffered).
    Used on sys V where the only way to tell if there is any
    output from the process is to read at least one char.
    Always -1 on systems that support FIONREAD.  */
 
+/* Don't make static; need to access externally.  */
 int proc_buffered_char[MAXDESC];
+
+static Lisp_Object get_process ();
+
+extern EMACS_TIME timer_check ();
+extern int timers_run;
+
+/* Maximum number of bytes to send to a pty without an eof.  */
+static int pty_max_bytes;
+
+#ifdef HAVE_PTYS
+/* The file name of the pty opened by allocate_pty.  */
+
+static char pty_name[24];
+#endif
 \f
 /* Compute the Lisp form of the process status, p->status, from
    the numeric status that was returned by `wait'.  */
 
+Lisp_Object status_convert ();
+
 update_status (p)
      struct Lisp_Process *p;
 {
@@ -323,7 +277,7 @@ update_status (p)
   p->raw_status_high = Qnil;
 }
 
-/*  Convert a process status work in Unix format to 
+/*  Convert a process status word in Unix format to 
     the list that we use internally.  */
 
 Lisp_Object
@@ -354,7 +308,7 @@ decode_status (l, symbol, code, coredump)
 {
   Lisp_Object tem;
 
-  if (XTYPE (l) == Lisp_Symbol)
+  if (SYMBOLP (l))
     {
       *symbol = l;
       *code = 0;
@@ -365,7 +319,7 @@ decode_status (l, symbol, code, coredump)
       *symbol = XCONS (l)->car;
       tem = XCONS (l)->cdr;
       *code = XFASTINT (XCONS (tem)->car);
-      tem = XFASTINT (XCONS (tem)->cdr);
+      tem = XCONS (tem)->cdr;
       *coredump = !NILP (tem);
     }
 }
@@ -384,7 +338,19 @@ status_message (status)
 
   if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
     {
-      string = build_string (code < NSIG ? sys_siglist[code] : "unknown");
+      char *signame = 0;
+      if (code < NSIG)
+       {
+#ifndef VMS
+         /* Cast to suppress warning if the table has const char *.  */
+         signame = (char *) sys_siglist[code];
+#else
+         signame = sys_errlist[code];
+#endif
+       }
+      if (signame == 0)
+       signame = "unknown";
+      string = build_string (signame);
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
       XSTRING (string)->data[0] = DOWNCASE (XSTRING (string)->data[0]);
       return concat2 (string, string2);
@@ -393,7 +359,7 @@ status_message (status)
     {
       if (code == 0)
        return build_string ("finished\n");
-      string = Fint_to_string (make_number (code));
+      string = Fnumber_to_string (make_number (code));
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
       return concat2 (build_string ("exited abnormally with code "),
                      concat2 (string, string2));
@@ -403,15 +369,12 @@ status_message (status)
 }
 \f
 #ifdef HAVE_PTYS
-static pty_process;
 
 /* 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.  */
 
-char pty_name[24];
-
 int
 allocate_pty ()
 {
@@ -419,6 +382,13 @@ allocate_pty ()
   register c, i;
   int fd;
 
+  /* Some systems name their pseudoterminals so that there are gaps in
+     the usual sequence - for example, on HP9000/S700 systems, there
+     are no pseudoterminals with names ending in 'f'.  So we wait for
+     three failures in a row before deciding that we've reached the
+     end of the ptys.  */
+  int failed_count = 0;
+
 #ifdef PTY_ITERATION
   PTY_ITERATION
 #else
@@ -428,33 +398,36 @@ allocate_pty ()
       {
 #ifdef PTY_NAME_SPRINTF
        PTY_NAME_SPRINTF
-#else
-#ifdef HPUX
-       sprintf (pty_name, "/dev/ptym/pty%c%x", c, i);
-#else
-#ifdef RTU
-       sprintf (pty_name, "/dev/pty%x", i);
 #else
        sprintf (pty_name, "/dev/pty%c%x", c, i);
-#endif /* not RTU */
-#endif /* not HPUX */
 #endif /* no PTY_NAME_SPRINTF */
 
-#ifndef IRIS
-       if (stat (pty_name, &stb) < 0)
+#ifdef PTY_OPEN
+       PTY_OPEN;
+#else /* no PTY_OPEN */
+#ifdef IRIS
+       /* Unusual IRIS code */
+       *ptyv = open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
+       if (fd < 0)
+         return -1;
+       if (fstat (fd, &stb) < 0)
          return -1;
+#else /* not IRIS */
+       if (stat (pty_name, &stb) < 0)
+         {
+           failed_count++;
+           if (failed_count >= 3)
+             return -1;
+         }
+       else
+         failed_count = 0;
 #ifdef O_NONBLOCK
        fd = open (pty_name, O_RDWR | O_NONBLOCK, 0);
 #else
        fd = open (pty_name, O_RDWR | O_NDELAY, 0);
 #endif
-#else /* Unusual IRIS code */
-       *ptyv = open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
-       if (fd < 0)
-         return -1;
-       if (fstat (fd, &stb) < 0)
-         return -1;
-#endif /* IRIS */
+#endif /* not IRIS */
+#endif /* no PTY_OPEN */
 
        if (fd >= 0)
          {
@@ -462,27 +435,14 @@ allocate_pty ()
               this avoids a nasty yet stupid bug in rlogins */
 #ifdef PTY_TTY_NAME_SPRINTF
            PTY_TTY_NAME_SPRINTF
-#else
-           /* TODO: In version 19, make these special cases use the macro above.  */
-#ifdef HPUX
-            sprintf (pty_name, "/dev/pty/tty%c%x", c, i);
-#else
-#ifdef RTU
-            sprintf (pty_name, "/dev/ttyp%x", i);
-#else
-#ifdef IRIS
-           sprintf (pty_name, "/dev/ttyq%d", minor (stb.st_rdev));
 #else
             sprintf (pty_name, "/dev/tty%c%x", c, i);
-#endif /* not IRIS */
-#endif /* not RTU */
-#endif /* not HPUX */
 #endif /* no PTY_TTY_NAME_SPRINTF */
 #ifndef UNIPLUS
            if (access (pty_name, 6) != 0)
              {
                close (fd);
-#ifndef IRIS
+#if !defined(IRIS) && !defined(__sgi)
                continue;
 #else
                return -1;
@@ -501,27 +461,23 @@ Lisp_Object
 make_process (name)
      Lisp_Object name;
 {
+  struct Lisp_Vector *vec;
   register Lisp_Object val, tem, name1;
   register struct Lisp_Process *p;
   char suffix[10];
   register int i;
 
-  /* size of process structure includes the vector header,
-     so deduct for that.  But struct Lisp_Vector includes the first
-     element, thus deducts too much, so add it back.  */
-  val = Fmake_vector (make_number ((sizeof (struct Lisp_Process)
-                                   - sizeof (struct Lisp_Vector)
-                                   + sizeof (Lisp_Object))
-                                  / sizeof (Lisp_Object)),
-                     Qnil);
-  XSETTYPE (val, Lisp_Process);
-
-  p = XPROCESS (val);
-  XFASTINT (p->infd) = 0;
-  XFASTINT (p->outfd) = 0;
-  XFASTINT (p->pid) = 0;
-  XFASTINT (p->tick) = 0;
-  XFASTINT (p->update_tick) = 0;
+  vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct Lisp_Process));
+  for (i = 0; i < VECSIZE (struct Lisp_Process); i++)
+    vec->contents[i] = Qnil;
+  vec->size = VECSIZE (struct Lisp_Process);
+  p = (struct Lisp_Process *)vec;
+
+  XSETINT (p->infd, -1);
+  XSETINT (p->outfd, -1);
+  XSETFASTINT (p->pid, 0);
+  XSETFASTINT (p->tick, 0);
+  XSETFASTINT (p->update_tick, 0);
   p->raw_status_low = Qnil;
   p->raw_status_high = Qnil;
   p->status = Qrun;
@@ -539,6 +495,7 @@ make_process (name)
     }
   name = name1;
   p->name = name;
+  XSETPROCESS (val, p);
   Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
   return val;
 }
@@ -550,17 +507,16 @@ remove_process (proc)
 
   pair = Frassq (proc, Vprocess_alist);
   Vprocess_alist = Fdelq (pair, Vprocess_alist);
-  Fset_marker (XPROCESS (proc)->mark, Qnil, Qnil);
 
   deactivate_process (proc);
 }
 \f
 DEFUN ("processp", Fprocessp, Sprocessp, 1, 1, 0,
   "Return t if OBJECT is a process.")
-  (obj)
-     Lisp_Object obj;
+  (object)
+     Lisp_Object object;
 {
-  return XTYPE (obj) == Lisp_Process ? Qt : Qnil;
+  return PROCESSP (object) ? Qt : Qnil;
 }
 
 DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
@@ -568,7 +524,7 @@ DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
   (name)
      register Lisp_Object name;
 {
-  if (XTYPE (name) == Lisp_Process)
+  if (PROCESSP (name))
     return name;
   CHECK_STRING (name, 0);
   return Fcdr (Fassoc (name, Vprocess_alist));
@@ -577,74 +533,88 @@ DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
   "Return the (or, a) process associated with BUFFER.\n\
 BUFFER may be a buffer or the name of one.")
-  (name)
-     register Lisp_Object name;
+  (buffer)
+     register Lisp_Object buffer;
 {
   register Lisp_Object buf, tail, proc;
 
-  if (NILP (name)) return Qnil;
-  buf = Fget_buffer (name);
+  if (NILP (buffer)) return Qnil;
+  buf = Fget_buffer (buffer);
   if (NILP (buf)) return Qnil;
 
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
       proc = Fcdr (Fcar (tail));
-      if (XTYPE (proc) == Lisp_Process && EQ (XPROCESS (proc)->buffer, buf))
+      if (PROCESSP (proc) && EQ (XPROCESS (proc)->buffer, buf))
        return proc;
     }
   return Qnil;
 }
 
-/* This is how commands for the user decode process arguments */
+/* This is how commands for the user decode process arguments.  It
+   accepts a process, a process name, a buffer, a buffer name, or nil.
+   Buffers denote the first process in the buffer, and nil denotes the
+   current buffer.  */
 
-Lisp_Object
+static Lisp_Object
 get_process (name)
      register Lisp_Object name;
 {
-  register Lisp_Object proc;
-  if (NILP (name))
-    proc = Fget_buffer_process (Fcurrent_buffer ());
+  register Lisp_Object proc, obj;
+  if (STRINGP (name))
+    {
+      obj = Fget_process (name);
+      if (NILP (obj))
+       obj = Fget_buffer (name);
+      if (NILP (obj))
+       error ("Process %s does not exist", XSTRING (name)->data);
+    }
+  else if (NILP (name))
+    obj = Fcurrent_buffer ();
   else
+    obj = name;
+
+  /* Now obj should be either a buffer object or a process object.
+   */
+  if (BUFFERP (obj))
     {
-      proc = Fget_process (name);
+      proc = Fget_buffer_process (obj);
       if (NILP (proc))
-       proc = Fget_buffer_process (Fget_buffer (name));
+       error ("Buffer %s has no process", XSTRING (XBUFFER (obj)->name)->data);
     }
-
-  if (!NILP (proc))
-    return proc;
-
-  if (NILP (name))
-    error ("Current buffer has no process");
   else
-    error ("Process %s does not exist", XSTRING (name)->data);
-  /* NOTREACHED */
+    {
+      CHECK_PROCESS (obj, 0);
+      proc = obj;
+    }
+  return proc;
 }
 
 DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
   "Delete PROCESS: kill it and forget about it immediately.\n\
-PROCESS may be a process or the name of one, or a buffer name.")
-  (proc)
-     register Lisp_Object proc;
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.")
+  (process)
+     register Lisp_Object process;
 {
-  proc = get_process (proc);
-  XPROCESS (proc)->raw_status_low = Qnil;
-  XPROCESS (proc)->raw_status_high = Qnil;
-  if (NETCONN_P (proc))
+  process = get_process (process);
+  XPROCESS (process)->raw_status_low = Qnil;
+  XPROCESS (process)->raw_status_high = Qnil;
+  if (NETCONN_P (process))
     {
-      XPROCESS (proc)->status = Fcons (Qexit, Fcons (make_number (0), Qnil));
-      XSETINT (XPROCESS (proc)->tick, ++process_tick);
+      XPROCESS (process)->status = Fcons (Qexit, Fcons (make_number (0), Qnil));
+      XSETINT (XPROCESS (process)->tick, ++process_tick);
     }
-  else if (XFASTINT (XPROCESS (proc)->infd))
+  else if (XINT (XPROCESS (process)->infd) >= 0)
     {
-      Fkill_process (proc, Qnil);
+      Fkill_process (process, Qnil);
       /* Do this now, since remove_process will make sigchld_handler do nothing.  */
-      XPROCESS (proc)->status 
+      XPROCESS (process)->status 
        = Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil));
-      XSETINT (XPROCESS (proc)->tick, ++process_tick);
+      XSETINT (XPROCESS (process)->tick, ++process_tick);
       status_notify ();
     }
-  remove_process (proc);
+  remove_process (process);
   return Qnil;
 }
 \f
@@ -656,24 +626,30 @@ exit -- for a process that has exited.\n\
 signal -- for a process that has got a fatal signal.\n\
 open -- for a network stream connection that is open.\n\
 closed -- for a network stream connection that is closed.\n\
-nil -- if arg is a process name and no such process exists.")
-/* command -- for a command channel opened to Emacs by another process.\n\
-   external -- for an i/o channel opened to Emacs by another process.\n\  */
-  (proc)
-     register Lisp_Object proc;
+nil -- if arg is a process name and no such process exists.\n\
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.")
+  (process)
+     register Lisp_Object process;
 {
   register struct Lisp_Process *p;
   register Lisp_Object status;
-  proc = Fget_process (proc);
-  if (NILP (proc))
-    return proc;
-  p = XPROCESS (proc);
+
+  if (STRINGP (process))
+    process = Fget_process (process);
+  else
+    process = get_process (process);
+
+  if (NILP (process))
+    return process;
+
+  p = XPROCESS (process);
   if (!NILP (p->raw_status_low))
     update_status (p);
   status = p->status;
-  if (XTYPE (status) == Lisp_Cons)
+  if (CONSP (status))
     status = XCONS (status)->car;
-  if (NETCONN_P (proc))
+  if (NETCONN_P (process))
     {
       if (EQ (status, Qrun))
        status = Qopen;
@@ -687,14 +663,14 @@ DEFUN ("process-exit-status", Fprocess_exit_status, Sprocess_exit_status,
        1, 1, 0,
   "Return the exit status of PROCESS or the signal number that killed it.\n\
 If PROCESS has not yet exited or died, return 0.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  if (!NILP (XPROCESS (proc)->raw_status_low))
-    update_status (XPROCESS (proc));
-  if (XTYPE (XPROCESS (proc)->status) == Lisp_Cons)
-    return XCONS (XCONS (XPROCESS (proc)->status)->cdr)->car;
+  CHECK_PROCESS (process, 0);
+  if (!NILP (XPROCESS (process)->raw_status_low))
+    update_status (XPROCESS (process));
+  if (CONSP (XPROCESS (process)->status))
+    return XCONS (XCONS (XPROCESS (process)->status)->cdr)->car;
   return make_number (0);
 }
 
@@ -702,22 +678,22 @@ DEFUN ("process-id", Fprocess_id, Sprocess_id, 1, 1, 0,
   "Return the process id of PROCESS.\n\
 This is the pid of the Unix process which PROCESS uses or talks to.\n\
 For a network connection, this value is nil.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->pid;
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->pid;
 }
 
 DEFUN ("process-name", Fprocess_name, Sprocess_name, 1, 1, 0,
   "Return the name of PROCESS, as a string.\n\
 This is the name of the program invoked in PROCESS,\n\
 possibly modified to make it unique among process names.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->name;
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->name;
 }
 
 DEFUN ("process-command", Fprocess_command, Sprocess_command, 1, 1, 0,
@@ -725,23 +701,34 @@ DEFUN ("process-command", Fprocess_command, Sprocess_command, 1, 1, 0,
 This is a list of strings, the first string being the program executed\n\
 and the rest of the strings being the arguments given to it.\n\
 For a non-child channel, this is nil.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->command;
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->command;
+}
+
+DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 1, 0,
+  "Return the name of the terminal PROCESS uses, or nil if none.\n\
+This is the terminal that the process itself reads and writes on,\n\
+not the name of the pty that Emacs uses to talk with that terminal.")
+  (process)
+     register Lisp_Object process;
+{
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->tty_name;
 }
 
 DEFUN ("set-process-buffer", Fset_process_buffer, Sset_process_buffer,
   2, 2, 0,
   "Set buffer associated with PROCESS to BUFFER (a buffer, or nil).")
-  (proc, buffer)
-     register Lisp_Object proc, buffer;
+  (process, buffer)
+     register Lisp_Object process, buffer;
 {
-  CHECK_PROCESS (proc, 0);
+  CHECK_PROCESS (process, 0);
   if (!NILP (buffer))
     CHECK_BUFFER (buffer, 1);
-  XPROCESS (proc)->buffer = buffer;
+  XPROCESS (process)->buffer = buffer;
   return buffer;
 }
 
@@ -750,35 +737,46 @@ DEFUN ("process-buffer", Fprocess_buffer, Sprocess_buffer,
   "Return the buffer PROCESS is associated with.\n\
 Output from PROCESS is inserted in this buffer\n\
 unless PROCESS has a filter.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->buffer;
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->buffer;
 }
 
 DEFUN ("process-mark", Fprocess_mark, Sprocess_mark,
   1, 1, 0,
   "Return the marker for the end of the last output from PROCESS.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->mark;
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->mark;
 }
 
 DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter,
   2, 2, 0,
   "Give PROCESS the filter function FILTER; nil means no filter.\n\
+t means stop accepting output from the process.\n\
 When a process has a filter, each time it does output\n\
 the entire string of output is passed to the filter.\n\
 The filter gets two arguments: the process and the string of output.\n\
 If the process has a filter, its buffer is not used for output.")
-  (proc, filter)
-     register Lisp_Object proc, filter;
+  (process, filter)
+     register Lisp_Object process, filter;
 {
-  CHECK_PROCESS (proc, 0);
-  XPROCESS (proc)->filter = filter;
+  CHECK_PROCESS (process, 0);
+  if (EQ (filter, Qt))
+    {
+      FD_CLR (XINT (XPROCESS (process)->infd), &input_wait_mask);
+      FD_CLR (XINT (XPROCESS (process)->infd), &non_keyboard_wait_mask);
+    }
+  else if (EQ (XPROCESS (process)->filter, Qt))
+    {
+      FD_SET (XINT (XPROCESS (process)->infd), &input_wait_mask);
+      FD_SET (XINT (XPROCESS (process)->infd), &non_keyboard_wait_mask);
+    }
+  XPROCESS (process)->filter = filter;
   return filter;
 }
 
@@ -786,11 +784,11 @@ DEFUN ("process-filter", Fprocess_filter, Sprocess_filter,
   1, 1, 0,
   "Returns the filter function of PROCESS; nil if none.\n\
 See `set-process-filter' for more info on filter functions.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->filter;
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->filter;
 }
 
 DEFUN ("set-process-sentinel", Fset_process_sentinel, Sset_process_sentinel,
@@ -798,11 +796,11 @@ DEFUN ("set-process-sentinel", Fset_process_sentinel, Sset_process_sentinel,
   "Give PROCESS the sentinel SENTINEL; nil for none.\n\
 The sentinel is called as a function when the process changes state.\n\
 It gets two arguments: the process, and a string describing the change.")
-  (proc, sentinel)
-     register Lisp_Object proc, sentinel;
+  (process, sentinel)
+     register Lisp_Object process, sentinel;
 {
-  CHECK_PROCESS (proc, 0);
-  XPROCESS (proc)->sentinel = sentinel;
+  CHECK_PROCESS (process, 0);
+  XPROCESS (process)->sentinel = sentinel;
   return sentinel;
 }
 
@@ -810,29 +808,58 @@ DEFUN ("process-sentinel", Fprocess_sentinel, Sprocess_sentinel,
   1, 1, 0,
   "Return the sentinel of PROCESS; nil if none.\n\
 See `set-process-sentinel' for more info on sentinels.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->sentinel;
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->sentinel;
+}
+
+DEFUN ("set-process-window-size", Fset_process_window_size,
+  Sset_process_window_size, 3, 3, 0,
+  "Tell PROCESS that it has logical window size HEIGHT and WIDTH.")
+  (process, height, width)
+     register Lisp_Object process, height, width;
+{
+  CHECK_PROCESS (process, 0);
+  CHECK_NATNUM (height, 0);
+  CHECK_NATNUM (width, 0);
+  if (set_window_size (XINT (XPROCESS (process)->infd),
+                      XINT (height), XINT(width)) <= 0)
+    return Qnil;
+  else
+    return Qt;
 }
 
 DEFUN ("process-kill-without-query", Fprocess_kill_without_query,
   Sprocess_kill_without_query, 1, 2, 0,
   "Say no query needed if PROCESS is running when Emacs is exited.\n\
-Optional second argument if non-nill says to require a query.\n\
+Optional second argument if non-nil says to require a query.\n\
 Value is t if a query was formerly required.")
-  (proc, value)
-     register Lisp_Object proc, value;
+  (process, value)
+     register Lisp_Object process, value;
 {
   Lisp_Object tem;
 
-  CHECK_PROCESS (proc, 0);
-  tem = XPROCESS (proc)->kill_without_query;
-  XPROCESS (proc)->kill_without_query = Fnull (value);
+  CHECK_PROCESS (process, 0);
+  tem = XPROCESS (process)->kill_without_query;
+  XPROCESS (process)->kill_without_query = Fnull (value);
 
   return Fnull (tem);
 }
+
+#if 0 /* Turned off because we don't currently record this info
+        in the process.  Perhaps add it.  */
+DEFUN ("process-connection", Fprocess_connection, Sprocess_connection, 1, 1, 0,
+ "Return the connection type of `PROCESS'.\n\
+The value is `nil' for a pipe,\n\
+`t' or `pty' for a pty, or `stream' for a socket connection.")
+  (process)
+     Lisp_Object process;
+{
+  return XPROCESS (process)->type;
+}
+#endif
 \f
 Lisp_Object
 list_processes_1 ()
@@ -844,7 +871,7 @@ list_processes_1 ()
   register int state;
   char tembuf[80];
 
-  XFASTINT (minspace) = 1;
+  XSETFASTINT (minspace, 1);
 
   set_buffer_internal (XBUFFER (Vstandard_output));
   Fbuffer_disable_undo (Vstandard_output);
@@ -852,8 +879,8 @@ list_processes_1 ()
   current_buffer->truncate_lines = Qt;
 
   write_string ("\
-Proc         Status   Buffer         Command\n\
-----         ------   ------         -------\n", -1);
+Proc         Status   Buffer         Tty         Command\n\
+----         ------   ------         ---         -------\n", -1);
 
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
@@ -870,7 +897,7 @@ Proc         Status   Buffer         Command\n\
       if (!NILP (p->raw_status_low))
        update_status (p);
       symbol = p->status;
-      if (XTYPE (p->status) == Lisp_Cons)
+      if (CONSP (p->status))
        symbol = XCONS (p->status)->car;
 
       
@@ -880,7 +907,7 @@ Proc         Status   Buffer         Command\n\
          tem = Fcar (Fcdr (p->status));
 #ifdef VMS
          if (XINT (tem) < NSIG)
-           write_string (sys_siglist [XINT (tem)], -1);
+           write_string (sys_errlist [XINT (tem)], -1);
          else
 #endif
            Fprinc (symbol, Qnil);
@@ -903,7 +930,7 @@ Proc         Status   Buffer         Command\n\
          tem = Fcar (Fcdr (p->status));
          if (XFASTINT (tem))
            {
-             sprintf (tembuf, " %d", XFASTINT (tem));
+             sprintf (tembuf, " %d", (int) XFASTINT (tem));
              write_string (tembuf, -1);
            }
        }
@@ -921,6 +948,13 @@ Proc         Status   Buffer         Command\n\
 
       Findent_to (make_number (37), minspace);
 
+      if (STRINGP (p->tty_name))
+       Finsert (1, &p->tty_name);
+      else
+       insert_string ("(none)");
+
+      Findent_to (make_number (49), minspace);
+
       if (NETCONN_P (proc))
         {
          sprintf (tembuf, "(network stream connection to %s)\n",
@@ -963,6 +997,10 @@ DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
   return Fmapcar (Qcdr, Vprocess_alist);
 }
 \f
+/* Starting asynchronous inferior processes.  */
+
+static Lisp_Object start_process_unwind ();
+
 DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
   "Start a program in a subprocess.  Return the process object for it.\n\
 Args are NAME BUFFER PROGRAM &rest PROGRAM-ARGS\n\
@@ -978,7 +1016,7 @@ Remaining arguments are strings to give program as arguments.")
      int nargs;
      register Lisp_Object *args;
 {
-  Lisp_Object buffer, name, program, proc, tem;
+  Lisp_Object buffer, name, program, proc, current_dir, tem;
 #ifdef VMS
   register unsigned char *new_argv;
   int len;
@@ -986,11 +1024,38 @@ Remaining arguments are strings to give program as arguments.")
   register unsigned char **new_argv;
 #endif
   register int i;
+  int count = specpdl_ptr - specpdl;
 
   buffer = args[1];
   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, gcpro2;
+
+    current_dir = current_buffer->directory;
+
+    GCPRO2 (buffer, current_dir);
+
+    current_dir 
+      = expand_and_dir_to_file (Funhandled_file_name_directory (current_dir),
+                               Qnil);
+    if (NILP (Ffile_accessible_directory_p (current_dir)))
+      report_file_error ("Setting current directory",
+                        Fcons (current_buffer->directory, Qnil));
+
+    UNGCPRO;
+  }
+
   name = args[0];
   CHECK_STRING (name, 0);
 
@@ -1017,30 +1082,50 @@ Remaining arguments are strings to give program as arguments.")
       strcat (new_argv, " ");
       strcat (new_argv, XSTRING (tem)->data);
     }
+  /* Need to add code here to check for program existence on VMS */
+  
 #else /* not VMS */
   new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
 
-  for (i = 3; i < nargs; i++)
-    {
-      tem = args[i];
-      CHECK_STRING (tem, i);
-      new_argv[i - 2] = XSTRING (tem)->data;
-    }
-  new_argv[i - 2] = 0;
-  new_argv[0] = XSTRING (program)->data;
-
   /* If program file name is not absolute, search our path for it */
-  if (new_argv[0][0] != '/')
+  if (!IS_DIRECTORY_SEP (XSTRING (program)->data[0])
+      && !(XSTRING (program)->size > 1
+          && IS_DEVICE_SEP (XSTRING (program)->data[1])))
     {
+      struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
       tem = Qnil;
-      openp (Vexec_path, program, "", &tem, 1);
+      GCPRO4 (name, program, buffer, current_dir);
+      openp (Vexec_path, program, EXEC_SUFFIXES, &tem, 1);
+      UNGCPRO;
       if (NILP (tem))
        report_file_error ("Searching for program", Fcons (program, Qnil));
+      tem = Fexpand_file_name (tem, Qnil);
       new_argv[0] = XSTRING (tem)->data;
     }
+  else
+    {
+      if (!NILP (Ffile_directory_p (program)))
+       error ("Specified program for new process is a directory");
+
+      new_argv[0] = XSTRING (program)->data;
+    }
+
+  for (i = 3; i < nargs; i++)
+    {
+      tem = args[i];
+      CHECK_STRING (tem, i);
+      new_argv[i - 2] = XSTRING (tem)->data;
+    }
+  new_argv[i - 2] = 0;
 #endif /* not VMS */
 
   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
+     check in create_process doesn't need to call remove_process
+     itself; it's all taken care of here.  */
+  record_unwind_protect (start_process_unwind, proc);
 
   XPROCESS (proc)->childp = Qt;
   XPROCESS (proc)->command_channel_p = Qnil;
@@ -1049,11 +1134,35 @@ Remaining arguments are strings to give program as arguments.")
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
-  create_process (proc, new_argv);
+  /* Make the process marker point into the process buffer (if any).  */
+  if (!NILP (buffer))
+    Fset_marker (XPROCESS (proc)->mark,
+                make_number (BUF_ZV (XBUFFER (buffer))), buffer);
 
-  return proc;
+  create_process (proc, new_argv, current_dir);
+
+  return unbind_to (count, proc);
+}
+
+/* This function is the unwind_protect form for Fstart_process.  If
+   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
+start_process_unwind (proc)
+     Lisp_Object proc;
+{
+  if (!PROCESSP (proc))
+    abort ();
+
+  /* Was PROC started successfully?  */
+  if (XINT (XPROCESS (proc)->pid) <= 0)
+    remove_process (proc);
+
+  return Qnil;
 }
 
+
 SIGTYPE
 create_process_1 (signo)
      int signo;
@@ -1085,36 +1194,37 @@ create_process_sigchld ()
 #endif
 
 #ifndef VMS /* VMS version of this function is in vmsproc.c.  */
-create_process (process, new_argv)
+create_process (process, new_argv, current_dir)
      Lisp_Object process;
      char **new_argv;
+     Lisp_Object current_dir;
 {
-  int pid, inchannel, outchannel, forkin, forkout;
+  int pid, inchannel, outchannel;
   int sv[2];
+#ifdef POSIX_SIGNALS
+  sigset_t procmask;
+  sigset_t blocked;
+  struct sigaction sigint_action;
+  struct sigaction sigquit_action;
+#ifdef AIX
+  struct sigaction sighup_action;
+#endif
+#else /* !POSIX_SIGNALS */
 #ifdef SIGCHLD
   SIGTYPE (*sigchld)();
 #endif
-  int pty_flag = 0;
-  Lisp_Object current_dir;
-  char **env;
+#endif /* !POSIX_SIGNALS */
+  /* Use volatile to protect variables from being clobbered by longjmp.  */
+  volatile int forkin, forkout;
+  volatile int pty_flag = 0;
   extern char **environ;
 
-  env = environ;
-
   inchannel = outchannel = -1;
 
 #ifdef HAVE_PTYS
-  if (EQ (Vprocess_connection_type, Qt))
+  if (!NILP (Vprocess_connection_type))
     outchannel = inchannel = allocate_pty ();
 
-  /* Make sure that the child will be able to chdir to the current
-     buffer's current directory.  We can't just have the child check
-     for an error when it does the chdir, since it's in a vfork.  */
-  current_dir = expand_and_dir_to_file (current_buffer->directory, Qnil);
-  if (NILP (Ffile_accessible_directory_p (current_dir)))
-    report_file_error ("Setting current directory",
-                      Fcons (current_buffer->directory, Qnil));
-
   if (inchannel >= 0)
     {
 #ifndef USG 
@@ -1145,12 +1255,22 @@ create_process (process, new_argv)
     }
 #else /* not SKTPAIR */
     {
+#ifdef WINDOWSNT
+      pipe_with_inherited_out (sv);
+      inchannel = sv[0];
+      forkout = sv[1];
+
+      pipe_with_inherited_in (sv);
+      forkin = sv[0];
+      outchannel = sv[1];
+#else /* not WINDOWSNT */
       pipe (sv);
       inchannel = sv[0];
       forkout = sv[1];
       pipe (sv);
       outchannel = sv[1];
       forkin = sv[0];
+#endif /* not WINDOWSNT */
     }
 #endif /* not SKTPAIR */
 
@@ -1171,27 +1291,47 @@ create_process (process, new_argv)
 
 #ifdef O_NONBLOCK
   fcntl (inchannel, F_SETFL, O_NONBLOCK);
+  fcntl (outchannel, F_SETFL, O_NONBLOCK);
 #else
 #ifdef O_NDELAY
   fcntl (inchannel, F_SETFL, O_NDELAY);
+  fcntl (outchannel, F_SETFL, O_NDELAY);
 #endif
 #endif
 
   /* Record this as an active process, with its channels.
      As a result, child_setup will close Emacs's side of the pipes.  */
   chan_process[inchannel] = process;
-  XFASTINT (XPROCESS (process)->infd) = inchannel;
-  XFASTINT (XPROCESS (process)->outfd) = outchannel;
+  XSETINT (XPROCESS (process)->infd, inchannel);
+  XSETINT (XPROCESS (process)->outfd, outchannel);
   /* Record the tty descriptor used in the subprocess.  */
   if (forkin < 0)
     XPROCESS (process)->subtty = Qnil;
   else
-    XFASTINT (XPROCESS (process)->subtty) = forkin;
+    XSETFASTINT (XPROCESS (process)->subtty, forkin);
   XPROCESS (process)->pty_flag = (pty_flag ? Qt : Qnil);
   XPROCESS (process)->status = Qrun;
 
   /* Delay interrupts until we have a chance to store
      the new fork's pid in its process structure */
+#ifdef POSIX_SIGNALS
+  sigemptyset (&blocked);
+#ifdef SIGCHLD
+  sigaddset (&blocked, SIGCHLD);
+#endif
+#ifdef HAVE_VFORK
+  /* On many hosts (e.g. Solaris 2.4), if a vforked child calls `signal',
+     this sets the parent's signal handlers as well as the child's.
+     So delay all interrupts whose handlers the child might munge,
+     and record the current handlers so they can be restored later.  */
+  sigaddset (&blocked, SIGINT );  sigaction (SIGINT , 0, &sigint_action );
+  sigaddset (&blocked, SIGQUIT);  sigaction (SIGQUIT, 0, &sigquit_action);
+#ifdef AIX
+  sigaddset (&blocked, SIGHUP );  sigaction (SIGHUP , 0, &sighup_action );
+#endif
+#endif /* HAVE_VFORK */
+  sigprocmask (SIG_BLOCK, &blocked, &procmask);
+#else /* !POSIX_SIGNALS */
 #ifdef SIGCHLD
 #ifdef BSD4_1
   sighold (SIGCHLD);
@@ -1206,6 +1346,12 @@ create_process (process, new_argv)
 #endif /* ordinary USG */
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
+#endif /* !POSIX_SIGNALS */
+
+  FD_SET (inchannel, &input_wait_mask);
+  FD_SET (inchannel, &non_keyboard_wait_mask);
+  if (inchannel > max_process_desc)
+    max_process_desc = inchannel;
 
   /* Until we store the proper pid, enable sigchld_handler
      to recognize an unknown pid as standing for this process.
@@ -1220,8 +1366,10 @@ create_process (process, new_argv)
        Protect it from permanent change.  */
     char **save_environ = environ;
 
+#ifndef WINDOWSNT
     pid = vfork ();
     if (pid == 0)
+#endif /* not WINDOWSNT */
       {
        int xforkin = forkin;
        int xforkout = forkout;
@@ -1236,15 +1384,45 @@ create_process (process, new_argv)
 #ifdef HAVE_PTYS
        /* First, disconnect its current controlling terminal.  */
 #ifdef HAVE_SETSID
+       /* We tried doing setsid only if pty_flag, but it caused
+          process_set_signal to fail on SGI when using a pipe.  */
        setsid ();
+       /* Make the pty's terminal the controlling terminal.  */
+       if (pty_flag)
+         {
+#ifdef TIOCSCTTY
+           /* We ignore the return value
+              because faith@cs.unc.edu says that is necessary on Linux.  */
+           ioctl (xforkin, TIOCSCTTY, 0);
+#endif
+         }
 #else /* not HAVE_SETSID */
 #ifdef USG
-       /* It's very important to call setpgrp() here and no time
+       /* It's very important to call setpgrp here and no time
           afterwards.  Otherwise, we lose our controlling tty which
           is set when we open the pty. */
        setpgrp ();
 #endif /* USG */
 #endif /* not HAVE_SETSID */
+#if defined (HAVE_TERMIOS) && defined (LDISC1)
+       if (pty_flag && xforkin >= 0)
+         {
+           struct termios t;
+           tcgetattr (xforkin, &t);
+           t.c_lflag = LDISC1;
+           if (tcsetattr (xforkin, TCSANOW, &t) < 0)
+             write (1, "create_process/tcsetattr LDISC1 failed\n", 39);
+         }
+#else
+#if defined (NTTYDISC) && defined (TIOCSETD)
+       if (pty_flag && xforkin >= 0)
+         {
+           /* Use new line discipline.  */
+           int ldisc = NTTYDISC;
+           ioctl (xforkin, TIOCSETD, &ldisc);
+         }
+#endif
+#endif
 #ifdef TIOCNOTTY 
        /* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you
           can do TIOCSPGRP only to the process's controlling tty.  */
@@ -1259,7 +1437,11 @@ create_process (process, new_argv)
            /* In order to get a controlling terminal on some versions
               of BSD, it is necessary to put the process in pgrp 0
               before it opens the terminal.  */
+#ifdef OSF1
+           setpgid (0, 0);
+#else
            setpgrp (0, 0);
+#endif
 #endif
          }
 #endif /* TIOCNOTTY */
@@ -1271,17 +1453,34 @@ create_process (process, new_argv)
           This makes the pty the controlling terminal of the subprocess.  */
        if (pty_flag)
          {
+#ifdef SET_CHILD_PTY_PGRP
+           int pgrp = getpid ();
+#endif
+
            /* I wonder if close (open (pty_name, ...)) would work?  */
            if (xforkin >= 0)
              close (xforkin);
            xforkout = xforkin = open (pty_name, O_RDWR, 0);
 
            if (xforkin < 0)
-             abort ();
+             {
+               write (1, "Couldn't open the pty terminal ", 31);
+               write (1, pty_name, strlen (pty_name));
+               write (1, "\n", 1);
+               _exit (1);
+             }
+
+#ifdef SET_CHILD_PTY_PGRP
+           ioctl (xforkin, TIOCSPGRP, &pgrp);
+           ioctl (xforkout, TIOCSPGRP, &pgrp);
+#endif
          }
 #endif /* not UNIPLUS and not RTU */
 #ifdef SETUP_SLAVE_PTY
-       SETUP_SLAVE_PTY;
+       if (pty_flag)
+         {
+           SETUP_SLAVE_PTY;
+         }
 #endif /* SETUP_SLAVE_PTY */
 #ifdef AIX
        /* On AIX, we've disabled SIGHUP above once we start a child on a pty.
@@ -1291,6 +1490,13 @@ create_process (process, new_argv)
 #endif
 #endif /* HAVE_PTYS */
 
+       signal (SIGINT, SIG_DFL);
+       signal (SIGQUIT, SIG_DFL);
+
+       /* Stop blocking signals in the child.  */
+#ifdef POSIX_SIGNALS
+       sigprocmask (SIG_SETMASK, &procmask, 0);
+#else /* !POSIX_SIGNALS */
 #ifdef SIGCHLD
 #ifdef BSD4_1
        sigrelse (SIGCHLD);
@@ -1298,53 +1504,80 @@ create_process (process, new_argv)
 #if defined (BSD) || defined (UNIPLUS) || defined (HPUX)
        sigsetmask (SIGEMPTYMASK);
 #else /* ordinary USG */
+#if 0
        signal (SIGCHLD, sigchld);
+#endif
 #endif /* ordinary USG */
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
+#endif /* !POSIX_SIGNALS */
 
-       child_setup_tty (xforkout);
+       if (pty_flag)
+         child_setup_tty (xforkout);
+#ifdef WINDOWSNT
+       pid = child_setup (xforkin, xforkout, xforkout,
+                          new_argv, 1, current_dir);
+#else  /* not WINDOWSNT */     
        child_setup (xforkin, xforkout, xforkout,
-                    new_argv, env, 1, current_dir);
+                    new_argv, 1, current_dir);
+#endif /* not WINDOWSNT */
       }
     environ = save_environ;
   }
 
+  /* This runs in the Emacs process.  */
   if (pid < 0)
     {
-      remove_process (process);
-      report_file_error ("Doing vfork", Qnil);
+      if (forkin >= 0)
+       close (forkin);
+      if (forkin != forkout && forkout >= 0)
+       close (forkout);
     }
-
-  XFASTINT (XPROCESS (process)->pid) = pid;
-
-  FD_SET (inchannel, &input_wait_mask);
-
-  /* If the subfork execv fails, and it exits,
-     this close hangs.  I don't know why.
-     So have an interrupt jar it loose.  */
-  stop_polling ();
-  signal (SIGALRM, create_process_1);
-  alarm (1);
-#ifdef SYSV4_PTYS
-  /* OK to close only if it's not a pty.  Otherwise we need to leave
-     it open for ioctl to get pgrp when signals are sent, or to send
-     the interrupt characters through if that's how we're signalling
-     subprocesses.  Alternately if you are concerned about running out
-     of file descriptors, you could just save the tty name and open
-     just to do the ioctl.  */
-  if (NILP (XFASTINT (XPROCESS (process)->pty_flag)))
-#endif
+  else
     {
+      /* vfork succeeded.  */
+      XSETFASTINT (XPROCESS (process)->pid, pid);
+
+#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.  */
+      stop_polling ();
+      signal (SIGALRM, create_process_1);
+      alarm (1);
       XPROCESS (process)->subtty = Qnil;
       if (forkin >= 0)
        close (forkin);
+      alarm (0);
+      start_polling ();
+      if (forkin != forkout && forkout >= 0)
+       close (forkout);
+
+#ifdef HAVE_PTYS
+      if (pty_flag)
+       XPROCESS (process)->tty_name = build_string (pty_name);
+      else
+#endif
+       XPROCESS (process)->tty_name = Qnil;
     }
-  alarm (0);
-  start_polling ();
-  if (forkin != forkout && forkout >= 0)
-    close (forkout);
 
+  /* Restore the signal state whether vfork succeeded or not.
+     (We will signal an error, below, if it failed.)  */
+#ifdef POSIX_SIGNALS
+#ifdef HAVE_VFORK
+  /* Restore the parent's signal handlers.  */
+  sigaction (SIGINT, &sigint_action, 0);
+  sigaction (SIGQUIT, &sigquit_action, 0);
+#ifdef AIX
+  sigaction (SIGHUP, &sighup_action, 0);
+#endif
+#endif /* HAVE_VFORK */
+  /* Stop blocking signals in the parent.  */
+  sigprocmask (SIG_SETMASK, &procmask, 0);
+#else /* !POSIX_SIGNALS */
 #ifdef SIGCHLD
 #ifdef BSD4_1
   sigrelse (SIGCHLD);
@@ -1362,6 +1595,11 @@ create_process (process, new_argv)
 #endif /* ordinary USG */
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
+#endif /* !POSIX_SIGNALS */
+
+  /* Now generate the error if vfork failed.  */
+  if (pid < 0)
+    report_file_error ("Doing vfork", Qnil);
 }
 #endif /* not VMS */
 
@@ -1397,17 +1635,19 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   struct servent *svc_info;
   struct hostent *host_info_ptr, host_info;
   char *(addr_list[2]);
-  unsigned long numeric_addr;
+  IN_ADDR numeric_addr;
   int s, outch, inch;
   char errstring[80];
   int port;
   struct hostent host_info_fixed;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  int retry = 0;
+  int count = specpdl_ptr - specpdl;
 
   GCPRO4 (name, buffer, host, service);
   CHECK_STRING (name, 0);
   CHECK_STRING (host, 0);
-  if (XTYPE(service) == Lisp_Int)
+  if (INTEGERP (service))
     port = htons ((unsigned short) XINT (service));
   else
     {
@@ -1418,22 +1658,50 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
       port = svc_info->s_port;
     }
 
-  host_info_ptr = gethostbyname (XSTRING (host)->data);
+  /* Slow down polling to every ten seconds.
+     Some kernels have a bug which causes retrying connect to fail
+     after a connect.  Polling can interfere with gethostbyname too.  */
+#ifdef POLL_FOR_INPUT
+  bind_polling_period (10);
+#endif
+
+#ifndef TERM
+  while (1)
+    {
+#ifdef TRY_AGAIN
+      h_errno = 0;
+#endif
+      immediate_quit = 1;
+      QUIT;
+      host_info_ptr = gethostbyname (XSTRING (host)->data);
+      immediate_quit = 0;
+#ifdef TRY_AGAIN
+      if (! (host_info_ptr == 0 && h_errno == TRY_AGAIN))
+#endif
+       break;
+      Fsleep_for (make_number (1), Qnil);
+    }
   if (host_info_ptr == 0)
     /* Attempt to interpret host as numeric inet address */
     {
-      numeric_addr = inet_addr (XSTRING (host)->data);
-      if (numeric_addr == -1)
+      numeric_addr = inet_addr ((char *) XSTRING (host)->data);
+      if (NUMERIC_ADDR_ERROR)
        error ("Unknown host \"%s\"", XSTRING (host)->data);
 
       host_info_ptr = &host_info;
       host_info.h_name = 0;
       host_info.h_aliases = 0;
       host_info.h_addrtype = AF_INET;
-      host_info.h_addr_list  =  &(addr_list[0]);
-      addr_list[0] = (char*)(&numeric_addr);
+#ifdef h_addr
+      /* Older machines have only one address slot called h_addr.
+        Newer machines have h_addr_list, but #define h_addr to
+        be its first element.  */
+      host_info.h_addr_list = &(addr_list[0]);
+#endif
+      host_info.h_addr = (char*)(&numeric_addr);
       addr_list[1] = 0;
-      host_info.h_length = strlen (addr_list[0]);
+      /* numeric_addr isn't null-terminated; it has fixed length.  */
+      host_info.h_length = sizeof (numeric_addr);
     }
 
   bzero (&address, sizeof address);
@@ -1446,18 +1714,66 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   if (s < 0) 
     report_file_error ("error creating socket", Fcons (name, Qnil));
 
+  /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
+     when connect is interrupted.  So let's not let it get interrupted.
+     Note we do not turn off polling, because polling is only used
+     when not interrupt_input, and thus not normally used on the systems
+     which have this bug.  On systems which use polling, there's no way
+     to quit if polling is turned off.  */
+  if (interrupt_input)
+    unrequest_sigio ();
+
  loop:
-  if (connect (s, &address, sizeof address) == -1)
+
+  immediate_quit = 1;
+  QUIT;
+
+  if (connect (s, (struct sockaddr *) &address, sizeof address) == -1
+      && errno != EISCONN)
     {
       int xerrno = errno;
+
+      immediate_quit = 0;
+
       if (errno == EINTR)
        goto loop;
+      if (errno == EADDRINUSE && retry < 20)
+       {
+         /* A delay here is needed on some FreeBSD systems,
+            and it is harmless, since this retrying takes time anyway
+            and should be infrequent.  */
+         Fsleep_for (make_number (1), Qnil);
+         retry++;
+         goto loop;
+       }
+
       close (s);
+
+      if (interrupt_input)
+       request_sigio ();
+
       errno = xerrno;
       report_file_error ("connection failed",
                         Fcons (host, Fcons (name, Qnil)));
     }
 
+  immediate_quit = 0;
+
+#ifdef POLL_FOR_INPUT
+  unbind_to (count, Qnil);
+#endif
+
+  if (interrupt_input)
+    request_sigio ();
+
+#else /* TERM */
+  s = connect_server (0);
+  if (s < 0)
+    report_file_error ("error creating socket", Fcons (name, Qnil));
+  send_command (s, C_PORT, 0, "%s:%d", XSTRING (host)->data, ntohs (port));
+  send_command (s, C_DUMB, 1, 0);
+#endif /* TERM */
+
   inch = s;
   outch = dup (s);
   if (outch < 0) 
@@ -1484,10 +1800,13 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Qnil;
   XPROCESS (proc)->pid = Qnil;
-  XFASTINT (XPROCESS (proc)->infd) = s;
-  XFASTINT (XPROCESS (proc)->outfd) = outch;
+  XSETINT (XPROCESS (proc)->infd, s);
+  XSETINT (XPROCESS (proc)->outfd, outch);
   XPROCESS (proc)->status = Qrun;
   FD_SET (inch, &input_wait_mask);
+  FD_SET (inch, &non_keyboard_wait_mask);
+  if (inch > max_process_desc)
+    max_process_desc = inch;
 
   UNGCPRO;
   return proc;
@@ -1500,10 +1819,10 @@ deactivate_process (proc)
   register int inchannel, outchannel;
   register struct Lisp_Process *p = XPROCESS (proc);
 
-  inchannel = XFASTINT (p->infd);
-  outchannel = XFASTINT (p->outfd);
+  inchannel = XINT (p->infd);
+  outchannel = XINT (p->outfd);
 
-  if (inchannel)
+  if (inchannel >= 0)
     {
       /* Beware SIGCHLD hereabouts. */
       flush_pending_output (inchannel);
@@ -1511,20 +1830,31 @@ deactivate_process (proc)
       {
        VMS_PROC_STUFF *get_vms_process_pointer (), *vs;
        sys$dassgn (outchannel);
-       vs = get_vms_process_pointer (p->pid)
+       vs = get_vms_process_pointer (p->pid);
        if (vs)
          give_back_vms_process_stuff (vs);
       }
 #else
       close (inchannel);
-      if (outchannel && outchannel != inchannel)
+      if (outchannel >= 0 && outchannel != inchannel)
        close (outchannel);
 #endif
 
-      XFASTINT (p->infd) = 0;
-      XFASTINT (p->outfd) = 0;
+      XSETINT (p->infd, -1);
+      XSETINT (p->outfd, -1);
       chan_process[inchannel] = Qnil;
       FD_CLR (inchannel, &input_wait_mask);
+      FD_CLR (inchannel, &non_keyboard_wait_mask);
+      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;
+       }
     }
 }
 
@@ -1534,6 +1864,7 @@ deactivate_process (proc)
 
 close_process_descs ()
 {
+#ifndef WINDOWSNT
   int i;
   for (i = 0; i < MAXDESC; i++)
     {
@@ -1541,14 +1872,15 @@ close_process_descs ()
       process = chan_process[i];
       if (!NILP (process))
        {
-         int in = XFASTINT (XPROCESS (process)->infd);
-         int out = XFASTINT (XPROCESS (process)->outfd);
-         if (in)
+         int in = XINT (XPROCESS (process)->infd);
+         int out = XINT (XPROCESS (process)->outfd);
+         if (in >= 0)
            close (in);
-         if (out && in != out)
+         if (out >= 0 && in != out)
            close (out);
        }
     }
+#endif
 }
 \f
 DEFUN ("accept-process-output", Faccept_process_output, Saccept_process_output,
@@ -1561,8 +1893,8 @@ Non-nil second arg TIMEOUT and third arg TIMEOUT-MSECS are number of\n\
 seconds and microseconds to wait; return after that much time whether\n\
 or not there is input.\n\
 Return non-nil iff we received any output before the timeout expired.")
-  (proc, timeout, timeout_msecs)
-     register Lisp_Object proc, timeout, timeout_msecs;
+  (process, timeout, timeout_msecs)
+     register Lisp_Object process, timeout, timeout_msecs;
 {
   int seconds;
   int useconds;
@@ -1571,8 +1903,8 @@ Return non-nil iff we received any output before the timeout expired.")
     {
       CHECK_NUMBER (timeout_msecs, 2);
       useconds = XINT (timeout_msecs);
-      if (XTYPE (timeout) != Lisp_Int)
-       XSET (timeout, Lisp_Int, 0);
+      if (!INTEGERP (timeout))
+       XSETINT (timeout, 0);
 
       {
        int carry = useconds / 1000000;
@@ -1590,26 +1922,29 @@ Return non-nil iff we received any output before the timeout expired.")
          }
       }
     }
+  else
+    useconds = 0;
 
   if (! NILP (timeout))
     {
       CHECK_NUMBER (timeout, 1);
       seconds = XINT (timeout);
-      if (seconds <= 0)
+      if (seconds < 0 || (seconds == 0 && useconds == 0))
        seconds = -1;
     }
   else
     {
-      if (NILP (proc))
+      if (NILP (process))
        seconds = -1;
       else
        seconds = 0;
     }
 
+  if (NILP (process))
+    XSETFASTINT (process, 0);
+
   return
-    (wait_reading_process_input (seconds, useconds,
-                                (NILP (proc)
-                                 ? XPROCESS (get_process (proc)) : 0), 0)
+    (wait_reading_process_input (seconds, useconds, process, 0)
      ? Qt : Qnil);
 }
 
@@ -1618,36 +1953,54 @@ Return non-nil iff we received any output before the timeout expired.")
    function Fwaiting_for_user_input_p below) whether emacs was waiting
    for user-input when that process-filter was called.
    waiting_for_input cannot be used as that is by definition 0 when
-   lisp code is being evalled */
+   lisp code is being evalled.
+   This is also used in record_asynch_buffer_change.
+   For that purpose, this must be 0
+   when not inside wait_reading_process_input.  */
 static int waiting_for_user_input_p;
 
+/* This is here so breakpoints can be put on it.  */
+static
+wait_reading_process_input_1 ()
+{
+}
+
 /* Read and dispose of subprocess output while waiting for timeout to
    elapse and/or keyboard input to be available.
 
-   time_limit is:
+   TIME_LIMIT is:
      timeout in seconds, or
      zero for no limit, or
      -1 means gobble data immediately available but don't wait for any.
 
-   read_kbd is:
+   MICROSECS is:
+     an additional duration to wait, measured in microseconds.
+     If this is nonzero and time_limit is 0, then the timeout
+     consists of MICROSECS only.
+
+   READ_KBD is a lisp value:
      0 to ignore keyboard input, or
      1 to return when input is available, or
-     -1 means caller will actually read the input, so don't throw to
+     -1 meaning caller will actually read the input, so don't throw to
        the quit handler, or
-     a pointer to a struct Lisp_Process, meaning wait until something
-       arrives from that process.  The return value is true iff we read
-       some input from that process.
+     a cons cell, meaning wait until its car is non-nil
+       (and gobble terminal input into the buffer if any arrives), or
+     a process object, meaning wait until something arrives from that
+       process.  The return value is true iff we read some input from
+       that process.
 
-   do_display != 0 means redisplay should be done to show subprocess
+   DO_DISPLAY != 0 means redisplay should be done to show subprocess
    output that arrives.
 
-   If read_kbd is a pointer to a struct Lisp_Process, then the
+   If READ_KBD is a pointer to a struct Lisp_Process, then the
      function returns true iff we received input from that process
      before the timeout elapsed.
-   Otherwise, return true iff we recieved input from any process.  */
+   Otherwise, return true iff we received input from any process.  */
 
 wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
-     int time_limit, microsecs, read_kbd, do_display;
+     int time_limit, microsecs;
+     Lisp_Object read_kbd;
+     int do_display;
 {
   register int channel, nfds, m;
   static SELECT_TYPE Available;
@@ -1655,21 +2008,30 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
   Lisp_Object proc;
   EMACS_TIME timeout, end_time, garbage;
   SELECT_TYPE Atemp;
-  int wait_channel = 0;
+  int wait_channel = -1;
   struct Lisp_Process *wait_proc = 0;
   int got_some_input = 0;
+  Lisp_Object *wait_for_cell = 0;
 
   FD_ZERO (&Available);
 
-  /* Detect when read_kbd is really the address of a Lisp_Process.  */
-  if (read_kbd > 10 || read_kbd < -1)
+  /* If read_kbd is a process to watch, set wait_proc and wait_channel
+     accordingly.  */
+  if (PROCESSP (read_kbd))
+    {
+      wait_proc = XPROCESS (read_kbd);
+      wait_channel = XINT (wait_proc->infd);
+      XSETFASTINT (read_kbd, 0);
+    }
+
+  /* If waiting for non-nil in a cell, record where.  */
+  if (CONSP (read_kbd))
     {
-      wait_proc = (struct Lisp_Process *) read_kbd;
-      wait_channel = XFASTINT (wait_proc->infd);
-      read_kbd = 0;
+      wait_for_cell = &XCONS (read_kbd)->car;
+      XSETFASTINT (read_kbd, 0);
     }
 
-  waiting_for_user_input_p = read_kbd;
+  waiting_for_user_input_p = XINT (read_kbd);
 
   /* Since we may need to wait several times,
      compute the absolute time to return at.  */
@@ -1680,33 +2042,18 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       EMACS_ADD_TIME (end_time, end_time, timeout);
     }
 
-  /* Turn off periodic alarms (in case they are in use)
-     because the select emulator uses alarms.  */
-  stop_polling ();
-
   while (1)
     {
+      int timeout_reduced_for_timers = 0;
+
       /* If calling from keyboard input, do not quit
         since we want to return C-g as an input character.
         Otherwise, do pending quit if requested.  */
-      if (read_kbd >= 0)
+      if (XINT (read_kbd) >= 0)
        QUIT;
 
-      /* If status of something has changed, and no input is available,
-        notify the user of the change right away */
-      if (update_tick != process_tick && do_display)
-       {
-         Atemp = input_wait_mask;
-         EMACS_SET_SECS_USECS (timeout, 0, 0);
-         if (select (MAXDESC, &Atemp, 0, 0, &timeout) <= 0)
-           status_notify ();
-       }
-
-      /* Don't wait for output from a non-running process.  */
-      if (wait_proc != 0 && !NILP (wait_proc->raw_status_low))
-       update_status (wait_proc);
-      if (wait_proc != 0
-         && ! EQ (wait_proc->status, Qrun))
+      /* Exit now if the cell we're waiting for became non-nil.  */
+      if (wait_for_cell && ! NILP (*wait_for_cell))
        break;
 
       /* Compute time from now till when time limit is up */
@@ -1731,26 +2078,109 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
          EMACS_SET_SECS_USECS (timeout, 100000, 0);
        }
 
+      /* If our caller will not immediately handle keyboard events,
+        run timer events directly.
+        (Callers that will immediately read keyboard events
+        call timer_delay on their own.)  */
+      if (1)
+       {
+         EMACS_TIME timer_delay;
+         int old_timers_run;
+
+       retry:
+         old_timers_run = timers_run;
+         timer_delay = timer_check (1);
+         if (timers_run != old_timers_run && do_display)
+           {
+             redisplay_preserve_echo_area ();
+             /* We must retry, since a timer may have requeued itself
+                and that could alter the time_delay.  */
+             goto retry;
+           }
+
+         if (! EMACS_TIME_NEG_P (timer_delay) && time_limit != -1)
+           {
+             EMACS_TIME difference;
+             EMACS_SUB_TIME (difference, timer_delay, timeout);
+             if (EMACS_TIME_NEG_P (difference))
+               {
+                 timeout = timer_delay;
+                 timeout_reduced_for_timers = 1;
+               }
+           }
+         else
+           {
+             /* This is so a breakpoint can be put here.  */
+             wait_reading_process_input_1 ();
+           }
+       }
+
       /* Cause C-g and alarm signals to take immediate action,
-        and cause input available signals to zero out timeout */
-      if (read_kbd < 0)
+        and cause input available signals to zero out timeout.
+
+        It is important that we do this before checking for process
+        activity.  If we get a SIGCHLD after the explicit checks for
+        process activity, timeout is the only way we will know.  */
+      if (XINT (read_kbd) < 0)
        set_waiting_for_input (&timeout);
 
-      /* Wait till there is something to do */
+      /* If status of something has changed, and no input is
+        available, notify the user of the change right away.  After
+        this explicit check, we'll let the SIGCHLD handler zap
+        timeout to get our attention.  */
+      if (update_tick != process_tick && do_display)
+       {
+         Atemp = input_wait_mask;
+         EMACS_SET_SECS_USECS (timeout, 0, 0);
+         if ((select (MAXDESC, &Atemp, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+                      &timeout)
+              <= 0))
+           {
+             /* It's okay for us to do this and then continue with
+                the loop, since timeout has already been zeroed out.  */
+             clear_waiting_for_input ();
+             status_notify ();
+           }
+       }
+
+      /* Don't wait for output from a non-running process.  */
+      if (wait_proc != 0 && !NILP (wait_proc->raw_status_low))
+       update_status (wait_proc);
+      if (wait_proc != 0
+         && ! EQ (wait_proc->status, Qrun))
+       {
+         clear_waiting_for_input ();
+         break;
+       }
 
-      Available = input_wait_mask;
-      if (!read_kbd)
-       FD_CLR (0, &Available);
+      /* Wait till there is something to do */
 
-      /* If a screen has been newly mapped and needs updating,
-        reprocess its display stuff.  */
-      if (screen_garbaged)
-       redisplay_preserve_echo_area ();
+      if (! XINT (read_kbd) && wait_for_cell == 0)
+       Available = non_keyboard_wait_mask;
+      else
+       Available = input_wait_mask;
+
+      /* If frame size has changed or the window is newly mapped,
+        redisplay now, before we start to wait.  There is a race
+        condition here; if a SIGIO arrives between now and the select
+        and indicates that a frame is trashed, the select may block
+        displaying a trashed screen.  */
+      if (frame_garbaged && do_display)
+       {
+         clear_waiting_for_input ();
+         redisplay_preserve_echo_area ();
+         if (XINT (read_kbd) < 0)
+           set_waiting_for_input (&timeout);
+       }
 
-      if (read_kbd && detect_input_pending ())
-       nfds = 0;
+      if (XINT (read_kbd) && detect_input_pending ())
+       {
+         nfds = 0;
+         FD_ZERO (&Available);
+       }
       else
-       nfds = select (MAXDESC, &Available, 0, 0, &timeout);
+       nfds = select (MAXDESC, &Available, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+                      &timeout);
 
       xerrno = errno;
 
@@ -1760,12 +2190,22 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /*  If we woke up due to SIGWINCH, actually change size now.  */
       do_pending_window_change ();
 
-      if (time_limit && nfds == 0)     /* timeout elapsed */
+      if (time_limit && nfds == 0 && ! timeout_reduced_for_timers)
+       /* We wanted the full specified time, so return now.  */
        break;
       if (nfds < 0)
        {
          if (xerrno == EINTR)
            FD_ZERO (&Available);
+#ifdef ultrix
+         /* Ultrix select seems to return ENOMEM when it is
+            interrupted.  Treat it just like EINTR.  Bleah.  Note
+            that we want to test for the "ultrix" CPP symbol, not
+            "__ultrix__"; the latter is only defined under GCC, but
+            not by DEC's bundled CC.  -JimB  */
+         else if (xerrno == ENOMEM)
+           FD_ZERO (&Available);
+#endif
 #ifdef ALLIANT
          /* This happens for no known reason on ALLIANT.
             I am guessing that this is the right response. -- RMS.  */
@@ -1780,19 +2220,26 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 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.
+                in m/ibmrt-aix.h), and here we just ignore the select error.
                 Cleanup occurs c/o status_notify after SIGCLD. */
-             FD_ZERO (&Available);          /* Cannot depend on values returned */
+             FD_ZERO (&Available); /* Cannot depend on values returned */
 #else
              abort ();
 #endif
            }
          else
-           error("select error: %s", sys_errlist[xerrno]);
+           error ("select error: %s", strerror (xerrno));
        }
-#ifdef sun
-      else if (nfds > 0 && FD_ISSET (0, &Available) && interrupt_input)
-       /* System sometimes fails to deliver SIGIO.  */
+#if defined(sun) && !defined(USG5_4)
+      else if (nfds > 0 && keyboard_bit_set (&Available)
+              && interrupt_input)
+       /* System sometimes fails to deliver SIGIO.
+
+          David J. Mackenzie says that Emacs doesn't compile under
+          Solaris if this code is enabled, thus the USG5_4 in the CPP
+          conditional.  "I haven't noticed any ill effects so far.
+          If you find a Solaris expert somewhere, they might know
+          better." */
        kill (getpid (), SIGIO);
 #endif
 
@@ -1800,37 +2247,51 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /* If there is any, return immediately
         to give it higher priority than subprocesses */
 
-      if (read_kbd && detect_input_pending ())
+      if (XINT (read_kbd) < 0 && detect_input_pending ())
+       {
+         swallow_events (do_display);
+         if (detect_input_pending ())
+           break;
+       }
+
+      if ((XINT (read_kbd) > 0 || wait_for_cell)
+         && detect_input_pending_run_timers (do_display))
+       {
+         swallow_events (do_display);
+         if (detect_input_pending_run_timers (do_display))
+           break;
+       }
+
+      /* Exit now if the cell we're waiting for became non-nil.  */
+      if (wait_for_cell && ! NILP (*wait_for_cell))
        break;
 
+#ifdef SIGIO
       /* If we think we have keyboard input waiting, but didn't get SIGIO
         go read it.  This can happen with X on BSD after logging out.
         In that case, there really is no input and no SIGIO,
         but select says there is input.  */
 
-      /*
-      if (read_kbd && interrupt_input && (Available & fileno (stdin)))
-      */
-      if (read_kbd && interrupt_input && (FD_ISSET (fileno (stdin), &Available)))
-       kill (0, SIGIO);
-
-#ifdef vipc
-      /* Check for connection from other process */
-
-      if (Available & ChannelMask (comm_server))
-       {
-         Available &= ~(ChannelMask (comm_server));
-         create_commchan ();
-       }
-#endif vipc
+      if (XINT (read_kbd) && interrupt_input
+         && (keyboard_bit_set (&Available)))
+       kill (getpid (), SIGIO);
+#endif
 
       if (! wait_proc)
        got_some_input |= nfds > 0;
 
-      /* Check for data from a process or a command channel */
-      for (channel = FIRST_PROC_DESC; channel < MAXDESC; channel++)
+      /* If checking input just got us a size-change event from X,
+        obey it now if we should.  */
+      if (XINT (read_kbd) || wait_for_cell)
+       do_pending_window_change ();
+
+      /* Check for data from a process.  */
+      /* Really FIRST_PROC_DESC should be 0 on Unix,
+        but this is safer in the short run.  */
+      for (channel = 0; channel <= max_process_desc; channel++)
        {
-         if (FD_ISSET (channel, &Available))
+         if (FD_ISSET (channel, &Available)
+             && FD_ISSET (channel, &non_keyboard_wait_mask))
            {
              int nread;
 
@@ -1839,7 +2300,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 waiting.  */
              if (wait_channel == channel)
                {
-                 wait_channel = 0;
+                 wait_channel = -1;
                  time_limit = -1;
                  got_some_input = 1;
                }
@@ -1847,24 +2308,6 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
              if (NILP (proc))
                continue;
 
-#ifdef vipc
-             /* It's a command channel */
-             if (!NILP (XPROCESS (proc)->command_channel_p))
-               {
-                 ProcessCommChan (channel, proc);
-                 if (NILP (XPROCESS (proc)->command_channel_p))
-                   {
-                     /* It has ceased to be a command channel! */
-                     int bytes_available;
-                     if (ioctl (channel, FIONREAD, &bytes_available) < 0)
-                       bytes_available = 0;
-                     if (bytes_available)
-                       FD_SET (channel, &Available);
-                   }
-                 continue;
-               }
-#endif /* vipc */
-
              /* Read data from the process, starting with our
                 buffered-ahead character if we have one.  */
 
@@ -1897,9 +2340,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 subprocess termination and SIGCHLD.  */
              else if (nread == 0 && !NETCONN_P (proc))
                ;
-#endif /* O_NDELAY */
-#endif /* O_NONBLOCK */
-#endif /* EWOULDBLOCK */
+#endif                         /* O_NDELAY */
+#endif                         /* O_NONBLOCK */
+#endif                         /* EWOULDBLOCK */
 #ifdef HAVE_PTYS
              /* On some OSs with ptys, when the process on one end of
                 a pty exits, the other end gets an error reading with
@@ -1910,9 +2353,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 get a SIGCHLD). */
              else if (nread == -1 && errno == EIO)
                ;
-#endif /* HAVE_PTYS */
-/* If we can detect process termination, don't consider the process
-   gone just because its pipe is closed.  */
+#endif                         /* HAVE_PTYS */
+             /* If we can detect process termination, don't consider the process
+                gone just because its pipe is closed.  */
 #ifdef SIGCHLD
              else if (nread == 0 && !NETCONN_P (proc))
                ;
@@ -1929,15 +2372,43 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                      = Fcons (Qexit, Fcons (make_number (256), Qnil));
                }
            }
-       } /* end for each file descriptor */
-    } /* end while exit conditions not met */
+       }                       /* end for each file descriptor */
+    }                          /* end while exit conditions not met */
 
-  /* Resume periodic signals to poll for input, if necessary.  */
-  start_polling ();
+  waiting_for_user_input_p = 0;
+
+  /* If calling from keyboard input, do not quit
+     since we want to return C-g as an input character.
+     Otherwise, do pending quit if requested.  */
+  if (XINT (read_kbd) >= 0)
+    {
+      /* Prevent input_pending from remaining set if we quit.  */
+      clear_input_pending ();
+      QUIT;
+    }
 
   return got_some_input;
 }
 \f
+/* Given a list (FUNCTION ARGS...), apply FUNCTION to the ARGS.  */
+
+static Lisp_Object
+read_process_output_call (fun_and_args)
+     Lisp_Object fun_and_args;
+{
+  return apply1 (XCONS (fun_and_args)->car, XCONS (fun_and_args)->cdr);
+}
+
+static Lisp_Object
+read_process_output_error_handler (error)
+     Lisp_Object error;
+{
+  cmd_error_internal (error, "error in process filter: ");
+  Vinhibit_quit = Qt;
+  update_echo_area ();
+  Fsleep_for (make_number (2), Qnil);
+}
+
 /* Read pending output from the process channel,
    starting with our buffered-ahead character if we have one.
    Yield number of characters read.
@@ -1984,12 +2455,20 @@ read_process_output (proc, channel)
 #else /* not VMS */
 
   if (proc_buffered_char[channel] < 0)
+#ifdef WINDOWSNT
+    nchars = read_child_output (channel, chars, sizeof (chars));
+#else
     nchars = read (channel, chars, sizeof chars);
+#endif
   else
     {
       chars[0] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
+#ifdef WINDOWSNT
+      nchars = read_child_output (channel, chars + 1, sizeof (chars) - 1);
+#else
       nchars = read (channel, chars + 1, sizeof chars - 1);
+#endif
       if (nchars < 0)
        nchars = 1;
       else
@@ -2006,43 +2485,108 @@ read_process_output (proc, channel)
         hitting ^G when a filter happens to be running won't screw
         it up.  */
       int count = specpdl_ptr - specpdl;
+      Lisp_Object odeactivate;
+      Lisp_Object obuffer, okeymap;
+
+      /* 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;
+      XSETBUFFER (obuffer, current_buffer);
+      okeymap = current_buffer->keymap;
+
       specbind (Qinhibit_quit, Qt);
-      call2 (outstream, proc, make_string (chars, nchars));
+      specbind (Qlast_nonmenu_event, Qt);
+
+      running_asynch_code = 1;
+      internal_condition_case_1 (read_process_output_call,
+                                Fcons (outstream,
+                                       Fcons (proc,
+                                              Fcons (make_string (chars,
+                                                                  nchars),
+                                                     Qnil))),
+                                !NILP (Vdebug_on_error) ? Qnil : Qerror,
+                                read_process_output_error_handler);
+      running_asynch_code = 0;
+      restore_match_data ();
+
+      /* Handling the process output should not deactivate the mark.  */
+      Vdeactivate_mark = odeactivate;
+
+#if 0 /* Call record_asynch_buffer_change unconditionally,
+        because we might have changed minor modes or other things
+        that affect key bindings.  */
+      if (! EQ (Fcurrent_buffer (), obuffer)
+         || ! EQ (current_buffer->keymap, okeymap))
+#endif
+       /* But do it only if the caller is actually going to read events.
+          Otherwise there's no need to make him wake up, and it could
+          cause trouble (for example it would make Fsit_for return).  */
+       if (waiting_for_user_input_p == -1)
+         record_asynch_buffer_change ();
 
 #ifdef VMS
       start_vms_process_read (vs);
 #endif
-      unbind_to (count);
+      unbind_to (count, Qnil);
       return nchars;
     }
 
   /* If no filter, write into buffer if it isn't dead.  */
   if (!NILP (p->buffer) && !NILP (XBUFFER (p->buffer)->name))
     {
-      Lisp_Object tem;
+      Lisp_Object old_read_only;
+      Lisp_Object old_begv, old_zv;
+      Lisp_Object odeactivate;
+
+      odeactivate = Vdeactivate_mark;
 
       Fset_buffer (p->buffer);
       opoint = point;
+      old_read_only = current_buffer->read_only;
+      XSETFASTINT (old_begv, BEGV);
+      XSETFASTINT (old_zv, ZV);
+
+      current_buffer->read_only = Qnil;
 
       /* 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 (marker_position (p->mark));
+       SET_PT (clip_to_bounds (BEGV, marker_position (p->mark), ZV));
       else
        SET_PT (ZV);
+
+      /* If the output marker is outside of the visible region, save
+        the restriction and widen.  */
+      if (! (BEGV <= point && point <= ZV))
+       Fwiden ();
+
+      /* Make sure opoint floats ahead of any new text, just as point
+        would.  */
       if (point <= opoint)
        opoint += nchars;
 
-      tem = current_buffer->read_only;
-      current_buffer->read_only = Qnil;
+      /* Insert after old_begv, but before old_zv.  */
+      if (point < XFASTINT (old_begv))
+       XSETFASTINT (old_begv, XFASTINT (old_begv) + nchars);
+      if (point <= XFASTINT (old_zv))
+       XSETFASTINT (old_zv, XFASTINT (old_zv) + nchars);
+
       /* Insert before markers in case we are inserting where
         the buffer's mark is, and the user's next command is Meta-y.  */
       insert_before_markers (chars, nchars);
-      current_buffer->read_only = tem;
       Fset_marker (p->mark, make_number (point), p->buffer);
+
       update_mode_lines++;
 
+      /* If the restriction isn't what it should be, set it.  */
+      if (XFASTINT (old_begv) != BEGV || XFASTINT (old_zv) != ZV)
+       Fnarrow_to_region (old_begv, old_zv);
+
+      /* Handling the process output should not deactivate the mark.  */
+      Vdeactivate_mark = odeactivate;
+
+      current_buffer->read_only = old_read_only;
       SET_PT (opoint);
       set_buffer_internal (old);
     }
@@ -2054,11 +2598,11 @@ read_process_output (proc, channel)
 
 DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, Swaiting_for_user_input_p,
        0, 0, 0,
-  "Returns non-NIL if emacs is waiting for input from the user.\n\
+  "Returns non-nil if emacs is waiting for input from the user.\n\
 This is intended for use by asynchronous process output filters and sentinels.")
        ()
 {
-  return ((waiting_for_user_input_p) ? Qt : Qnil);
+  return (waiting_for_user_input_p ? Qt : Qnil);
 }
 \f
 /* Sending data to subprocess */
@@ -2075,15 +2619,19 @@ send_process_trap ()
   longjmp (send_process_frame, 1);
 }
 
-send_process (proc, buf, len)
-     Lisp_Object proc;
+/* Send some data to process PROC.
+   BUF is the beginning of the data; LEN is the number of characters.
+   OBJECT is the Lisp object that the data comes from.  */
+
+send_process (proc, buf, len, object)
+     volatile Lisp_Object proc;
      char *buf;
      int len;
+     Lisp_Object object;
 {
-  /* Don't use register vars; longjmp can lose them.  */
+  /* Use volatile to protect variables from being clobbered by longjmp.  */
   int rv;
-  unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data;
-
+  volatile unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data;
 
 #ifdef VMS
   struct Lisp_Process *p = XPROCESS (proc);
@@ -2102,44 +2650,111 @@ send_process (proc, buf, len)
   else if (write_to_vms_process (vs, buf, len))
     ;
 #else
+
+  if (pty_max_bytes == 0)
+    {
+#if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON)
+      pty_max_bytes = fpathconf (XFASTINT (XPROCESS (proc)->outfd),
+                                _PC_MAX_CANON);
+      if (pty_max_bytes < 0)
+       pty_max_bytes = 250;
+#else
+      pty_max_bytes = 250;
+#endif
+      /* Deduct one, to leave space for the eof.  */
+      pty_max_bytes--;
+    }
+
   if (!setjmp (send_process_frame))
     while (len > 0)
       {
        int this = len;
-       /* Don't send more than 500 bytes at a time.  */
-       if (this > 500)
-         this = 500;
-       signal (SIGPIPE, send_process_trap);
-       rv = write (XFASTINT (XPROCESS (proc)->outfd), buf, this);
-       signal (SIGPIPE, SIG_DFL);
-       if (rv < 0)
+       SIGTYPE (*old_sigpipe)();
+       int flush_pty = 0;
+
+       /* Decide how much data we can send in one batch.
+          Long lines need to be split into multiple batches.  */
+       if (!NILP (XPROCESS (proc)->pty_flag))
+         {
+           /* Starting this at zero is always correct when not the first iteration
+              because the previous iteration ended by sending C-d.
+              It may not be correct for the first iteration
+              if a partial line was sent in a separate send_process call.
+              If that proves worth handling, we need to save linepos
+              in the process object.  */
+           int linepos = 0;
+           char *ptr = buf;
+           char *end = buf + len;
+
+           /* Scan through this text for a line that is too long.  */
+           while (ptr != end && linepos < pty_max_bytes)
+             {
+               if (*ptr == '\n')
+                 linepos = 0;
+               else
+                 linepos++;
+               ptr++;
+             }
+           /* If we found one, break the line there
+              and put in a C-d to force the buffer through.  */
+           this = ptr - buf;
+         }
+
+       /* Send this batch, using one or more write calls.  */
+       while (this > 0)
          {
-           if (0
+           old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap);
+           rv = write (XINT (XPROCESS (proc)->outfd), buf, this);
+           signal (SIGPIPE, old_sigpipe);
+
+           if (rv < 0)
+             {
+               if (0
 #ifdef EWOULDBLOCK
-               || errno == EWOULDBLOCK
+                   || errno == EWOULDBLOCK
 #endif
 #ifdef EAGAIN
-               || errno == EAGAIN
-#endif
-               )
-             {
-               /* It would be nice to accept process output here,
-                  but that is difficult.  For example, it could
-                  garbage what we are sending if that is from a buffer.  */
-               immediate_quit = 1;
-               QUIT;
-               sleep (1);
-               immediate_quit = 0;
-               continue;
+                   || errno == EAGAIN
+#endif
+                   )
+                 /* Buffer is full.  Wait, accepting input; 
+                    that may allow the program
+                    to finish doing output and read more.  */
+                 {
+                   Lisp_Object zero;
+                   int offset;
+
+                   /* Running filters might relocate buffers or strings.
+                      Arrange to relocate BUF.  */
+                   if (BUFFERP (object))
+                     offset = BUF_PTR_CHAR_POS (XBUFFER (object),
+                                                (unsigned char *) buf);
+                   else if (STRINGP (object))
+                     offset = buf - (char *) XSTRING (object)->data;
+
+                   XSETFASTINT (zero, 0);
+                   wait_reading_process_input (1, 0, zero, 0);
+
+                   if (BUFFERP (object))
+                     buf = (char *) BUF_CHAR_ADDRESS (XBUFFER (object), offset);
+                   else if (STRINGP (object))
+                     buf = offset + (char *) XSTRING (object)->data;
+
+                   rv = 0;
+                 }
+               else
+                 /* This is a real error.  */
+                 report_file_error ("writing to process", Fcons (proc, Qnil));
              }
-           report_file_error ("writing to process", Fcons (proc, Qnil));
+           buf += rv;
+           len -= rv;
+           this -= rv;
          }
-       buf += rv;
-       len -= rv;
-       /* Allow input from processes between bursts of sending.
-          Otherwise things may get stopped up.  */
+
+       /* If we sent just part of the string, put in an EOF
+          to force it through, before we send the rest.  */
        if (len > 0)
-         wait_reading_process_input (-1, 0, 0, 0);
+         Fprocess_send_eof (proc);
       }
 #endif
   else
@@ -2160,7 +2775,8 @@ send_process (proc, buf, len)
 DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region,
   3, 3, 0,
   "Send current contents of region as input to PROCESS.\n\
-PROCESS may be a process name or an actual process.\n\
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.\n\
 Called from program, takes three arguments, PROCESS, START and END.\n\
 If the region is more than 500 characters long,\n\
 it is sent in several bunches.  This may happen even for shorter regions.\n\
@@ -2178,7 +2794,8 @@ Output from processes can arrive in between bunches.")
     move_gap (start);
 
   start1 = XINT (start);
-  send_process (proc, &FETCH_CHAR (start1), XINT (end) - XINT (start));
+  send_process (proc, &FETCH_CHAR (start1), XINT (end) - XINT (start),
+               Fcurrent_buffer ());
 
   return Qnil;
 }
@@ -2186,7 +2803,8 @@ Output from processes can arrive in between bunches.")
 DEFUN ("process-send-string", Fprocess_send_string, Sprocess_send_string,
   2, 2, 0,
   "Send PROCESS the contents of STRING as input.\n\
-PROCESS may be a process name or an actual process.\n\
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.\n\
 If STRING is more than 500 characters long,\n\
 it is sent in several bunches.  This may happen even for shorter strings.\n\
 Output from processes can arrive in between bunches.")
@@ -2196,7 +2814,7 @@ Output from processes can arrive in between bunches.")
   Lisp_Object proc;
   CHECK_STRING (string, 1);
   proc = get_process (process);
-  send_process (proc, XSTRING (string)->data, XSTRING (string)->size);
+  send_process (proc, XSTRING (string)->data, XSTRING (string)->size, string);
   return Qnil;
 }
 \f
@@ -2205,8 +2823,13 @@ Output from processes can arrive in between bunches.")
    the terminal being used to communicate with PROCESS.
    This is used for various commands in shell mode.
    If NOMSG is zero, insert signal-announcements into process's buffers
-   right away.  */
+   right away.
+
+   If we can, we try to signal PROCESS by sending control characters
+   down the pty.  This allows us to signal inferiors who have changed
+   their uid, for which killpg would return an EPERM error.  */
 
+static void
 process_send_signal (process, signo, current_group, nomsg)
      Lisp_Object process;
      int signo;
@@ -2224,67 +2847,112 @@ process_send_signal (process, signo, current_group, nomsg)
   if (!EQ (p->childp, Qt))
     error ("Process %s is not a subprocess",
           XSTRING (p->name)->data);
-  if (!XFASTINT (p->infd))
+  if (XINT (p->infd) < 0)
     error ("Process %s is not active",
           XSTRING (p->name)->data);
 
   if (NILP (p->pty_flag))
     current_group = Qnil;
 
-#ifdef TIOCGPGRP               /* Not sure about this! (fnf) */
   /* If we are using pgrps, get a pgrp number and make it negative.  */
   if (!NILP (current_group))
     {
+#ifdef SIGNALS_VIA_CHARACTERS
       /* If possible, send signals to the entire pgrp
         by sending an input character to it.  */
+
+      /* TERMIOS is the latest and bestest, and seems most likely to
+         work.  If the system has it, use it.  */
+#ifdef HAVE_TERMIOS
+      struct termios t;
+
+      switch (signo)
+       {
+       case SIGINT:
+         tcgetattr (XINT (p->infd), &t);
+         send_process (proc, &t.c_cc[VINTR], 1, Qnil);
+         return;
+
+       case SIGQUIT:
+         tcgetattr (XINT (p->infd), &t);
+         send_process (proc, &t.c_cc[VQUIT], 1, Qnil);
+         return;
+
+       case SIGTSTP:
+         tcgetattr (XINT (p->infd), &t);
+#if defined (VSWTCH) && !defined (PREFER_VSUSP)
+         send_process (proc, &t.c_cc[VSWTCH], 1, Qnil);
+#else
+         send_process (proc, &t.c_cc[VSUSP], 1, Qnil);
+#endif
+         return;
+       }
+
+#else /* ! HAVE_TERMIOS */
+
+      /* On Berkeley descendants, the following IOCTL's retrieve the
+        current control characters.  */
 #if defined (TIOCGLTC) && defined (TIOCGETC)
+
       struct tchars c;
       struct ltchars lc;
 
       switch (signo)
        {
        case SIGINT:
-         ioctl (XFASTINT (p->infd), TIOCGETC, &c);
-         send_process (proc, &c.t_intrc, 1);
-         return Qnil;
+         ioctl (XINT (p->infd), TIOCGETC, &c);
+         send_process (proc, &c.t_intrc, 1, Qnil);
+         return;
        case SIGQUIT:
-         ioctl (XFASTINT (p->infd), TIOCGETC, &c);
-         send_process (proc, &c.t_quitc, 1);
-         return Qnil;
+         ioctl (XINT (p->infd), TIOCGETC, &c);
+         send_process (proc, &c.t_quitc, 1, Qnil);
+         return;
+#ifdef SIGTSTP
        case SIGTSTP:
-         ioctl (XFASTINT (p->infd), TIOCGLTC, &lc);
-         send_process (proc, &lc.t_suspc, 1);
-         return Qnil;
+         ioctl (XINT (p->infd), TIOCGLTC, &lc);
+         send_process (proc, &lc.t_suspc, 1, Qnil);
+         return;
+#endif /* ! defined (SIGTSTP) */
        }
-#endif /* have TIOCGLTC and have TIOCGETC */
-      /* It is possible that the following code would work
-        on other kinds of USG systems, not just on the IRIS.
-        This should be tried in Emacs 19.  */
-#if defined (IRIS) && defined (HAVE_SETSID) /* Check for Irix, not older
-                                              systems.  */
+
+#else /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
+
+      /* On SYSV descendants, the TCGETA ioctl retrieves the current control
+        characters.  */
+#ifdef TCGETA
       struct termio t;
       switch (signo)
        {
        case SIGINT:
-         ioctl (XFASTINT (p->infd), TCGETA, &t);
-         send_process (proc, &t.c_cc[VINTR], 1);
-         return Qnil;
+         ioctl (XINT (p->infd), TCGETA, &t);
+         send_process (proc, &t.c_cc[VINTR], 1, Qnil);
+         return;
        case SIGQUIT:
-         ioctl (XFASTINT (p->infd), TCGETA, &t);
-         send_process (proc, &t.c_cc[VQUIT], 1);
-         return Qnil;
+         ioctl (XINT (p->infd), TCGETA, &t);
+         send_process (proc, &t.c_cc[VQUIT], 1, Qnil);
+         return;
+#ifdef SIGTSTP
        case SIGTSTP:
-         ioctl (XFASTINT (p->infd), TCGETA, &t);
-         send_process (proc, &t.c_cc[VSWTCH], 1);
-         return Qnil;
+         ioctl (XINT (p->infd), TCGETA, &t);
+         send_process (proc, &t.c_cc[VSWTCH], 1, Qnil);
+         return;
+#endif /* ! defined (SIGTSTP) */
        }
-#endif /* IRIS and HAVE_SETSID */
-
+#else /* ! defined (TCGETA) */
+      Your configuration files are messed up.
+      /* If your system configuration files define SIGNALS_VIA_CHARACTERS,
+        you'd better be using one of the alternatives above!  */
+#endif /* ! defined (TCGETA) */
+#endif /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
+#endif /* ! defined HAVE_TERMIOS */
+#endif /* ! defined (SIGNALS_VIA_CHARACTERS) */
+
+#ifdef TIOCGPGRP 
       /* Get the pgrp using the tty itself, if we have that.
         Otherwise, use the pty to get the pgrp.
         On pfa systems, saka@pfu.fujitsu.co.JP writes:
-        "TICGPGRP symbol defined in sys/ioctl.h at E50.
-         But, TIOCGPGRP donot work on E50 ;-P work fine on E60"
+        "TIOCGPGRP symbol defined in sys/ioctl.h at E50.
+        But, TIOCGPGRP does not work on E50 ;-P works fine on E60"
         His patch indicates that if TIOCGPGRP returns an error, then
         we should just assume that p->pid is also the process group id.  */
       {
@@ -2293,25 +2961,25 @@ process_send_signal (process, signo, current_group, nomsg)
        if (!NILP (p->subtty))
          err = ioctl (XFASTINT (p->subtty), TIOCGPGRP, &gid);
        else
-         err = ioctl (XFASTINT (p->infd), TIOCGPGRP, &gid);
+         err = ioctl (XINT (p->infd), TIOCGPGRP, &gid);
 
 #ifdef pfa
        if (err == -1)
          gid = - XFASTINT (p->pid);
-#endif
+#endif /* ! defined (pfa) */
       }
       if (gid == -1)
        no_pgrp = 1;
       else
        gid = - gid;
+#else  /* ! defined (TIOCGPGRP ) */
+      /* Can't select pgrps on this system, so we know that
+        the child itself heads the pgrp.  */
+      gid = - XFASTINT (p->pid);
+#endif /* ! defined (TIOCGPGRP ) */
     }
   else
     gid = - XFASTINT (p->pid);
-#else /* not using pgrps */
-  /* Can't select pgrps on this system, so we know that
-     the child itself heads the pgrp.  */
-  gid = - XFASTINT (p->pid);
-#endif /* not using pgrps */
 
   switch (signo)
     {
@@ -2324,15 +2992,15 @@ process_send_signal (process, signo, current_group, nomsg)
       if (!nomsg)
        status_notify ();
       break;
-#endif
+#endif /* ! defined (SIGCONT) */
     case SIGINT:
 #ifdef VMS
-      send_process (proc, "\003", 1);  /* ^C */
+      send_process (proc, "\003", 1, Qnil);    /* ^C */
       goto whoosh;
 #endif
     case SIGQUIT:
 #ifdef VMS
-      send_process (proc, "\031", 1);  /* ^Y */
+      send_process (proc, "\031", 1, Qnil);    /* ^Y */
       goto whoosh;
 #endif
     case SIGKILL:
@@ -2340,7 +3008,7 @@ process_send_signal (process, signo, current_group, nomsg)
       sys$forcex (&(XFASTINT (p->pid)), 0, 1);
       whoosh:
 #endif
-      flush_pending_output (XFASTINT (p->infd));
+      flush_pending_output (XINT (p->infd));
       break;
     }
 
@@ -2356,20 +3024,21 @@ process_send_signal (process, signo, current_group, nomsg)
   /* gid may be a pid, or minus a pgrp's number */
 #ifdef TIOCSIGSEND
   if (!NILP (current_group))
-    ioctl (XFASTINT (p->infd), TIOCSIGSEND, signo);
+    ioctl (XINT (p->infd), TIOCSIGSEND, signo);
   else
     {
       gid = - XFASTINT (p->pid);
       kill (gid, signo);
     }
-#else /* no TIOCSIGSEND */
+#else /* ! defined (TIOCSIGSEND) */
   EMACS_KILLPG (-gid, signo);
-#endif
+#endif /* ! defined (TIOCSIGSEND) */
 }
 
 DEFUN ("interrupt-process", Finterrupt_process, Sinterrupt_process, 0, 2, 0,
   "Interrupt process PROCESS.  May be process or name of one.\n\
-Nil or no arg means current buffer's process.\n\
+PROCESS may be a process, a buffer, or the name of a process or buffer.\n\
+nil or no arg means current buffer's process.\n\
 Second arg CURRENT-GROUP non-nil means send signal to\n\
 the current process-group of the process's controlling terminal\n\
 rather than to the process's own process group.\n\
@@ -2432,46 +3101,165 @@ See function `interrupt-process' for more details on usage.")
 
 DEFUN ("signal-process", Fsignal_process, Ssignal_process,
   2, 2, "nProcess number: \nnSignal code: ",
-  "Send the process with number PID the signal with code CODE.\n\
-Both PID and CODE are integers.")
-  (pid, sig)
-     Lisp_Object pid, sig;
+  "Send the process with process id PID the signal with code SIGCODE.\n\
+PID must be an integer.  The process need not be a child of this Emacs.\n\
+SIGCODE may be an integer, or a symbol whose name is a signal name.")
+  (pid, sigcode)
+     Lisp_Object pid, sigcode;
 {
   CHECK_NUMBER (pid, 0);
-  CHECK_NUMBER (sig, 1);
-  return make_number (kill (XINT (pid), XINT (sig)));
+
+#define handle_signal(NAME, VALUE)             \
+  else if (!strcmp (name, NAME))               \
+    XSETINT (sigcode, VALUE)
+
+  if (INTEGERP (sigcode))
+    ;
+  else
+    {
+      unsigned char *name;
+
+      CHECK_SYMBOL (sigcode, 1);
+      name = XSYMBOL (sigcode)->name->data;
+
+      if (0)
+       ;
+#ifdef SIGHUP
+      handle_signal ("SIGHUP", SIGHUP);
+#endif
+#ifdef SIGINT
+      handle_signal ("SIGINT", SIGINT);
+#endif
+#ifdef SIGQUIT
+      handle_signal ("SIGQUIT", SIGQUIT);
+#endif
+#ifdef SIGILL
+      handle_signal ("SIGILL", SIGILL);
+#endif
+#ifdef SIGABRT
+      handle_signal ("SIGABRT", SIGABRT);
+#endif
+#ifdef SIGEMT
+      handle_signal ("SIGEMT", SIGEMT);
+#endif
+#ifdef SIGKILL
+      handle_signal ("SIGKILL", SIGKILL);
+#endif
+#ifdef SIGFPE
+      handle_signal ("SIGFPE", SIGFPE);
+#endif
+#ifdef SIGBUS
+      handle_signal ("SIGBUS", SIGBUS);
+#endif
+#ifdef SIGSEGV
+      handle_signal ("SIGSEGV", SIGSEGV);
+#endif
+#ifdef SIGSYS
+      handle_signal ("SIGSYS", SIGSYS);
+#endif
+#ifdef SIGPIPE
+      handle_signal ("SIGPIPE", SIGPIPE);
+#endif
+#ifdef SIGALRM
+      handle_signal ("SIGALRM", SIGALRM);
+#endif
+#ifdef SIGTERM
+      handle_signal ("SIGTERM", SIGTERM);
+#endif
+#ifdef SIGURG
+      handle_signal ("SIGURG", SIGURG);
+#endif
+#ifdef SIGSTOP
+      handle_signal ("SIGSTOP", SIGSTOP);
+#endif
+#ifdef SIGTSTP
+      handle_signal ("SIGTSTP", SIGTSTP);
+#endif
+#ifdef SIGCONT
+      handle_signal ("SIGCONT", SIGCONT);
+#endif
+#ifdef SIGCHLD
+      handle_signal ("SIGCHLD", SIGCHLD);
+#endif
+#ifdef SIGTTIN
+      handle_signal ("SIGTTIN", SIGTTIN);
+#endif
+#ifdef SIGTTOU
+      handle_signal ("SIGTTOU", SIGTTOU);
+#endif
+#ifdef SIGIO
+      handle_signal ("SIGIO", SIGIO);
+#endif
+#ifdef SIGXCPU
+      handle_signal ("SIGXCPU", SIGXCPU);
+#endif
+#ifdef SIGXFSZ
+      handle_signal ("SIGXFSZ", SIGXFSZ);
+#endif
+#ifdef SIGVTALRM
+      handle_signal ("SIGVTALRM", SIGVTALRM);
+#endif
+#ifdef SIGPROF
+      handle_signal ("SIGPROF", SIGPROF);
+#endif
+#ifdef SIGWINCH
+      handle_signal ("SIGWINCH", SIGWINCH);
+#endif
+#ifdef SIGINFO
+      handle_signal ("SIGINFO", SIGINFO);
+#endif
+#ifdef SIGUSR1
+      handle_signal ("SIGUSR1", SIGUSR1);
+#endif
+#ifdef SIGUSR2
+      handle_signal ("SIGUSR2", SIGUSR2);
+#endif
+      else
+       error ("Undefined signal name %s", name);
+    }
+
+#undef handle_signal
+
+#ifdef WINDOWSNT
+  /* Only works for kill-type signals */
+  return make_number (win32_kill_process (XINT (pid), XINT (sigcode)));
+#else
+  return make_number (kill (XINT (pid), XINT (sigcode)));
+#endif
 }
 
 DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
   "Make PROCESS see end-of-file in its input.\n\
 Eof comes after any text already sent to it.\n\
-nil or no arg means current buffer's process.")
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.\n\
+If PROCESS is a network connection, or is a process communicating\n\
+through a pipe (as opposed to a pty), then you cannot send any more\n\
+text to PROCESS after you call this function.")
   (process)
      Lisp_Object process;
 {
   Lisp_Object proc;
 
   proc = get_process (process);
-  /* Sending a zero-length record is supposed to mean eof
-     when TIOCREMOTE is turned on.  */
-#ifdef DID_REMOTE
-  {
-    char buf[1];
-    write (XFASTINT (XPROCESS (proc)->outfd), buf, 0);
-  }
-#else /* did not do TOICREMOTE */
+
+  /* Make sure the process is really alive.  */
+  if (! NILP (XPROCESS (proc)->raw_status_low))
+    update_status (XPROCESS (proc));
+  if (! EQ (XPROCESS (proc)->status, Qrun))
+    error ("Process %s not running", XSTRING (XPROCESS (proc)->name)->data);
+
 #ifdef VMS
-  send_process (proc, "\032", 1);      /* ^z */
+  send_process (proc, "\032", 1, Qnil);        /* ^z */
 #else
   if (!NILP (XPROCESS (proc)->pty_flag))
-    send_process (proc, "\004", 1);
+    send_process (proc, "\004", 1, Qnil);
   else
     {
-      close (XPROCESS (proc)->outfd);
-      XFASTINT (XPROCESS (proc)->outfd) = open ("/dev/null", O_WRONLY);
+      close (XINT (XPROCESS (proc)->outfd));
+      XSETINT (XPROCESS (proc)->outfd, open (NULL_DEVICE, O_WRONLY));
     }
 #endif /* VMS */
-#endif /* did not do TOICREMOTE */
   return process;
 }
 
@@ -2483,16 +3271,15 @@ kill_buffer_processes (buffer)
 {
   Lisp_Object tail, proc;
 
-  for (tail = Vprocess_alist; XGCTYPE (tail) == Lisp_Cons;
-       tail = XCONS (tail)->cdr)
+  for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
     {
       proc = XCONS (XCONS (tail)->car)->cdr;
-      if (XGCTYPE (proc) == Lisp_Process
+      if (GC_PROCESSP (proc)
          && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
        {
          if (NETCONN_P (proc))
-           deactivate_process (proc);
-         else if (XFASTINT (XPROCESS (proc)->infd))
+           Fdelete_process (proc);
+         else if (XINT (XPROCESS (proc)->infd) >= 0)
            process_send_signal (proc, SIGHUP, Qnil, 1);
        }
     }
@@ -2526,6 +3313,7 @@ sigchld_handler (signo)
   int old_errno = errno;
   Lisp_Object proc;
   register struct Lisp_Process *p;
+  extern EMACS_TIME *input_available_clear_time;
 
 #ifdef BSD4_1
   extern int sigheld;
@@ -2573,7 +3361,7 @@ sigchld_handler (signo)
       /* Find the process that signaled us, and record its status.  */
 
       p = 0;
-      for (tail = Vprocess_alist; XSYMBOL (tail) != XSYMBOL (Qnil); tail = XCONS (tail)->cdr)
+      for (tail = Vprocess_alist; CONSP (tail); tail = XCONS (tail)->cdr)
        {
          proc = XCONS (XCONS (tail)->car)->cdr;
          p = XPROCESS (proc);
@@ -2585,11 +3373,11 @@ sigchld_handler (signo)
       /* Look for an asynchronous process whose pid hasn't been filled
         in yet.  */
       if (p == 0)
-       for (tail = Vprocess_alist; XSYMBOL (tail) != XSYMBOL (Qnil); tail = XCONS (tail)->cdr)
+       for (tail = Vprocess_alist; CONSP (tail); tail = XCONS (tail)->cdr)
          {
            proc = XCONS (XCONS (tail)->car)->cdr;
            p = XPROCESS (proc);
-           if (XTYPE (p->pid) == Lisp_Int && XINT (p->pid) == -1)
+           if (INTEGERP (p->pid) && XINT (p->pid) == -1)
              break;
            p = 0;
          }
@@ -2598,16 +3386,29 @@ sigchld_handler (signo)
       if (p != 0)
        {
          union { int i; WAITTYPE wt; } u;
+         int clear_desc_flag = 0;
          
          XSETINT (p->tick, ++process_tick);
          u.wt = w;
-         XFASTINT (p->raw_status_low) = u.i & 0xffff;
-         XFASTINT (p->raw_status_high) = u.i >> 16;
+         XSETINT (p->raw_status_low, u.i & 0xffff);
+         XSETINT (p->raw_status_high, u.i >> 16);
          
          /* If process has terminated, stop waiting for its output.  */
-         if (WIFSIGNALED (w) || WIFEXITED (w))
-           if (p->infd)
-             FD_CLR (p->infd, &input_wait_mask);
+         if ((WIFSIGNALED (w) || WIFEXITED (w))
+             && XINT (p->infd) >= 0)
+           clear_desc_flag = 1;
+
+         /* We use clear_desc_flag to avoid a compiler bug in Microsoft C.  */
+         if (clear_desc_flag)
+           {
+             FD_CLR (XINT (p->infd), &input_wait_mask);
+             FD_CLR (XINT (p->infd), &non_keyboard_wait_mask);
+           }
+
+         /* Tell wait_reading_process_input that it needs to wake up and
+            look around.  */
+         if (input_available_clear_time)
+           EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
        }
 
        /* There was no asynchronous process found for that id.  Check
@@ -2620,7 +3421,29 @@ sigchld_handler (signo)
          if (WIFEXITED (w))
            synch_process_retcode = WRETCODE (w);
          else if (WIFSIGNALED (w))
-           synch_process_death = sys_siglist[WTERMSIG (w)];
+           {
+             int code = WTERMSIG (w);
+             char *signame = 0;
+
+             if (code < NSIG)
+               {
+#ifndef VMS
+                 /* Suppress warning if the table has const char *.  */
+                 signame = (char *) sys_siglist[code];
+#else
+                 signame = sys_errlist[code];
+#endif
+               }
+             if (signame == 0)
+               signame = "unknown";
+
+             synch_process_death = signame;
+           }
+
+         /* Tell wait_reading_process_input that it needs to wake up and
+            look around.  */
+         if (input_available_clear_time)
+           EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
        }
 
       /* On some systems, we must return right away.
@@ -2628,7 +3451,7 @@ sigchld_handler (signo)
         get another signal.
         Otherwise (on systems that have WNOHANG), loop around
         to use up all the processes that have something to tell us.  */
-#if defined (USG) && ! (defined (HPUX) && defined (WNOHANG))
+#if defined (USG) && ! (defined (HPUX) && defined (WNOHANG)) || defined (WINDOWSNT)
 #ifdef USG
       signal (signo, sigchld_handler);
 #endif
@@ -2647,14 +3470,30 @@ exec_sentinel_unwind (data)
   return Qnil;
 }
 
+static Lisp_Object
+exec_sentinel_error_handler (error)
+     Lisp_Object error;
+{
+  cmd_error_internal (error, "error in process sentinel: ");
+  Vinhibit_quit = Qt;
+  update_echo_area ();
+  Fsleep_for (make_number (2), Qnil);
+}
+
 static void
 exec_sentinel (proc, reason)
      Lisp_Object proc, reason;
 {
-  Lisp_Object sentinel;
+  Lisp_Object sentinel, obuffer, odeactivate, okeymap;
   register struct Lisp_Process *p = XPROCESS (proc);
   int count = specpdl_ptr - specpdl;
 
+  /* 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;
+  XSETBUFFER (obuffer, current_buffer);
+  okeymap = current_buffer->keymap;
+
   sentinel = p->sentinel;
   if (NILP (sentinel))
     return;
@@ -2665,8 +3504,29 @@ exec_sentinel (proc, reason)
   record_unwind_protect (exec_sentinel_unwind, Fcons (proc, sentinel));
   /* Inhibit quit so that random quits don't screw up a running filter.  */
   specbind (Qinhibit_quit, Qt);
-  call2 (sentinel, proc, reason);
-  unbind_to (count);
+  specbind (Qlast_nonmenu_event, Qt);
+
+  running_asynch_code = 1;
+  internal_condition_case_1 (read_process_output_call,
+                            Fcons (sentinel,
+                                   Fcons (proc, Fcons (reason, Qnil))),
+                            !NILP (Vdebug_on_error) ? Qnil : Qerror,
+                            exec_sentinel_error_handler);
+  running_asynch_code = 0;
+  restore_match_data ();
+
+  Vdeactivate_mark = odeactivate;
+#if 0
+  if (! EQ (Fcurrent_buffer (), obuffer)
+      || ! EQ (current_buffer->keymap, okeymap))
+#endif
+    /* But do it only if the caller is actually going to read events.
+       Otherwise there's no need to make him wake up, and it could
+       cause trouble (for example it would make Fsit_for return).  */
+    if (waiting_for_user_input_p == -1)
+      record_asynch_buffer_change ();
+
+  unbind_to (count, Qnil);
 }
 
 /* Report all recent events of a change in process status
@@ -2676,16 +3536,21 @@ exec_sentinel (proc, reason)
 status_notify ()
 {
   register Lisp_Object proc, buffer;
-  Lisp_Object tail = Qnil;
-  Lisp_Object msg = Qnil;
+  Lisp_Object tail, msg;
   struct gcpro gcpro1, gcpro2;
 
+  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.  */
+  update_tick = process_tick;
+
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
       Lisp_Object symbol;
@@ -2699,8 +3564,9 @@ status_notify ()
          XSETINT (p->update_tick, XINT (p->tick));
 
          /* If process is still active, read any output that remains.  */
-         if (XFASTINT (p->infd))
-           while (read_process_output (proc, XFASTINT (p->infd)) > 0);
+         if (XINT (p->infd) >= 0)
+           while (! EQ (p->filter, Qt)
+                  && read_process_output (proc, XINT (p->infd)) > 0);
 
          buffer = p->buffer;
 
@@ -2711,7 +3577,7 @@ status_notify ()
 
          /* If process is terminated, deactivate it or delete it.  */
          symbol = p->status;
-         if (XTYPE (p->status) == Lisp_Cons)
+         if (CONSP (p->status))
            symbol = XCONS (p->status)->car;
 
          if (EQ (symbol, Qsignal) || EQ (symbol, Qexit)
@@ -2730,11 +3596,12 @@ status_notify ()
             when a process becomes runnable.  */
          else if (!EQ (symbol, Qrun) && !NILP (buffer))
            {
-             Lisp_Object ro = XBUFFER (buffer)->read_only;
-             Lisp_Object tem;
+             Lisp_Object ro, tem;
              struct buffer *old = current_buffer;
              int opoint;
 
+             ro = XBUFFER (buffer)->read_only;
+
              /* Avoid error if buffer is deleted
                 (probably that's why the process is dead, too) */
              if (NILP (XBUFFER (buffer)->name))
@@ -2769,11 +3636,63 @@ status_notify ()
   update_mode_lines++;  /* in case buffers use %s in mode-line-format */
   redisplay_preserve_echo_area ();
 
-  update_tick = process_tick;
-
   UNGCPRO;
 }
 \f
+/* The first time this is called, assume keyboard input comes from DESC
+   instead of from where we used to expect it.
+   Subsequent calls mean assume input keyboard can come from DESC
+   in addition to other places.  */
+
+static int add_keyboard_wait_descriptor_called_flag;
+
+void
+add_keyboard_wait_descriptor (desc)
+     int desc;
+{
+  if (! add_keyboard_wait_descriptor_called_flag)
+    FD_CLR (0, &input_wait_mask);
+  add_keyboard_wait_descriptor_called_flag = 1;
+  FD_SET (desc, &input_wait_mask);
+  if (desc > max_keyboard_desc)
+    max_keyboard_desc = desc;
+}
+
+/* From now on, do not expect DESC to give keyboard input.  */
+
+void
+delete_keyboard_wait_descriptor (desc)
+     int desc;
+{
+  int fd;
+  int lim = max_keyboard_desc;
+
+  FD_CLR (desc, &input_wait_mask);
+
+  if (desc == max_keyboard_desc)
+    for (fd = 0; fd < lim; fd++)
+      if (FD_ISSET (fd, &input_wait_mask)
+         && !FD_ISSET (fd, &non_keyboard_wait_mask))
+       max_keyboard_desc = fd;
+}
+
+/* Return nonzero if *MASK has a bit set
+   that corresponds to one of the keyboard input descriptors.  */
+
+int
+keyboard_bit_set (mask)
+     SELECT_TYPE *mask;
+{
+  int fd;
+
+  for (fd = 0; fd <= max_keyboard_desc; fd++)
+    if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask)
+       && !FD_ISSET (fd, &non_keyboard_wait_mask))
+      return 1;
+
+  return 0;
+}
+\f
 init_process ()
 {
   register int i;
@@ -2786,7 +3705,11 @@ init_process ()
 #endif
 
   FD_ZERO (&input_wait_mask);
+  FD_ZERO (&non_keyboard_wait_mask);
+  max_process_desc = 0;
+
   FD_SET (0, &input_wait_mask);
+
   Vprocess_alist = Qnil;
   for (i = 0; i < MAXDESC; i++)
     {
@@ -2794,21 +3717,9 @@ init_process ()
       proc_buffered_char[i] = -1;
     }
 }
-#ifdef 0
-DEFUN ("process-connection", Fprocess_connection, Sprocess_connection, 0, 1, 0,
- "Return the connection type of `PROCESS'.  This can be nil (pipe),\n\
-t or pty (pty) or stream (socket connection).")
-  (process)
-     Lisp_Object process;
-{
-  return XPROCESS (process)->type;
-}
-#endif
+
 syms_of_process ()
 {
-#ifdef HAVE_PTYS
-  pty_process = intern ("pty");
-#endif
 #ifdef HAVE_SOCKETS
   stream_process = intern ("stream");
 #endif
@@ -2832,6 +3743,9 @@ syms_of_process ()
   Qclosed = intern ("closed");
   staticpro (&Qclosed);
 
+  Qlast_nonmenu_event = intern ("last-nonmenu-event");
+  staticpro (&Qlast_nonmenu_event);
+
   staticpro (&Vprocess_alist);
 
   DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
@@ -2842,9 +3756,10 @@ nil means don't delete them until `list-processes' is run.");
 
   DEFVAR_LISP ("process-connection-type", &Vprocess_connection_type,
     "Control type of device used to communicate with subprocesses.\n\
-Values are nil to use a pipe, and t or 'pty for a pty.  Note that if\n\
-pty's are not available, this variable will be ignored. The value takes\n\
-effect when `start-process' is called.");
+Values are nil to use a pipe, or t or `pty' to use a pty.\n\
+The value has no effect if the system has no ptys or if all ptys are busy:\n\
+then a pipe is used in any case.\n\
+The value takes effect when `start-process' is called.");
   Vprocess_connection_type = Qt;
 
   defsubr (&Sprocessp);
@@ -2855,6 +3770,7 @@ effect when `start-process' is called.");
   defsubr (&Sprocess_exit_status);
   defsubr (&Sprocess_id);
   defsubr (&Sprocess_name);
+  defsubr (&Sprocess_tty_name);
   defsubr (&Sprocess_command);
   defsubr (&Sset_process_buffer);
   defsubr (&Sprocess_buffer);
@@ -2862,6 +3778,7 @@ effect when `start-process' is called.");
   defsubr (&Sset_process_filter);
   defsubr (&Sprocess_filter);
   defsubr (&Sset_process_sentinel);
+  defsubr (&Sset_process_window_size);
   defsubr (&Sprocess_sentinel);
   defsubr (&Sprocess_kill_without_query);
   defsubr (&Slist_processes);
@@ -2893,9 +3810,12 @@ effect when `start-process' is called.");
 #include "lisp.h"
 #include "systime.h"
 #include "termopts.h"
+#include "sysselect.h"
 
-extern int screen_garbaged;
+extern int frame_garbaged;
 
+extern EMACS_TIME timer_check ();
+extern int timers_run;
 
 /* As described above, except assuming that there are no subprocesses:
 
@@ -2906,7 +3826,7 @@ extern int screen_garbaged;
      zero for no limit, or
      -1 means gobble data immediately available but don't wait for any.
 
-   read_kbd is:
+   read_kbd is a Lisp_Object:
      0 to ignore keyboard input, or
      1 to return when input is available, or
      -1 means caller will actually read the input, so don't throw to
@@ -2915,26 +3835,23 @@ extern int screen_garbaged;
      `subprocesses' isn't defined.
 
    do_display != 0 means redisplay should be done to show subprocess
-   output that arrives.  This version of the function ignores it.
+   output that arrives.
 
-   If read_kbd is a pointer to a struct Lisp_Process, then the
-     function returns true iff we received input from that process
-     before the timeout elapsed.
-   Otherwise, return true iff we recieved input from any process.  */
+   Return true iff we received input from any process.  */
 
 int
 wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
-     int time_limit, microsecs, read_kbd, do_display;
+     int time_limit, microsecs;
+     Lisp_Object read_kbd;
+     int do_display;
 {
-  EMACS_TIME end_time, timeout, *timeout_p;
-  int waitchannels;
+  EMACS_TIME end_time, timeout;
+  SELECT_TYPE waitchannels;
+  int xerrno;
 
   /* What does time_limit really mean?  */
   if (time_limit || microsecs)
     {
-      /* It's not infinite.  */
-      timeout_p = &timeout;
-
       if (time_limit == -1)
        /* In fact, it's zero.  */
        EMACS_SET_SECS_USECS (timeout, 0, 0);
@@ -2947,7 +3864,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
     }
   else
     /* It's infinite.  */
-    timeout_p = 0;
+    EMACS_SET_SECS_USECS (timeout, 100000, 0);
 
   /* Turn off periodic alarms (in case they are in use)
      because the select emulator uses alarms.  */
@@ -2956,37 +3873,69 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
   for (;;)
     {
       int nfds;
+      int timeout_reduced_for_timers = 0;
 
-      waitchannels = read_kbd ? 1 : 0;
+      if (XINT (read_kbd))
+       FD_SET (0, &waitchannels);
+      else
+       FD_ZERO (&waitchannels);
 
       /* If calling from keyboard input, do not quit
         since we want to return C-g as an input character.
         Otherwise, do pending quit if requested.  */
-      if (read_kbd >= 0)
+      if (XINT (read_kbd) >= 0)
        QUIT;
 
-      if (timeout_p)
+      /* Compute time from now till when time limit is up */
+      /* Exit if already run out */
+      if (time_limit > 0 || microsecs)
        {
-         EMACS_GET_TIME (*timeout_p);
-         EMACS_SUB_TIME (*timeout_p, end_time, *timeout_p);
-         if (EMACS_TIME_NEG_P (*timeout_p))
+         EMACS_GET_TIME (timeout);
+         EMACS_SUB_TIME (timeout, end_time, timeout);
+         if (EMACS_TIME_NEG_P (timeout))
            break;
        }
 
+      /* If our caller will not immediately handle keyboard events,
+        run timer events directly.
+        (Callers that will immediately read keyboard events
+        call timer_delay on their own.)  */
+      if (XINT (read_kbd) >= 0)
+       {
+         EMACS_TIME timer_delay;
+         int old_timers_run = timers_run;
+         timer_delay = timer_check (1);
+         if (timers_run != old_timers_run && do_display)
+           redisplay_preserve_echo_area ();
+         if (! EMACS_TIME_NEG_P (timer_delay) && time_limit != -1)
+           {
+             EMACS_TIME difference;
+             EMACS_SUB_TIME (difference, timer_delay, timeout);
+             if (EMACS_TIME_NEG_P (difference))
+               {
+                 timeout = timer_delay;
+                 timeout_reduced_for_timers = 1;
+               }
+           }
+       }
+
       /* Cause C-g and alarm signals to take immediate action,
         and cause input available signals to zero out timeout.  */
-      if (read_kbd < 0)
+      if (XINT (read_kbd) < 0)
        set_waiting_for_input (&timeout);
 
-      /* If a screen has been newly mapped and needs updating,
+      /* If a frame has been newly mapped and needs updating,
         reprocess its display stuff.  */
-      if (screen_garbaged)
+      if (frame_garbaged && do_display)
        redisplay_preserve_echo_area ();
 
-      if (read_kbd && detect_input_pending ())
+      if (XINT (read_kbd) && detect_input_pending ())
        nfds = 0;
       else
-       nfds = select (1, &waitchannels, 0, 0, timeout_p);
+       nfds = select (1, &waitchannels, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+                      &timeout);
+
+      xerrno = errno;
 
       /* Make C-g and alarm signals set flags again */
       clear_waiting_for_input ();
@@ -2994,35 +3943,57 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /*  If we woke up due to SIGWINCH, actually change size now.  */
       do_pending_window_change ();
 
+      if (time_limit && nfds == 0 && ! timeout_reduced_for_timers)
+       /* We waited the full specified time, so return now.  */
+       break;
+
       if (nfds == -1)
        {
          /* If the system call was interrupted, then go around the
             loop again.  */
-         if (errno == EINTR)
-           waitchannels = 0;
+         if (xerrno == EINTR)
+           FD_ZERO (&waitchannels);
+         else
+           error ("select error: %s", strerror (xerrno));
        }
 #ifdef sun
       else if (nfds > 0 && (waitchannels & 1)  && interrupt_input)
        /* System sometimes fails to deliver SIGIO.  */
        kill (getpid (), SIGIO);
 #endif
-      if (read_kbd && interrupt_input && (waitchannels & 1))
-       kill (0, SIGIO);
+#ifdef SIGIO
+      if (XINT (read_kbd) && interrupt_input && (waitchannels & 1))
+       kill (getpid (), SIGIO);
+#endif
 
-      /* If we have timed out (nfds == 0) or found some input (nfds > 0),
-        we should exit.  */
-      if (nfds >= 0)
-       break;
+      /* Check for keyboard input */
+
+      if (XINT (read_kbd) < 0 && detect_input_pending ())
+       {
+         swallow_events (do_display);
+         if (detect_input_pending ())
+           break;
+       }
+
+      if (XINT (read_kbd) > 0
+         && detect_input_pending_run_timers (do_display))
+       {
+         swallow_events (do_display);
+         if (detect_input_pending_run_timers (do_display))
+           break;
+       }
     }
 
+  start_polling ();
+
   return 0;
 }
 
 
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
-  "Return the (or, a) process associated with BUFFER.\n\
-This copy of Emacs has not been built to support subprocesses, so this\n\
-function always returns nil.")
+  /* Don't confuse make-docfile by having two doc strings for this function.
+     make-docfile does not pay attention to #if, for good reason!  */
+  0)
   (name)
      register Lisp_Object name;
 {