]> code.delx.au - gnu-emacs/blobdiff - src/process.c
*** empty log message ***
[gnu-emacs] / src / process.c
index 8ddfe240eb69ddbf81f14f3e298c538d5eb23ded..e950a7b4395df7c6c83465a44accb4cfdc9ea0f9 100644 (file)
@@ -22,8 +22,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "config.h"
 
+/* This file is split into two parts by the following preprocessor
+   conditional.  The 'then' clause contains all of the support for
+   asynchronous subprocesses.  The 'else' clause contains stub
+   versions of some of the asynchronous subprocess routines that are
+   often called elsewhere in Emacs, so we don't have to #ifdef the
+   sections that call them.  */
+
+\f
 #ifdef subprocesses
-/* The entire file is within this conditional */
 
 #include <stdio.h>
 #include <errno.h>
@@ -58,41 +65,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <bsdtty.h>
 #endif
 
-#ifdef HPUX
-#undef TIOCGPGRP
-#endif
-
 #ifdef IRIS
 #include <sys/sysmacros.h>     /* for "minor" */
 #endif /* not IRIS */
 
 #include "systime.h"
-
-#if defined (HPUX) && defined (HAVE_PTYS)
-#include <sys/ptyio.h>
-#endif
-
-#ifdef AIX
-#include <sys/pty.h>
-#include <unistd.h>
-#endif
-
-#ifdef SYSV_PTYS
-#include <sys/tty.h>
-#ifdef titan
-#include <sys/ttyhw.h>
-#include <sys/stream.h>
-#endif
-#include <sys/pty.h>
-#endif
-
-#ifdef XENIX
-#undef TIOCGETC  /* Avoid confusing some conditionals that test this.  */
-#endif
-
-#ifdef BROKEN_TIOCGETC
-#undef TIOCGETC
-#endif
+#include "systerm.h"
 
 #include "lisp.h"
 #include "window.h"
@@ -101,8 +79,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "termhooks.h"
 #include "termopts.h"
 #include "commands.h"
-
-extern int screen_garbaged;
+#include "dispextern.h"
 
 Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
 /* Qexit is declared and initialized in eval.c.  */
@@ -396,7 +373,7 @@ status_message (status)
 }
 \f
 #ifdef HAVE_PTYS
-static pty_process;
+static int pty_process;
 
 /* Open an available pty, returning a file descriptor.
    Return -1 on failure.
@@ -412,6 +389,13 @@ allocate_pty ()
   register c, i;
   int fd;
 
+  /* Some systems name their pseudoterminals so that there are gaps in
+     the usual sequence - for example, on HP9000/S700 systems, there
+     are no pseudoterminals with names ending in 'f'.  So we wait for
+     three failures in a row before deciding that we've reached the
+     end of the ptys.  */
+  int failed_count = 0;
+
 #ifdef PTY_ITERATION
   PTY_ITERATION
 #else
@@ -433,20 +417,27 @@ allocate_pty ()
 #endif /* not HPUX */
 #endif /* no PTY_NAME_SPRINTF */
 
-#ifndef IRIS
-       if (stat (pty_name, &stb) < 0)
+#ifdef IRIS
+       /* Unusual IRIS code */
+       *ptyv = open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
+       if (fd < 0)
+         return -1;
+       if (fstat (fd, &stb) < 0)
          return -1;
+#else
+       if (stat (pty_name, &stb) < 0)
+         {
+           failed_count++;
+           if (failed_count >= 3)
+             return -1;
+         }
+       else
+         failed_count = 0;
 #ifdef O_NONBLOCK
        fd = open (pty_name, O_RDWR | O_NONBLOCK, 0);
 #else
        fd = open (pty_name, O_RDWR | O_NDELAY, 0);
 #endif
-#else /* Unusual IRIS code */
-       *ptyv = open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
-       if (fd < 0)
-         return -1;
-       if (fstat (fd, &stb) < 0)
-         return -1;
 #endif /* IRIS */
 
        if (fd >= 0)
@@ -1089,11 +1080,8 @@ create_process (process, new_argv)
 #endif
   int pty_flag = 0;
   Lisp_Object current_dir;
-  char **env;
   extern char **environ;
 
-  env = environ;
-
   inchannel = outchannel = -1;
 
 #ifdef HAVE_PTYS
@@ -1298,7 +1286,7 @@ create_process (process, new_argv)
 
        child_setup_tty (xforkout);
        child_setup (xforkin, xforkout, xforkout,
-                    new_argv, env, 1, current_dir);
+                    new_argv, 1, current_dir);
       }
     environ = save_environ;
   }
@@ -1599,10 +1587,11 @@ Return non-nil iff we received any output before the timeout expired.")
        seconds = 0;
     }
 
+  if (NILP (proc))
+    XFASTINT (proc) = 0;
+
   return
-    (wait_reading_process_input (seconds, useconds,
-                                (NILP (proc)
-                                 ? XPROCESS (get_process (proc)) : 0), 0)
+    (wait_reading_process_input (seconds, useconds, proc, 0)
      ? Qt : Qnil);
 }
 
@@ -1622,14 +1611,14 @@ static int waiting_for_user_input_p;
      zero for no limit, or
      -1 means gobble data immediately available but don't wait for any.
 
-   read_kbd is:
+   read_kbd is a lisp value:
      0 to ignore keyboard input, or
      1 to return when input is available, or
      -1 means caller will actually read the input, so don't throw to
        the quit handler, or
-     a pointer to a struct Lisp_Process, meaning wait until something
-       arrives from that process.  The return value is true iff we read
-       some input from that process.
+     a process object, meaning wait until something arrives from that
+       process.  The return value is true iff we read some input from
+       that process.
 
    do_display != 0 means redisplay should be done to show subprocess
    output that arrives.
@@ -1640,7 +1629,9 @@ static int waiting_for_user_input_p;
    Otherwise, return true iff we recieved input from any process.  */
 
 wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
-     int time_limit, microsecs, read_kbd, do_display;
+     int time_limit, microsecs;
+     Lisp_Object read_kbd;
+     int do_display;
 {
   register int channel, nfds, m;
   static SELECT_TYPE Available;
@@ -1654,15 +1645,16 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
   FD_ZERO (&Available);
 
-  /* Detect when read_kbd is really the address of a Lisp_Process.  */
-  if (read_kbd > 10 || read_kbd < -1)
+  /* If read_kbd is a process to watch, set wait_proc and wait_channel
+     accordingly.  */
+  if (XTYPE (read_kbd) == Lisp_Process)
     {
-      wait_proc = (struct Lisp_Process *) read_kbd;
+      wait_proc = XPROCESS (read_kbd);
       wait_channel = XFASTINT (wait_proc->infd);
-      read_kbd = 0;
+      XFASTINT (read_kbd) = 0;
     }
 
-  waiting_for_user_input_p = read_kbd;
+  waiting_for_user_input_p = XINT (read_kbd);
 
   /* Since we may need to wait several times,
      compute the absolute time to return at.  */
@@ -1673,16 +1665,12 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       EMACS_ADD_TIME (end_time, end_time, timeout);
     }
 
-  /* Turn off periodic alarms (in case they are in use)
-     because the select emulator uses alarms.  */
-  stop_polling ();
-
   while (1)
     {
       /* If calling from keyboard input, do not quit
         since we want to return C-g as an input character.
         Otherwise, do pending quit if requested.  */
-      if (read_kbd >= 0)
+      if (XINT (read_kbd) >= 0)
        QUIT;
 
       /* If status of something has changed, and no input is available,
@@ -1726,32 +1714,27 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
       /* Cause C-g and alarm signals to take immediate action,
         and cause input available signals to zero out timeout */
-      if (read_kbd < 0)
+      if (XINT (read_kbd) < 0)
        set_waiting_for_input (&timeout);
 
       /* Wait till there is something to do */
 
       Available = input_wait_mask;
-      if (!read_kbd)
+      if (! XINT (read_kbd))
        FD_CLR (0, &Available);
 
-      /* If a screen has been newly mapped and needs updating,
-        reprocess its display stuff.  */
-      if (screen_garbaged)
+      /* If frame size has changed or the window is newly mapped,
+        redisplay now, before we start to wait.  There is a race
+        condition here; if a SIGIO arrives between now and the select
+        and indicates that a frame is trashed, we lose.  */
+      if (frame_garbaged)
        redisplay_preserve_echo_area ();
 
-      if (read_kbd && detect_input_pending ())
+      if (XINT (read_kbd) && detect_input_pending ())
        nfds = 0;
       else
-#ifdef AIX
-       nfds = select (MAXDESC, &Available, 0, 0, &timeout);
-#else
-#ifdef HPUX
-       nfds = select (MAXDESC, &Available, 0, 0, &timeout);
-#else
        nfds = select (MAXDESC, &Available, 0, 0, &timeout);
-#endif
-#endif
+
       xerrno = errno;
 
       /* Make C-g and alarm signals set flags again */
@@ -1760,7 +1743,7 @@ 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 elapsed */
        break;
       if (nfds < 0)
        {
@@ -1782,7 +1765,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF
                 in m-ibmrt-aix.h), and here we just ignore the select error.
                 Cleanup occurs c/o status_notify after SIGCLD. */
-             FD_ZERO (&Available);          /* Cannot depend on values returned */
+             FD_ZERO (&Available); /* Cannot depend on values returned */
 #else
              abort ();
 #endif
@@ -1800,19 +1783,21 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /* If there is any, return immediately
         to give it higher priority than subprocesses */
 
-      if (read_kbd && detect_input_pending ())
+      if (XINT (read_kbd) && detect_input_pending ())
        break;
 
+#ifdef SIGIO
       /* If we think we have keyboard input waiting, but didn't get SIGIO
         go read it.  This can happen with X on BSD after logging out.
         In that case, there really is no input and no SIGIO,
         but select says there is input.  */
 
       /*
-      if (read_kbd && interrupt_input && (Available & fileno (stdin)))
-      */
-      if (read_kbd && interrupt_input && (FD_ISSET (fileno (stdin), &Available)))
+       if (XINT (read_kbd) && interrupt_input && (Available & fileno (stdin)))
+       */
+      if (XINT (read_kbd) && interrupt_input && (FD_ISSET (fileno (stdin), &Available)))
        kill (0, SIGIO);
+#endif
 
 #ifdef vipc
       /* Check for connection from other process */
@@ -1827,6 +1812,11 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       if (! wait_proc)
        got_some_input |= nfds > 0;
 
+      /* If checking input just got us a size-change event from X,
+        obey it now if we should.  */
+      if (XINT (read_kbd))
+       do_pending_window_change ();
+
       /* Check for data from a process or a command channel */
       for (channel = FIRST_PROC_DESC; channel < MAXDESC; channel++)
        {
@@ -1863,7 +1853,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                    }
                  continue;
                }
-#endif /* vipc */
+#endif                         /* vipc */
 
              /* Read data from the process, starting with our
                 buffered-ahead character if we have one.  */
@@ -1897,9 +1887,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 subprocess termination and SIGCHLD.  */
              else if (nread == 0 && !NETCONN_P (proc))
                ;
-#endif /* O_NDELAY */
-#endif /* O_NONBLOCK */
-#endif /* EWOULDBLOCK */
+#endif                         /* O_NDELAY */
+#endif                         /* O_NONBLOCK */
+#endif                         /* EWOULDBLOCK */
 #ifdef HAVE_PTYS
              /* On some OSs with ptys, when the process on one end of
                 a pty exits, the other end gets an error reading with
@@ -1910,9 +1900,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 get a SIGCHLD). */
              else if (nread == -1 && errno == EIO)
                ;
-#endif /* HAVE_PTYS */
-/* If we can detect process termination, don't consider the process
-   gone just because its pipe is closed.  */
+#endif                         /* HAVE_PTYS */
+             /* If we can detect process termination, don't consider the process
+                gone just because its pipe is closed.  */
 #ifdef SIGCHLD
              else if (nread == 0 && !NETCONN_P (proc))
                ;
@@ -1929,11 +1919,18 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                      = Fcons (Qexit, Fcons (make_number (256), Qnil));
                }
            }
-       } /* end for each file descriptor */
-    } /* end while exit conditions not met */
+       }                       /* end for each file descriptor */
+    }                          /* end while exit conditions not met */
 
-  /* Resume periodic signals to poll for input, if necessary.  */
-  start_polling ();
+  /* If calling from keyboard input, do not quit
+     since we want to return C-g as an input character.
+     Otherwise, do pending quit if requested.  */
+  if (XINT (read_kbd) >= 0)
+    {
+      /* Prevent input_pending from remaining set if we quit.  */
+      clear_input_pending ();
+      QUIT;
+    }
 
   return got_some_input;
 }
@@ -2106,12 +2103,14 @@ send_process (proc, buf, len)
     while (len > 0)
       {
        int this = len;
+       SIGTYPE (*old_sigpipe)();
+
        /* Don't send more than 500 bytes at a time.  */
        if (this > 500)
          this = 500;
-       signal (SIGPIPE, send_process_trap);
+       old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap);
        rv = write (XFASTINT (XPROCESS (proc)->outfd), buf, this);
-       signal (SIGPIPE, SIG_DFL);
+       signal (SIGPIPE, old_sigpipe);
        if (rv < 0)
          {
            if (0
@@ -2139,7 +2138,12 @@ send_process (proc, buf, len)
        /* Allow input from processes between bursts of sending.
           Otherwise things may get stopped up.  */
        if (len > 0)
-         wait_reading_process_input (-1, 0, 0, 0);
+         {
+           Lisp_Object zero;
+
+           XFASTINT (zero) = 0;
+           wait_reading_process_input (-1, 0, zero, 0);
+         }
       }
 #endif
   else
@@ -2794,7 +2798,7 @@ init_process ()
       proc_buffered_char[i] = -1;
     }
 }
-#ifdef 0
+#if 0
 DEFUN ("process-connection", Fprocess_connection, Sprocess_connection, 0, 1, 0,
  "Return the connection type of `PROCESS'.  This can be nil (pipe),\n\
 t or pty (pty) or stream (socket connection).")
@@ -2884,4 +2888,167 @@ effect when `start-process' is called.");
 /*  defsubr (&Sprocess_connection); */
 }
 
-#endif /* subprocesses */
+\f
+#else /* not subprocesses */
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include "lisp.h"
+#include "systime.h"
+#include "termopts.h"
+
+extern int frame_garbaged;
+
+
+/* As described above, except assuming that there are no subprocesses:
+
+   Wait for timeout to elapse and/or keyboard input to be available.
+
+   time_limit is:
+     timeout in seconds, or
+     zero for no limit, or
+     -1 means gobble data immediately available but don't wait for any.
+
+   read_kbd is a Lisp_Object:
+     0 to ignore keyboard input, or
+     1 to return when input is available, or
+     -1 means caller will actually read the input, so don't throw to
+       the quit handler.
+     We know that read_kbd will never be a Lisp_Process, since
+     `subprocesses' isn't defined.
+
+   do_display != 0 means redisplay should be done to show subprocess
+   output that arrives.  This version of the function ignores it.
+
+   Return true iff we recieved input from any process.  */
+
+int
+wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
+     int time_limit, microsecs;
+     Lisp_Object read_kbd;
+     int do_display;
+{
+  EMACS_TIME end_time, timeout, *timeout_p;
+  int waitchannels;
+
+  /* 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);
+      else
+       EMACS_SET_SECS_USECS (timeout, time_limit, microsecs);
+
+      /* How far in the future is that?  */
+      EMACS_GET_TIME (end_time);
+      EMACS_ADD_TIME (end_time, end_time, timeout);
+    }
+  else
+    /* It's infinite.  */
+    timeout_p = 0;
+
+  /* Turn off periodic alarms (in case they are in use)
+     because the select emulator uses alarms.  */
+  stop_polling ();
+
+  for (;;)
+    {
+      int nfds;
+
+      waitchannels = XINT (read_kbd) ? 1 : 0;
+
+      /* If calling from keyboard input, do not quit
+        since we want to return C-g as an input character.
+        Otherwise, do pending quit if requested.  */
+      if (XINT (read_kbd) >= 0)
+       QUIT;
+
+      if (timeout_p)
+       {
+         EMACS_GET_TIME (*timeout_p);
+         EMACS_SUB_TIME (*timeout_p, end_time, *timeout_p);
+         if (EMACS_TIME_NEG_P (*timeout_p))
+           break;
+       }
+
+      /* 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);
+
+      /* If a frame has been newly mapped and needs updating,
+        reprocess its display stuff.  */
+      if (frame_garbaged)
+       redisplay_preserve_echo_area ();
+
+      if (XINT (read_kbd) && detect_input_pending ())
+       nfds = 0;
+      else
+       nfds = select (1, &waitchannels, 0, 0, timeout_p);
+
+      /* Make C-g and alarm signals set flags again */
+      clear_waiting_for_input ();
+
+      /*  If we woke up due to SIGWINCH, actually change size now.  */
+      do_pending_window_change ();
+
+      if (nfds == -1)
+       {
+         /* If the system call was interrupted, then go around the
+            loop again.  */
+         if (errno == EINTR)
+           waitchannels = 0;
+       }
+#ifdef sun
+      else if (nfds > 0 && (waitchannels & 1)  && interrupt_input)
+       /* System sometimes fails to deliver SIGIO.  */
+       kill (getpid (), SIGIO);
+#endif
+      if (XINT (read_kbd) && interrupt_input && (waitchannels & 1))
+       kill (0, SIGIO);
+
+      /* If we have timed out (nfds == 0) or found some input (nfds > 0),
+        we should exit.  */
+      if (nfds >= 0)
+       break;
+    }
+
+  return 0;
+}
+
+
+DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
+  "Return the (or, a) process associated with BUFFER.\n\
+This copy of Emacs has not been built to support subprocesses, so this\n\
+function always returns nil.")
+  (name)
+     register Lisp_Object name;
+{
+  return Qnil;
+}
+
+/* Kill all processes associated with `buffer'.
+   If `buffer' is nil, kill all processes.
+   Since we have no subprocesses, this does nothing.  */
+
+kill_buffer_processes (buffer)
+     Lisp_Object buffer;
+{
+}
+
+init_process ()
+{
+}
+
+syms_of_process ()
+{
+  defsubr (&Sget_buffer_process);
+}
+
+\f
+#endif /* not subprocesses */