(wait_reading_process_input): If select times out,
[bpt/emacs.git] / src / process.c
index acd2d0b..7af4115 100644 (file)
@@ -1,5 +1,6 @@
 /* Asynchronous subprocess control for GNU Emacs.
-   Copyright (C) 1985, 86, 87, 88, 93, 94 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.
 
@@ -15,7 +16,8 @@ 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>
@@ -52,6 +54,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #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.  */
@@ -196,17 +201,18 @@ static 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.  */
-static int process_tick;
-
+int process_tick;
 /* Number of events for which the user or sentinel has been notified.  */
-static int update_tick;
+int update_tick;
 
 #include "sysselect.h"
 
-/* If we support X Windows, turn on the code to poll periodically
+/* 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_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
 
@@ -244,15 +250,16 @@ int proc_buffered_char[MAXDESC];
 
 static Lisp_Object get_process ();
 
+extern EMACS_TIME timer_check ();
+
 /* Maximum number of bytes to send to a pty without an eof.  */
 static int pty_max_bytes;
 
-/* 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.  */
+#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'.  */
@@ -362,6 +369,11 @@ status_message (status)
 \f
 #ifdef HAVE_PTYS
 
+/* 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.  */
+
 int
 allocate_pty ()
 {
@@ -501,10 +513,10 @@ remove_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 PROCESSP (obj) ? Qt : Qnil;
+  return PROCESSP (object) ? Qt : Qnil;
 }
 
 DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
@@ -521,13 +533,13 @@ 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))
@@ -582,27 +594,27 @@ 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, a buffer, the name of a process or buffer, or\n\
 nil, indicating the current buffer's process.")
-  (proc)
-     register Lisp_Object proc;
+  (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 (XINT (XPROCESS (proc)->infd) >= 0)
+  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
@@ -617,27 +629,27 @@ closed -- for a network stream connection that is closed.\n\
 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.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
   register struct Lisp_Process *p;
   register Lisp_Object status;
 
-  if (STRINGP (proc))
-    proc = Fget_process (proc);
+  if (STRINGP (process))
+    process = Fget_process (process);
   else
-    proc = get_process (proc);
+    process = get_process (process);
 
-  if (NILP (proc))
-    return proc;
+  if (NILP (process))
+    return process;
 
-  p = XPROCESS (proc);
+  p = XPROCESS (process);
   if (!NILP (p->raw_status_low))
     update_status (p);
   status = p->status;
   if (CONSP (status))
     status = XCONS (status)->car;
-  if (NETCONN_P (proc))
+  if (NETCONN_P (process))
     {
       if (EQ (status, Qrun))
        status = Qopen;
@@ -651,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 (CONSP (XPROCESS (proc)->status))
-    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);
 }
 
@@ -666,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,
@@ -689,34 +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.")
-  (proc)
-     register Lisp_Object proc;
+  (process)
+     register Lisp_Object process;
 {
-  CHECK_PROCESS (proc, 0);
-  return XPROCESS (proc)->tty_name;
+  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;
 }
 
@@ -725,21 +737,21 @@ 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,
@@ -750,21 +762,21 @@ 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);
+  CHECK_PROCESS (process, 0);
   if (EQ (filter, Qt))
     {
-      FD_CLR (XINT (XPROCESS (proc)->infd), &input_wait_mask);
-      FD_CLR (XINT (XPROCESS (proc)->infd), &non_keyboard_wait_mask);
+      FD_CLR (XINT (XPROCESS (process)->infd), &input_wait_mask);
+      FD_CLR (XINT (XPROCESS (process)->infd), &non_keyboard_wait_mask);
     }
-  else if (EQ (XPROCESS (proc)->filter, Qt))
+  else if (EQ (XPROCESS (process)->filter, Qt))
     {
-      FD_SET (XINT (XPROCESS (proc)->infd), &input_wait_mask);
-      FD_SET (XINT (XPROCESS (proc)->infd), &non_keyboard_wait_mask);
+      FD_SET (XINT (XPROCESS (process)->infd), &input_wait_mask);
+      FD_SET (XINT (XPROCESS (process)->infd), &non_keyboard_wait_mask);
     }
-  XPROCESS (proc)->filter = filter;
+  XPROCESS (process)->filter = filter;
   return filter;
 }
 
@@ -772,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,
@@ -784,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;
 }
 
@@ -796,23 +808,23 @@ 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.")
-  (proc, height, width)
-     register Lisp_Object proc, height, width;
+  (process, height, width)
+     register Lisp_Object process, height, width;
 {
-  CHECK_PROCESS (proc, 0);
+  CHECK_PROCESS (process, 0);
   CHECK_NATNUM (height, 0);
   CHECK_NATNUM (width, 0);
-  if (set_window_size (XINT (XPROCESS (proc)->infd),
+  if (set_window_size (XINT (XPROCESS (process)->infd),
                       XINT (height), XINT(width)) <= 0)
     return Qnil;
   else
@@ -824,14 +836,14 @@ DEFUN ("process-kill-without-query", Fprocess_kill_without_query,
   "Say no query needed if PROCESS is running when Emacs is exited.\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);
 }
@@ -918,7 +930,7 @@ Proc         Status   Buffer         Tty         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);
            }
        }
@@ -1034,9 +1046,9 @@ Remaining arguments are strings to give program as arguments.")
 
     GCPRO2 (buffer, current_dir);
 
-    current_dir 
-      expand_and_dir_to_file
-       (Funhandled_file_name_directory (current_dir), Qnil);
+    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));
@@ -1088,10 +1100,16 @@ Remaining arguments are strings to give program as arguments.")
       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
-    new_argv[0] = XSTRING (program)->data;
+    {
+      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++)
     {
@@ -1116,13 +1134,18 @@ Remaining arguments are strings to give program as arguments.")
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
+  /* 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);
+
   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 signalled
+   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
@@ -1176,12 +1199,24 @@ create_process (process, new_argv, current_dir)
      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;
+#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;
 
   inchannel = outchannel = -1;
@@ -1256,9 +1291,11 @@ create_process (process, new_argv, current_dir)
 
 #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
 
@@ -1277,6 +1314,24 @@ create_process (process, new_argv, current_dir)
 
   /* 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);
@@ -1291,6 +1346,7 @@ create_process (process, new_argv, current_dir)
 #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);
@@ -1406,13 +1462,18 @@ create_process (process, new_argv, current_dir)
              close (xforkin);
            xforkout = xforkin = open (pty_name, O_RDWR, 0);
 
+           if (xforkin < 0)
+             {
+               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
-
-           if (xforkin < 0)
-             abort ();
          }
 #endif /* not UNIPLUS and not RTU */
 #ifdef SETUP_SLAVE_PTY
@@ -1429,6 +1490,13 @@ create_process (process, new_argv, current_dir)
 #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);
@@ -1442,9 +1510,7 @@ create_process (process, new_argv, current_dir)
 #endif /* ordinary USG */
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
-
-       signal (SIGINT, SIG_DFL);
-       signal (SIGQUIT, SIG_DFL);
+#endif /* !POSIX_SIGNALS */
 
        if (pty_flag)
          child_setup_tty (xforkout);
@@ -1459,37 +1525,59 @@ create_process (process, new_argv, current_dir)
     environ = save_environ;
   }
 
+  /* This runs in the Emacs process.  */
   if (pid < 0)
     {
       if (forkin >= 0)
        close (forkin);
       if (forkin != forkout && forkout >= 0)
        close (forkout);
-      report_file_error ("Doing vfork", Qnil);
     }
-  
-  XSETFASTINT (XPROCESS (process)->pid, pid);
+  else
+    {
+      /* vfork succeeded.  */
+      XSETFASTINT (XPROCESS (process)->pid, pid);
 
 #ifdef WINDOWSNT
-  register_child (pid, inchannel);
+      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);
+      /* 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);
 
-  XPROCESS (process)->tty_name = build_string (pty_name);
+#ifdef HAVE_PTYS
+      if (pty_flag)
+       XPROCESS (process)->tty_name = build_string (pty_name);
+      else
+#endif
+       XPROCESS (process)->tty_name = Qnil;
+    }
 
+  /* 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);
@@ -1507,6 +1595,11 @@ create_process (process, new_argv, current_dir)
 #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 */
 
@@ -1565,6 +1658,13 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
       port = svc_info->s_port;
     }
 
+  /* 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)
     {
@@ -1619,13 +1719,6 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   if (interrupt_input)
     unrequest_sigio ();
 
-  /* Slow down polling to every ten seconds.
-     Some kernels have a bug which causes retrying connect to fail
-     after a connect.  */
-#ifdef POLL_FOR_INPUT
-  bind_polling_period (10);
-#endif
-
  loop:
   if (connect (s, (struct sockaddr *) &address, sizeof address) == -1
       && errno != EISCONN)
@@ -1636,6 +1729,10 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
        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;
        }
@@ -1784,8 +1881,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;
@@ -1825,17 +1922,17 @@ Return non-nil iff we received any output before the timeout expired.")
     }
   else
     {
-      if (NILP (proc))
+      if (NILP (process))
        seconds = -1;
       else
        seconds = 0;
     }
 
-  if (NILP (proc))
-    XSETFASTINT (proc, 0);
+  if (NILP (process))
+    XSETFASTINT (process, 0);
 
   return
-    (wait_reading_process_input (seconds, useconds, proc, 0)
+    (wait_reading_process_input (seconds, useconds, process, 0)
      ? Qt : Qnil);
 }
 
@@ -1927,13 +2024,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       EMACS_ADD_TIME (end_time, end_time, timeout);
     }
 
-  /* It would not be safe to call this below,
-     where we call redisplay_preserve_echo_area.  */
-  if (do_display && frame_garbaged)
-    prepare_menu_bars ();
-
   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.  */
@@ -1966,6 +2060,26 @@ 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 (read_kbd >= 0)
+       {
+         EMACS_TIME timer_delay;
+         timer_delay = timer_check (1);
+         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.
 
@@ -1983,7 +2097,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
        {
          Atemp = input_wait_mask;
          EMACS_SET_SECS_USECS (timeout, 0, 0);
-         if (select (MAXDESC, &Atemp, 0, 0, &timeout) <= 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.  */
@@ -2015,7 +2131,12 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
         and indicates that a frame is trashed, the select may block
         displaying a trashed screen.  */
       if (frame_garbaged && do_display)
-       redisplay_preserve_echo_area ();
+       {
+         clear_waiting_for_input ();
+         redisplay_preserve_echo_area ();
+         if (XINT (read_kbd) < 0)
+           set_waiting_for_input (&timeout);
+       }
 
       if (XINT (read_kbd) && detect_input_pending ())
        {
@@ -2023,7 +2144,8 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
          FD_ZERO (&Available);
        }
       else
-       nfds = select (MAXDESC, &Available, 0, 0, &timeout);
+       nfds = select (MAXDESC, &Available, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+                      &timeout);
 
       xerrno = errno;
 
@@ -2033,7 +2155,8 @@ 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)
        {
@@ -2243,7 +2366,7 @@ read_process_output_error_handler (error)
   cmd_error_internal (error, "error in process filter: ");
   Vinhibit_quit = Qt;
   update_echo_area ();
-  Fsleep_for (make_number (2));
+  Fsleep_for (make_number (2), Qnil);
 }
 
 /* Read pending output from the process channel,
@@ -2323,10 +2446,13 @@ read_process_output (proc, channel)
         it up.  */
       int count = specpdl_ptr - specpdl;
       Lisp_Object odeactivate;
-      Lisp_Object obuffer;
+      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;
-      obuffer = Fcurrent_buffer ();
+      XSETBUFFER (obuffer, current_buffer);
+      okeymap = current_buffer->keymap;
 
       specbind (Qinhibit_quit, Qt);
       specbind (Qlast_nonmenu_event, Qt);
@@ -2346,11 +2472,17 @@ read_process_output (proc, channel)
       /* Handling the process output should not deactivate the mark.  */
       Vdeactivate_mark = odeactivate;
 
-      if (! EQ (Fcurrent_buffer (), obuffer))
-       record_asynch_buffer_change ();
-
-      if (waiting_for_user_input_p)
-       prepare_menu_bars ();
+#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);
@@ -2452,14 +2584,14 @@ send_process_trap ()
    OBJECT is the Lisp object that the data comes from.  */
 
 send_process (proc, buf, len, object)
-     Lisp_Object proc;
+     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);
@@ -2929,18 +3061,130 @@ 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);
+
+#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 (sig)));
+  return make_number (win32_kill_process (XINT (pid), XINT (sigcode)));
 #else
-  return make_number (kill (XINT (pid), XINT (sig)));
+  return make_number (kill (XINT (pid), XINT (sigcode)));
 #endif
 }
 
@@ -3106,8 +3350,8 @@ sigchld_handler (signo)
          
          XSETINT (p->tick, ++process_tick);
          u.wt = w;
-         XSETFASTINT (p->raw_status_low, u.i & 0xffff);
-         XSETFASTINT (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))
@@ -3193,19 +3437,23 @@ exec_sentinel_error_handler (error)
   cmd_error_internal (error, "error in process sentinel: ");
   Vinhibit_quit = Qt;
   update_echo_area ();
-  Fsleep_for (make_number (2));
+  Fsleep_for (make_number (2), Qnil);
 }
 
 static void
 exec_sentinel (proc, reason)
      Lisp_Object proc, reason;
 {
-  Lisp_Object sentinel, obuffer, odeactivate;
+  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;
-  obuffer = Fcurrent_buffer ();
+  XSETBUFFER (obuffer, current_buffer);
+  okeymap = current_buffer->keymap;
+
   sentinel = p->sentinel;
   if (NILP (sentinel))
     return;
@@ -3228,11 +3476,16 @@ exec_sentinel (proc, reason)
   restore_match_data ();
 
   Vdeactivate_mark = odeactivate;
-  if (! EQ (Fcurrent_buffer (), obuffer))
-    record_asynch_buffer_change ();
+#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 ();
 
-  if (waiting_for_user_input_p)
-    prepare_menu_bars ();
   unbind_to (count, Qnil);
 }
 
@@ -3254,6 +3507,10 @@ status_notify ()
      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;
@@ -3339,8 +3596,6 @@ status_notify ()
   update_mode_lines++;  /* in case buffers use %s in mode-line-format */
   redisplay_preserve_echo_area ();
 
-  update_tick = process_tick;
-
   UNGCPRO;
 }
 \f
@@ -3390,7 +3645,7 @@ keyboard_bit_set (mask)
 {
   int fd;
 
-  for (fd = 0; fd < max_keyboard_desc; 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;
@@ -3515,6 +3770,7 @@ The value takes effect when `start-process' is called.");
 #include "lisp.h"
 #include "systime.h"
 #include "termopts.h"
+#include "sysselect.h"
 
 extern int frame_garbaged;
 
@@ -3548,7 +3804,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
      int do_display;
 {
   EMACS_TIME end_time, timeout, *timeout_p;
-  int waitchannels;
+  SELECT_TYPE waitchannels;
 
   /* What does time_limit really mean?  */
   if (time_limit || microsecs)
@@ -3570,9 +3826,6 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
     /* It's infinite.  */
     timeout_p = 0;
 
-  /* This must come before stop_polling.  */
-  prepare_menu_bars ();
-
   /* Turn off periodic alarms (in case they are in use)
      because the select emulator uses alarms.  */
   stop_polling ();
@@ -3581,7 +3834,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
     {
       int nfds;
 
-      waitchannels = XINT (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.
@@ -3610,7 +3866,8 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       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_p);
 
       /* Make C-g and alarm signals set flags again */
       clear_waiting_for_input ();
@@ -3623,7 +3880,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
          /* If the system call was interrupted, then go around the
             loop again.  */
          if (errno == EINTR)
-           waitchannels = 0;
+           FD_ZERO (&waitchannels);
        }
 #ifdef sun
       else if (nfds > 0 && (waitchannels & 1)  && interrupt_input)