(status_notify): Test p->infd > 0
[bpt/emacs.git] / src / process.c
index f9501f9..e902cc7 100644 (file)
@@ -73,12 +73,12 @@ Boston, MA 02111-1307, USA.  */
 #define NUMERIC_ADDR_ERROR (numeric_addr == -1)
 #endif
 
-#if defined(BSD) || defined(STRIDE)
+#if defined(BSD_SYSTEM) || defined(STRIDE)
 #include <sys/ioctl.h>
 #if !defined (O_NDELAY) && defined (HAVE_PTYS) && !defined(USG5)
 #include <fcntl.h>
 #endif /* HAVE_PTYS and no O_NDELAY */
-#endif /* BSD or STRIDE */
+#endif /* BSD_SYSTEM || STRIDE */
 
 #ifdef BROKEN_O_NONBLOCK
 #undef O_NONBLOCK
@@ -110,13 +110,10 @@ 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
-   Qt nor Qnil but is instead a string (name of foreign host we
-   are connected to + name of port we are connected to) */
+   Qt nor Qnil but is instead a cons cell (HOSTNAME PORTNUM).  */
 
 #ifdef HAVE_SOCKETS
-static Lisp_Object stream_process;
-
-#define NETCONN_P(p) (GC_STRINGP (XPROCESS (p)->childp))
+#define NETCONN_P(p) (GC_CONSP (XPROCESS (p)->childp))
 #else
 #define NETCONN_P(p) 0
 #endif /* HAVE_SOCKETS */
@@ -251,6 +248,7 @@ 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;
@@ -847,6 +845,17 @@ Value is t if a query was formerly required.")
   return Fnull (tem);
 }
 
+DEFUN ("process-contact", Fprocess_contact, Sprocess_contact,
+  1, 1, 0,
+  "Return the contact info of PROCESS; t for a real child.\n\
+For a net connection, the value is a cons cell of the form (HOST SERVICE).")
+  (process)
+     register Lisp_Object process;
+{
+  CHECK_PROCESS (process, 0);
+  return XPROCESS (process)->childp;
+}
+
 #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,
@@ -957,7 +966,7 @@ Proc         Status   Buffer         Tty         Command\n\
       if (NETCONN_P (proc))
         {
          sprintf (tembuf, "(network stream connection to %s)\n",
-                  XSTRING (p->childp)->data);
+                  XSTRING (XCONS (p->childp)->car)->data);
          insert_string (tembuf);
         }
       else 
@@ -1166,7 +1175,7 @@ SIGTYPE
 create_process_1 (signo)
      int signo;
 {
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
   /* USG systems forget handlers when they are used;
      must reestablish each time */
   signal (signo, create_process_1);
@@ -1254,22 +1263,12 @@ create_process (process, new_argv, current_dir)
     }
 #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 */
 
@@ -1335,7 +1334,7 @@ create_process (process, new_argv, current_dir)
 #ifdef BSD4_1
   sighold (SIGCHLD);
 #else /* not BSD4_1 */
-#if defined (BSD) || defined (UNIPLUS) || defined (HPUX)
+#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
   sigsetmask (sigmask (SIGCHLD));
 #else /* ordinary USG */
 #if 0
@@ -1436,7 +1435,7 @@ create_process (process, new_argv, current_dir)
            /* 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
+#ifdef HAVE_SETPGID
            setpgid (0, 0);
 #else
            setpgrp (0, 0);
@@ -1445,9 +1444,13 @@ create_process (process, new_argv, current_dir)
          }
 #endif /* TIOCNOTTY */
 
-#if !defined (RTU) && !defined (UNIPLUS)
+#if !defined (RTU) && !defined (UNIPLUS) && !defined (DONT_REOPEN_PTY)
 /*** There is a suggestion that this ought to be a
-     conditional on TIOCSPGRP.  */
+     conditional on TIOCSPGRP,
+     or !(defined (HAVE_SETSID) && defined (TIOCSCTTY)).
+     Trying the latter gave the wrong results on Debian GNU/Linux 1.1;
+     that system does seem to need this code, even though
+     both HAVE_SETSID and TIOCSCTTY are defined.  */
        /* Now close the pty (if we had it open) and reopen it.
           This makes the pty the controlling terminal of the subprocess.  */
        if (pty_flag)
@@ -1474,7 +1477,8 @@ create_process (process, new_argv, current_dir)
            ioctl (xforkout, TIOCSPGRP, &pgrp);
 #endif
          }
-#endif /* not UNIPLUS and not RTU */
+#endif /* not UNIPLUS and not RTU and not DONT_REOPEN_PTY */
+
 #ifdef SETUP_SLAVE_PTY
        if (pty_flag)
          {
@@ -1500,7 +1504,7 @@ create_process (process, new_argv, current_dir)
 #ifdef BSD4_1
        sigrelse (SIGCHLD);
 #else /* not BSD4_1 */
-#if defined (BSD) || defined (UNIPLUS) || defined (HPUX)
+#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
        sigsetmask (SIGEMPTYMASK);
 #else /* ordinary USG */
 #if 0
@@ -1581,7 +1585,7 @@ create_process (process, new_argv, current_dir)
 #ifdef BSD4_1
   sigrelse (SIGCHLD);
 #else /* not BSD4_1 */
-#if defined (BSD) || defined (UNIPLUS) || defined (HPUX)
+#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
   sigsetmask (SIGEMPTYMASK);
 #else /* ordinary USG */
 #if 0
@@ -1643,6 +1647,11 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   int retry = 0;
   int count = specpdl_ptr - specpdl;
 
+#ifdef WINDOWSNT
+  /* Ensure socket support is loaded if available. */
+  init_winsock (TRUE);
+#endif
+
   GCPRO4 (name, buffer, host, service);
   CHECK_STRING (name, 0);
   CHECK_STRING (host, 0);
@@ -1670,7 +1679,10 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
 #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
@@ -1789,14 +1801,14 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
 #endif
 #endif
 
-  XPROCESS (proc)->childp = host;
+  XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil));
   XPROCESS (proc)->command_channel_p = Qnil;
   XPROCESS (proc)->buffer = buffer;
   XPROCESS (proc)->sentinel = Qnil;
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Qnil;
   XPROCESS (proc)->pid = Qnil;
-  XSETINT (XPROCESS (proc)->infd, s);
+  XSETINT (XPROCESS (proc)->infd, inch);
   XSETINT (XPROCESS (proc)->outfd, outch);
   XPROCESS (proc)->status = Qrun;
   FD_SET (inch, &input_wait_mask);
@@ -1955,6 +1967,12 @@ Return non-nil iff we received any output before the timeout expired.")
    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.
 
@@ -2031,6 +2049,14 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       EMACS_SET_SECS_USECS (timeout, time_limit, microsecs);
       EMACS_ADD_TIME (end_time, end_time, timeout);
     }
+#ifdef hpux
+  /* AlainF 5-Jul-1996
+     HP-UX 10.10 seem to have problems with signals coming in
+     Causes "poll: interrupted system call" messages when Emacs is run
+     in an X window
+     Turn off periodic alarms (in case they are in use) */
+  stop_polling ();
+#endif
 
   while (1)
     {
@@ -2068,14 +2094,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)
+      /* Normally we run timers here.
+        But not if wait_for_cell; in those cases,
+        the wait is supposed to be short,
+        and those callers cannot handle running arbitrary Lisp code here.  */
+      if (! wait_for_cell)
        {
          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;
@@ -2086,6 +2124,12 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                  timeout_reduced_for_timers = 1;
                }
            }
+         /* If time_limit is -1, we are not going to wait at all.  */
+         else if (time_limit != -1)
+           {
+             /* This is so a breakpoint can be put here.  */
+             wait_reading_process_input_1 ();
+           }
        }
 
       /* Cause C-g and alarm signals to take immediate action,
@@ -2220,18 +2264,25 @@ 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 (XINT (read_kbd) < 0 && detect_input_pending ())
+      if ((XINT (read_kbd) != 0)
+         && detect_input_pending_run_timers (do_display))
        {
          swallow_events (do_display);
-         if (detect_input_pending ())
+         if (detect_input_pending_run_timers (do_display))
            break;
        }
 
-      if ((XINT (read_kbd) > 0 || wait_for_cell)
-         && detect_input_pending_run_timers ())
+      /* If wait_for_cell. check for keyboard input
+        but don't run any timers.
+        ??? (It seems wrong to me to check for keyboard
+        input at all when wait_for_cell, but the code
+        has been this way since July 1994.
+        Try changing this after version 19.31.)  */
+      if (wait_for_cell
+         && detect_input_pending ())
        {
          swallow_events (do_display);
-         if (detect_input_pending_run_timers ())
+         if (detect_input_pending ())
            break;
        }
 
@@ -2247,7 +2298,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
       if (XINT (read_kbd) && interrupt_input
          && (keyboard_bit_set (&Available)))
-       kill (0, SIGIO);
+       kill (getpid (), SIGIO);
 #endif
 
       if (! wait_proc)
@@ -2299,7 +2350,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 #ifdef EWOULDBLOCK
              else if (nread == -1 && errno == EWOULDBLOCK)
                ;
-#else
+#endif
+             /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK,
+                and Emacs uses O_NONBLOCK, so what we get is EAGAIN.  */
 #ifdef O_NONBLOCK
              else if (nread == -1 && errno == EAGAIN)
                ;
@@ -2315,7 +2368,6 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                ;
 #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
@@ -2359,7 +2411,15 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       clear_input_pending ();
       QUIT;
     }
-
+#ifdef hpux
+  /* AlainF 5-Jul-1996
+     HP-UX 10.10 seems to have problems with signals coming in
+     Causes "poll: interrupted system call" messages when Emacs is run
+     in an X window
+     Turn periodic alarms back on */
+  start_polling();
+#endif
+   
   return got_some_input;
 }
 \f
@@ -2428,20 +2488,12 @@ 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
+    nchars = read (channel, chars, sizeof (chars));
   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
+      nchars = read (channel, chars + 1, sizeof (chars) - 1);
       if (nchars < 0)
        nchars = 1;
       else
@@ -2460,6 +2512,7 @@ read_process_output (proc, channel)
       int count = specpdl_ptr - specpdl;
       Lisp_Object odeactivate;
       Lisp_Object obuffer, okeymap;
+      int outer_running_asynch_code = running_asynch_code;
 
       /* 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.  */
@@ -2470,7 +2523,24 @@ read_process_output (proc, channel)
       specbind (Qinhibit_quit, Qt);
       specbind (Qlast_nonmenu_event, Qt);
 
+      /* In case we get recursively called,
+        and we already saved the match data nonrecursively,
+        save the same match data in safely recursive fashion.  */
+      if (outer_running_asynch_code)
+       {
+         Lisp_Object tem;
+         /* Don't clobber the CURRENT match data, either!  */
+         tem = Fmatch_data ();
+         restore_match_data ();
+         record_unwind_protect (Fstore_match_data, Fmatch_data ());
+         Fstore_match_data (tem);
+       }
+
+      /* For speed, if a search happens within this code,
+        save the match data in a special nonrecursive fashion.  */
       running_asynch_code = 1;
+
+      /* Read and dispose of the process output.  */
       internal_condition_case_1 (read_process_output_call,
                                 Fcons (outstream,
                                        Fcons (proc,
@@ -2479,8 +2549,10 @@ read_process_output (proc, channel)
                                                      Qnil))),
                                 !NILP (Vdebug_on_error) ? Qnil : Qerror,
                                 read_process_output_error_handler);
-      running_asynch_code = 0;
+
+      /* If we saved the match data nonrecursively, restore it now.  */
       restore_match_data ();
+      running_asynch_code = outer_running_asynch_code;
 
       /* Handling the process output should not deactivate the mark.  */
       Vdeactivate_mark = odeactivate;
@@ -2514,7 +2586,7 @@ read_process_output (proc, channel)
       odeactivate = Vdeactivate_mark;
 
       Fset_buffer (p->buffer);
-      opoint = point;
+      opoint = PT;
       old_read_only = current_buffer->read_only;
       XSETFASTINT (old_begv, BEGV);
       XSETFASTINT (old_zv, ZV);
@@ -2531,24 +2603,24 @@ read_process_output (proc, channel)
 
       /* If the output marker is outside of the visible region, save
         the restriction and widen.  */
-      if (! (BEGV <= point && point <= ZV))
+      if (! (BEGV <= PT && PT <= ZV))
        Fwiden ();
 
       /* Make sure opoint floats ahead of any new text, just as point
         would.  */
-      if (point <= opoint)
+      if (PT <= opoint)
        opoint += nchars;
 
       /* Insert after old_begv, but before old_zv.  */
-      if (point < XFASTINT (old_begv))
+      if (PT < XFASTINT (old_begv))
        XSETFASTINT (old_begv, XFASTINT (old_begv) + nchars);
-      if (point <= XFASTINT (old_zv))
+      if (PT <= 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);
-      Fset_marker (p->mark, make_number (point), p->buffer);
+      Fset_marker (p->mark, make_number (PT), p->buffer);
 
       update_mode_lines++;
 
@@ -2605,6 +2677,9 @@ send_process (proc, buf, len, object)
   /* Use volatile to protect variables from being clobbered by longjmp.  */
   int rv;
   volatile unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data;
+  struct gcpro gcpro1;
+
+  GCPRO1 (object);
 
 #ifdef VMS
   struct Lisp_Process *p = XPROCESS (proc);
@@ -2743,6 +2818,8 @@ send_process (proc, buf, len, object)
       error ("SIGPIPE raised on process %s; closed it", procname);
 #endif
     }
+
+  UNGCPRO;
 }
 
 DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region,
@@ -3193,12 +3270,7 @@ SIGCODE may be an integer, or a symbol whose name is a signal 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,
@@ -3317,7 +3389,7 @@ sigchld_handler (signo)
 
          /* USG systems forget handlers when they are used;
             must reestablish each time */
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
          signal (signo, sigchld_handler);   /* WARNING - must come after wait3() */
 #endif
 #ifdef  BSD4_1
@@ -3425,7 +3497,7 @@ sigchld_handler (signo)
         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)) || defined (WINDOWSNT)
-#ifdef USG
+#if defined (USG) && ! defined (POSIX_SIGNALS)
       signal (signo, sigchld_handler);
 #endif
       errno = old_errno;
@@ -3460,6 +3532,7 @@ exec_sentinel (proc, reason)
   Lisp_Object sentinel, obuffer, odeactivate, okeymap;
   register struct Lisp_Process *p = XPROCESS (proc);
   int count = specpdl_ptr - specpdl;
+  int outer_running_asynch_code = running_asynch_code;
 
   /* 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.  */
@@ -3479,14 +3552,31 @@ exec_sentinel (proc, reason)
   specbind (Qinhibit_quit, Qt);
   specbind (Qlast_nonmenu_event, Qt);
 
+  /* In case we get recursively called,
+     and we already saved the match data nonrecursively,
+     save the same match data in safely recursive fashion.  */
+  if (outer_running_asynch_code)
+    {
+      Lisp_Object tem;
+      tem = Fmatch_data ();
+      restore_match_data ();
+      record_unwind_protect (Fstore_match_data, Fmatch_data ());
+      Fstore_match_data (tem);
+    }
+
+  /* For speed, if a search happens within this code,
+     save the match data in a special nonrecursive fashion.  */
   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;
+
+  /* If we saved the match data nonrecursively, restore it now.  */
   restore_match_data ();
+  running_asynch_code = outer_running_asynch_code;
 
   Vdeactivate_mark = odeactivate;
 #if 0
@@ -3537,9 +3627,9 @@ status_notify ()
          XSETINT (p->update_tick, XINT (p->tick));
 
          /* If process is still active, read any output that remains.  */
-         if (XINT (p->infd) >= 0)
-           while (! EQ (p->filter, Qt)
-                  && read_process_output (proc, XINT (p->infd)) > 0);
+         while (! EQ (p->filter, Qt)
+                && XINT (p->infd) >= 0
+                && read_process_output (proc, XINT (p->infd)) > 0);
 
          buffer = p->buffer;
 
@@ -3562,6 +3652,11 @@ status_notify ()
                deactivate_process (proc);
            }
 
+         /* The actions above may have further incremented p->tick.
+            So set p->update_tick again
+            so that an error in the sentinel will not cause
+            this code to be run again.  */
+         XSETINT (p->update_tick, XINT (p->tick));
          /* Now output the message suitably.  */
          if (!NILP (p->sentinel))
            exec_sentinel (proc, msg);
@@ -3580,7 +3675,7 @@ status_notify ()
              if (NILP (XBUFFER (buffer)->name))
                continue;
              Fset_buffer (buffer);
-             opoint = point;
+             opoint = PT;
              /* Insert new output into buffer
                 at the current end-of-output marker,
                 thus preserving logical ordering of input and output.  */
@@ -3588,7 +3683,7 @@ status_notify ()
                SET_PT (marker_position (p->mark));
              else
                SET_PT (ZV);
-             if (point <= opoint)
+             if (PT <= opoint)
                opoint += XSTRING (msg)->size + XSTRING (p->name)->size + 10;
 
              tem = current_buffer->read_only;
@@ -3598,7 +3693,7 @@ status_notify ()
              insert_string (" ");
              Finsert (1, &msg);
              current_buffer->read_only = tem;
-             Fset_marker (p->mark, make_number (point), p->buffer);
+             Fset_marker (p->mark, make_number (PT), p->buffer);
 
              SET_PT (opoint);
              set_buffer_internal (old);
@@ -3693,9 +3788,6 @@ init_process ()
 
 syms_of_process ()
 {
-#ifdef HAVE_SOCKETS
-  stream_process = intern ("stream");
-#endif
   Qprocessp = intern ("processp");
   staticpro (&Qprocessp);
   Qrun = intern ("run");
@@ -3751,9 +3843,10 @@ The value takes 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 (&Sset_process_window_size);
   defsubr (&Sprocess_kill_without_query);
+  defsubr (&Sprocess_contact);
   defsubr (&Slist_processes);
   defsubr (&Sprocess_list);
   defsubr (&Sstart_process);
@@ -3787,6 +3880,8 @@ The value takes effect when `start-process' is called.");
 
 extern int frame_garbaged;
 
+extern EMACS_TIME timer_check ();
+extern int timers_run;
 
 /* As described above, except assuming that there are no subprocesses:
 
@@ -3802,6 +3897,8 @@ extern int frame_garbaged;
      1 to return when input is available, or
      -1 means caller will actually read the input, so don't throw to
        the quit handler.
+     a cons cell, meaning wait until its car is non-nil
+       (and gobble terminal input into the buffer if any arrives), or
      We know that read_kbd will never be a Lisp_Process, since
      `subprocesses' isn't defined.
 
@@ -3816,15 +3913,21 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
      Lisp_Object read_kbd;
      int do_display;
 {
-  EMACS_TIME end_time, timeout, *timeout_p;
+  EMACS_TIME end_time, timeout;
   SELECT_TYPE waitchannels;
+  int xerrno;
+  Lisp_Object *wait_for_cell = 0;
+
+  /* If waiting for non-nil in a cell, record where.  */
+  if (CONSP (read_kbd))
+    {
+      wait_for_cell = &XCONS (read_kbd)->car;
+      XSETFASTINT (read_kbd, 0);
+    }
 
   /* 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);
@@ -3837,7 +3940,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.  */
@@ -3846,11 +3949,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
   for (;;)
     {
       int nfds;
-
-      if (XINT (read_kbd))
-       FD_SET (0, &waitchannels);
-      else
-       FD_ZERO (&waitchannels);
+      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.
@@ -3858,29 +3957,84 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       if (XINT (read_kbd) >= 0)
        QUIT;
 
-      if (timeout_p)
+      /* 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 */
+      /* 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 (! wait_for_cell)
+       {
+         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;
+               }
+           }
+       }
+
       /* Cause C-g and alarm signals to take immediate action,
         and cause input available signals to zero out timeout.  */
       if (XINT (read_kbd) < 0)
        set_waiting_for_input (&timeout);
 
+      /* Wait till there is something to do.  */
+
+      if (! XINT (read_kbd) && wait_for_cell == 0)
+       FD_ZERO (&waitchannels);
+      else
+       FD_SET (0, &waitchannels);
+
       /* If a frame has been newly mapped and needs updating,
         reprocess its display stuff.  */
       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 ())
-       nfds = 0;
+       {
+         nfds = 0;
+         FD_ZERO (&waitchannels);
+       }
       else
        nfds = select (1, &waitchannels, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
-                      timeout_p);
+                      &timeout);
+
+      xerrno = errno;
 
       /* Make C-g and alarm signals set flags again */
       clear_waiting_for_input ();
@@ -3888,12 +4042,18 @@ 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)
+         if (xerrno == EINTR)
            FD_ZERO (&waitchannels);
+         else
+           error ("select error: %s", strerror (xerrno));
        }
 #ifdef sun
       else if (nfds > 0 && (waitchannels & 1)  && interrupt_input)
@@ -3902,12 +4062,35 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 #endif
 #ifdef SIGIO
       if (XINT (read_kbd) && interrupt_input && (waitchannels & 1))
-       kill (0, SIGIO);
+       kill (getpid (), SIGIO);
 #endif
 
-      /* If we have timed out (nfds == 0) or found some input (nfds > 0),
-        we should exit.  */
-      if (nfds >= 0)
+      /* Check for keyboard input */
+
+      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;
+       }
+
+      /* If wait_for_cell. check for keyboard input
+        but don't run any timers.
+        ??? (It seems wrong to me to check for keyboard
+        input at all when wait_for_cell, but the code
+        has been this way since July 1994.
+        Try changing this after version 19.31.)  */
+      if (wait_for_cell
+         && detect_input_pending ())
+       {
+         swallow_events (do_display);
+         if (detect_input_pending ())
+           break;
+       }
+
+      /* Exit now if the cell we're waiting for became non-nil.  */
+      if (wait_for_cell && ! NILP (*wait_for_cell))
        break;
     }