Comment fixes.
[bpt/emacs.git] / src / process.c
index dd830fd..7155fce 100644 (file)
@@ -1,5 +1,5 @@
 /* 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 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -52,6 +52,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,36 +199,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;
-
-#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.  */
-#ifdef FD_SETSIZE
-#define MAXDESC FD_SETSIZE
-#else
-#define MAXDESC 64
-#endif
-#define SELECT_TYPE fd_set
-#else /* no FD_SET */
-#define MAXDESC 32
-#define SELECT_TYPE int
+int update_tick;
 
-/* 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 */
+#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
 
@@ -266,12 +251,11 @@ static Lisp_Object get_process ();
 /* 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'.  */
@@ -381,6 +365,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 ()
 {
@@ -467,22 +456,18 @@ 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);
+  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);
@@ -505,6 +490,7 @@ make_process (name)
     }
   name = name1;
   p->name = name;
+  XSETPROCESS (val, p);
   Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
   return val;
 }
@@ -940,7 +926,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);
            }
        }
@@ -1056,9 +1042,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));
@@ -1110,10 +1096,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++)
     {
@@ -1138,13 +1130,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
@@ -1198,12 +1195,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;
@@ -1299,6 +1308,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);
@@ -1313,6 +1340,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);
@@ -1428,13 +1456,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
@@ -1451,6 +1484,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);
@@ -1464,9 +1504,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);
@@ -1510,8 +1548,25 @@ create_process (process, new_argv, current_dir)
   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;
 
+#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);
@@ -1529,6 +1584,7 @@ create_process (process, new_argv, current_dir)
 #endif /* ordinary USG */
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
+#endif /* !POSIX_SIGNALS */
 }
 #endif /* not VMS */
 
@@ -1587,6 +1643,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)
     {
@@ -1641,13 +1704,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)
@@ -1658,6 +1714,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;
        }
@@ -1949,11 +2009,6 @@ 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)
     {
       /* If calling from keyboard input, do not quit
@@ -2005,7 +2060,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.  */
@@ -2037,7 +2094,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 ())
        {
@@ -2045,7 +2107,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;
 
@@ -2265,7 +2328,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,
@@ -2345,30 +2408,43 @@ 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);
 
+      running_asynch_code = 1;
       internal_condition_case_1 (read_process_output_call,
                                 Fcons (outstream,
                                        Fcons (proc,
-                                              Fcons (make_string (chars, nchars),
+                                              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 (! 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);
@@ -2470,14 +2546,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);
@@ -2947,18 +3023,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
 }
 
@@ -3124,8 +3312,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))
@@ -3211,19 +3399,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;
@@ -3236,18 +3428,26 @@ exec_sentinel (proc, reason)
   specbind (Qinhibit_quit, Qt);
   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 (! 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);
 }
 
@@ -3269,6 +3469,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;
@@ -3354,8 +3558,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
@@ -3405,7 +3607,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;
@@ -3530,6 +3732,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;
 
@@ -3585,9 +3788,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 ();
@@ -3625,7 +3825,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 ();