(read_process_output): Deactivate the mark.
[bpt/emacs.git] / src / process.c
index 35a3054..91e411e 100644 (file)
@@ -1,11 +1,11 @@
 /* Asynchronous subprocess control for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -71,7 +71,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "termhooks.h"
 #include "termopts.h"
 #include "commands.h"
-#include "dispextern.h"
+#include "frame.h"
 
 Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
 /* Qexit is declared and initialized in eval.c.  */
@@ -110,7 +110,7 @@ static Lisp_Object stream_process;
 
 #ifndef VMS
 #ifndef WAITTYPE
-#if !defined (BSD) && !defined (UNIPLUS) && !defined (STRIDE) && !(defined (HPUX) && !defined (NOMULTIPLEJOBS)) && !defined (HAVE_WAIT_HEADER)
+#if (!defined (BSD) && !defined (UNIPLUS) && !defined (STRIDE) && !(defined (HPUX) && !defined (NOMULTIPLEJOBS)) && !defined (HAVE_WAIT_HEADER)) || defined (LINUX)
 #define WAITTYPE int
 #define WIFSTOPPED(w) ((w&0377) == 0177)
 #define WIFSIGNALED(w) ((w&0377) != 0177 && (w&~0377) == 0)
@@ -159,10 +159,14 @@ static Lisp_Object stream_process;
 #endif /* BSD or UNIPLUS or STRIDE */
 #endif /* no WAITTYPE */
 #else /* VMS */
-
-/* For the CMU PTY driver + */
-#define DCL_PROMPT "$ "
-
+#define WAITTYPE int
+#define WIFSTOPPED(w) 0
+#define WIFSIGNALED(w) 0
+#define WIFEXITED(w) ((w) != -1)
+#define WRETCODE(w) (w)
+#define WSTOPSIG(w) (w)
+#define WCOREDUMP(w) 0
+#define WTERMSIG(w) (w)
 #include <ssdef.h>
 #include <iodef.h>
 #include <clidef.h>
@@ -175,7 +179,9 @@ extern char *sys_errlist[];
 
 #ifndef VMS
 #ifndef BSD4_1
+#ifndef LINUX
 extern char *sys_siglist[];
+#endif
 #else
 char *sys_siglist[] =
   {
@@ -209,13 +215,6 @@ char *sys_siglist[] =
 #endif
 #endif /* VMS */
 
-#ifdef vipc
-
-#include "vipc.h"
-extern int comm_server;
-extern int net_listen_address;
-#endif /* vipc */
-
 /* t means use pty, nil means use a pipe,
    maybe other values to come.  */
 Lisp_Object Vprocess_connection_type;
@@ -236,7 +235,11 @@ int update_tick;
 /* 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
@@ -349,7 +352,11 @@ status_message (status)
 
   if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
     {
+#ifndef VMS
       string = build_string (code < NSIG ? sys_siglist[code] : "unknown");
+#else
+      string = build_string (code < NSIG ? sys_errlist[code] : "unknown");
+#endif
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
       XSTRING (string)->data[0] = DOWNCASE (XSTRING (string)->data[0]);
       return concat2 (string, string2);
@@ -358,7 +365,7 @@ status_message (status)
     {
       if (code == 0)
        return build_string ("finished\n");
-      string = Fint_to_string (make_number (code));
+      string = Fnumber_to_string (make_number (code));
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
       return concat2 (build_string ("exited abnormally with code "),
                      concat2 (string, string2));
@@ -443,7 +450,7 @@ allocate_pty ()
            if (access (pty_name, 6) != 0)
              {
                close (fd);
-#ifndef IRIS
+#if !defined(IRIS) && !defined(__sgi)
                continue;
 #else
                return -1;
@@ -847,7 +854,7 @@ Proc         Status   Buffer         Command\n\
          tem = Fcar (Fcdr (p->status));
 #ifdef VMS
          if (XINT (tem) < NSIG)
-           write_string (sys_siglist [XINT (tem)], -1);
+           write_string (sys_errlist [XINT (tem)], -1);
          else
 #endif
            Fprinc (symbol, Qnil);
@@ -930,6 +937,10 @@ DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
   return Fmapcar (Qcdr, Vprocess_alist);
 }
 \f
+/* Starting asynchronous inferior processes.  */
+
+static Lisp_Object start_process_unwind ();
+
 DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
   "Start a program in a subprocess.  Return the process object for it.\n\
 Args are NAME BUFFER PROGRAM &rest PROGRAM-ARGS\n\
@@ -945,7 +956,7 @@ Remaining arguments are strings to give program as arguments.")
      int nargs;
      register Lisp_Object *args;
 {
-  Lisp_Object buffer, name, program, proc, tem;
+  Lisp_Object buffer, name, program, proc, current_dir, tem;
 #ifdef VMS
   register unsigned char *new_argv;
   int len;
@@ -953,11 +964,38 @@ Remaining arguments are strings to give program as arguments.")
   register unsigned char **new_argv;
 #endif
   register int i;
+  int count = specpdl_ptr - specpdl;
 
   buffer = args[1];
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer);
 
+  /* Make sure that the child will be able to chdir to the current
+     buffer's current directory, or its unhandled equivalent.  We
+     can't just have the child check for an error when it does the
+     chdir, since it's in a vfork.
+
+     We have to GCPRO around this because Fexpand_file_name and
+     Funhandled_file_name_directory might call a file name handling
+     function.  The argument list is protected by the caller, so all
+     we really have to worry about is buffer.  */
+  {
+    struct gcpro gcpro1, gcpro2;
+
+    current_dir = current_buffer->directory;
+
+    GCPRO2 (buffer, current_dir);
+
+    current_dir = 
+      expand_and_dir_to_file
+       (Funhandled_file_name_directory (current_dir), Qnil);
+    if (NILP (Ffile_accessible_directory_p (current_dir)))
+      report_file_error ("Setting current directory",
+                        Fcons (current_buffer->directory, Qnil));
+
+    UNGCPRO;
+  }
+
   name = args[0];
   CHECK_STRING (name, 0);
 
@@ -984,6 +1022,8 @@ Remaining arguments are strings to give program as arguments.")
       strcat (new_argv, " ");
       strcat (new_argv, XSTRING (tem)->data);
     }
+  /* Need to add code here to check for program existence on VMS */
+  
 #else /* not VMS */
   new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
 
@@ -1000,7 +1040,7 @@ Remaining arguments are strings to give program as arguments.")
   if (new_argv[0][0] != '/')
     {
       tem = Qnil;
-      openp (Vexec_path, program, "", &tem, 1);
+      openp (Vexec_path, program, EXEC_SUFFIXES, &tem, 1);
       if (NILP (tem))
        report_file_error ("Searching for program", Fcons (program, Qnil));
       new_argv[0] = XSTRING (tem)->data;
@@ -1008,6 +1048,11 @@ Remaining arguments are strings to give program as arguments.")
 #endif /* not VMS */
 
   proc = make_process (name);
+  /* If an error occurs and we can't start the process, we want to
+     remove it from the process list.  This means that each error
+     check in create_process doesn't need to call remove_process
+     itself; it's all taken care of here.  */
+  record_unwind_protect (start_process_unwind, proc);
 
   XPROCESS (proc)->childp = Qt;
   XPROCESS (proc)->command_channel_p = Qnil;
@@ -1016,11 +1061,30 @@ Remaining arguments are strings to give program as arguments.")
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
 
-  create_process (proc, new_argv);
+  create_process (proc, new_argv, current_dir);
 
-  return proc;
+  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
+   an error and the process wasn't started successfully, so we should
+   remove it from the process list.  */
+static Lisp_Object
+start_process_unwind (proc)
+     Lisp_Object proc;
+{
+  if (XTYPE (proc) != Lisp_Process)
+    abort ();
+
+  /* Was PROC started successfully?  */
+  if (XPROCESS (proc)->pid <= 0)
+    remove_process (proc);
+
+  return Qnil;
 }
 
+
 SIGTYPE
 create_process_1 (signo)
      int signo;
@@ -1052,9 +1116,10 @@ create_process_sigchld ()
 #endif
 
 #ifndef VMS /* VMS version of this function is in vmsproc.c.  */
-create_process (process, new_argv)
+create_process (process, new_argv, current_dir)
      Lisp_Object process;
      char **new_argv;
+     Lisp_Object current_dir;
 {
   int pid, inchannel, outchannel, forkin, forkout;
   int sv[2];
@@ -1062,7 +1127,6 @@ create_process (process, new_argv)
   SIGTYPE (*sigchld)();
 #endif
   int pty_flag = 0;
-  Lisp_Object current_dir;
   extern char **environ;
 
   inchannel = outchannel = -1;
@@ -1071,14 +1135,6 @@ create_process (process, new_argv)
   if (EQ (Vprocess_connection_type, Qt))
     outchannel = inchannel = allocate_pty ();
 
-  /* Make sure that the child will be able to chdir to the current
-     buffer's current directory.  We can't just have the child check
-     for an error when it does the chdir, since it's in a vfork.  */
-  current_dir = expand_and_dir_to_file (current_buffer->directory, Qnil);
-  if (NILP (Ffile_accessible_directory_p (current_dir)))
-    report_file_error ("Setting current directory",
-                      Fcons (current_buffer->directory, Qnil));
-
   if (inchannel >= 0)
     {
 #ifndef USG 
@@ -1203,8 +1259,10 @@ create_process (process, new_argv)
        setsid ();
 #ifdef TIOCSCTTY
        /* Make the pty's terminal the controlling terminal.  */
-       if (pty_flag && (ioctl (xforkin, TIOCSCTTY, 0) < 0))
-         abort ();
+       if (pty_flag)
+         /* We ignore the return value
+            because faith@cs.unc.edu says that is necessary on Linux.  */
+         ioctl (xforkin, TIOCSCTTY, 0);
 #endif
 #else /* not HAVE_SETSID */
 #ifdef USG
@@ -1282,11 +1340,8 @@ create_process (process, new_argv)
   }
 
   if (pid < 0)
-    {
-      remove_process (process);
-      report_file_error ("Doing vfork", Qnil);
-    }
-
+    report_file_error ("Doing vfork", Qnil);
+  
   XFASTINT (XPROCESS (process)->pid) = pid;
 
   FD_SET (inchannel, &input_wait_mask);
@@ -1401,8 +1456,13 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
       host_info.h_name = 0;
       host_info.h_aliases = 0;
       host_info.h_addrtype = AF_INET;
-      host_info.h_addr_list  =  &(addr_list[0]);
-      addr_list[0] = (char*)(&numeric_addr);
+#ifdef h_addr
+      /* Older machines have only one address slot called h_addr.
+        Newer machines have h_addr_list, but #define h_addr to
+        be its first element.  */
+      host_info.h_addr_list = &(addr_list[0]);
+#endif
+      host_info.h_addr = (char*)(&numeric_addr);
       addr_list[1] = 0;
       host_info.h_length = strlen (addr_list[0]);
     }
@@ -1482,7 +1542,7 @@ deactivate_process (proc)
       {
        VMS_PROC_STUFF *get_vms_process_pointer (), *vs;
        sys$dassgn (outchannel);
-       vs = get_vms_process_pointer (p->pid)
+       vs = get_vms_process_pointer (p->pid);
        if (vs)
          give_back_vms_process_stuff (vs);
       }
@@ -1603,11 +1663,16 @@ static int waiting_for_user_input_p;
      zero for no limit, or
      -1 means gobble data immediately available but don't wait for any.
 
+   microsecs is:
+     an additional duration to wait (if time_limit is greater than
+     zero), specified in millisec.
+
    read_kbd is a lisp value:
      0 to ignore keyboard input, or
      1 to return when input is available, or
-     -1 means caller will actually read the input, so don't throw to
+     -1 meaning caller will actually read the input, so don't throw to
        the quit handler, or
+     a cons cell, meaning wait wait until its car is non-nil, or
      a process object, meaning wait until something arrives from that
        process.  The return value is true iff we read some input from
        that process.
@@ -1634,6 +1699,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
   int wait_channel = 0;
   struct Lisp_Process *wait_proc = 0;
   int got_some_input = 0;
+  Lisp_Object *wait_for_cell = 0;
 
   FD_ZERO (&Available);
 
@@ -1646,6 +1712,13 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       XFASTINT (read_kbd) = 0;
     }
 
+  /* If waiting for non-nil in a cell, record where.  */
+  if (XTYPE (read_kbd) == Lisp_Cons)
+    {
+      wait_for_cell = &XCONS (read_kbd)->car;
+      XFASTINT (read_kbd) = 0;
+    }
+
   waiting_for_user_input_p = XINT (read_kbd);
 
   /* Since we may need to wait several times,
@@ -1665,23 +1738,6 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       if (XINT (read_kbd) >= 0)
        QUIT;
 
-      /* If status of something has changed, and no input is available,
-        notify the user of the change right away */
-      if (update_tick != process_tick && do_display)
-       {
-         Atemp = input_wait_mask;
-         EMACS_SET_SECS_USECS (timeout, 0, 0);
-         if (select (MAXDESC, &Atemp, 0, 0, &timeout) <= 0)
-           status_notify ();
-       }
-
-      /* Don't wait for output from a non-running process.  */
-      if (wait_proc != 0 && !NILP (wait_proc->raw_status_low))
-       update_status (wait_proc);
-      if (wait_proc != 0
-         && ! EQ (wait_proc->status, Qrun))
-       break;
-
       /* Compute time from now till when time limit is up */
       /* Exit if already run out */
       if (time_limit == -1)
@@ -1705,10 +1761,41 @@ 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 */
+        and cause input available signals to zero out timeout.
+
+        It is important that we do this before checking for process
+        activity.  If we get a SIGCHLD after the explicit checks for
+        process activity, timeout is the only way we will know.  */
       if (XINT (read_kbd) < 0)
        set_waiting_for_input (&timeout);
 
+      /* If status of something has changed, and no input is
+        available, notify the user of the change right away.  After
+        this explicit check, we'll let the SIGCHLD handler zap
+        timeout to get our attention.  */
+      if (update_tick != process_tick && do_display)
+       {
+         Atemp = input_wait_mask;
+         EMACS_SET_SECS_USECS (timeout, 0, 0);
+         if (select (MAXDESC, &Atemp, 0, 0, &timeout) <= 0)
+           {
+             /* It's okay for us to do this and then continue with
+                the loop, since timeout has already been zeroed out. */
+             clear_waiting_for_input ();
+             status_notify ();
+           }
+       }
+
+      /* Don't wait for output from a non-running process.  */
+      if (wait_proc != 0 && !NILP (wait_proc->raw_status_low))
+       update_status (wait_proc);
+      if (wait_proc != 0
+         && ! EQ (wait_proc->status, Qrun))
+       {
+         clear_waiting_for_input ();
+         break;
+       }
+
       /* Wait till there is something to do */
 
       Available = input_wait_mask;
@@ -1718,7 +1805,8 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /* 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.  */
+        and indicates that a frame is trashed, the select may block
+        displaying a trashed screen.  */
       if (frame_garbaged)
        redisplay_preserve_echo_area ();
 
@@ -1741,9 +1829,12 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
        {
          if (xerrno == EINTR)
            FD_ZERO (&Available);
-#ifdef __ultrix__
-         /* Ultrix select seems to return ENOMEM when it is interrupted.
-            Treat it just like EINTR.  Bleah.  -JimB  */
+#ifdef ultrix
+         /* Ultrix select seems to return ENOMEM when it is
+            interrupted.  Treat it just like EINTR.  Bleah.  Note
+            that we want to test for the "ultrix" CPP symbol, not
+            "__ultrix__"; the latter is only defined under GCC, but
+            not by DEC's bundled CC.  -JimB  */
          else if (xerrno == ENOMEM)
            FD_ZERO (&Available);
 #endif
@@ -1771,9 +1862,15 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
          else
            error("select error: %s", sys_errlist[xerrno]);
        }
-#ifdef sun
+#if defined(sun) && !defined(USG5_4)
       else if (nfds > 0 && FD_ISSET (0, &Available) && interrupt_input)
-       /* System sometimes fails to deliver SIGIO.  */
+       /* System sometimes fails to deliver SIGIO.
+
+          David J. Mackenzie says that Emacs doesn't compile under
+          Solaris if this code is enabled, thus the USG5_4 in the CPP
+          conditional.  "I haven't noticed any ill effects so far.
+          If you find a Solaris expert somewhere, they might know
+          better." */
        kill (getpid (), SIGIO);
 #endif
 
@@ -1782,6 +1879,14 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
         to give it higher priority than subprocesses */
 
       if (XINT (read_kbd) && detect_input_pending ())
+       {
+         swallow_events ();
+         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;
 
 #ifdef SIGIO
@@ -1790,23 +1895,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
         In that case, there really is no input and no SIGIO,
         but select says there is input.  */
 
-      /*
-       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 */
-
-      if (Available & ChannelMask (comm_server))
-       {
-         Available &= ~(ChannelMask (comm_server));
-         create_commchan ();
-       }
-#endif /* vipc */
-
       if (! wait_proc)
        got_some_input |= nfds > 0;
 
@@ -1835,24 +1927,6 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
              if (NILP (proc))
                continue;
 
-#ifdef vipc
-             /* It's a command channel */
-             if (!NILP (XPROCESS (proc)->command_channel_p))
-               {
-                 ProcessCommChan (channel, proc);
-                 if (NILP (XPROCESS (proc)->command_channel_p))
-                   {
-                     /* It has ceased to be a command channel! */
-                     int bytes_available;
-                     if (ioctl (channel, FIONREAD, &bytes_available) < 0)
-                       bytes_available = 0;
-                     if (bytes_available)
-                       FD_SET (channel, &Available);
-                   }
-                 continue;
-               }
-#endif                         /* vipc */
-
              /* Read data from the process, starting with our
                 buffered-ahead character if we have one.  */
 
@@ -2001,9 +2075,25 @@ read_process_output (proc, channel)
         hitting ^G when a filter happens to be running won't screw
         it up.  */
       int count = specpdl_ptr - specpdl;
+      Lisp_Object odeactivate;
+
+      odeactivate = Vdeactivate_mark;
+
       specbind (Qinhibit_quit, Qt);
       call2 (outstream, proc, make_string (chars, nchars));
 
+      /* Deactivate the mark now, so it doesn't happen
+        *after* the following command.  */
+      if (!NILP (current_buffer->mark_active))
+       {
+         if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
+           {
+             current_buffer->mark_active = Qnil;
+             call1 (Vrun_hooks, intern ("deactivate-mark-hook"));
+           }
+       }
+      Vdeactivate_mark = odeactivate;
+
 #ifdef VMS
       start_vms_process_read (vs);
 #endif
@@ -2014,10 +2104,19 @@ read_process_output (proc, channel)
   /* If no filter, write into buffer if it isn't dead.  */
   if (!NILP (p->buffer) && !NILP (XBUFFER (p->buffer)->name))
     {
-      Lisp_Object tem;
+      Lisp_Object old_read_only;
+      Lisp_Object old_begv, old_zv;
+      Lisp_Object odeactivate;
+
+      odeactivate = Vdeactivate_mark;
 
       Fset_buffer (p->buffer);
       opoint = point;
+      old_read_only = current_buffer->read_only;
+      XFASTINT (old_begv) = BEGV;
+      XFASTINT (old_zv) = ZV;
+
+      current_buffer->read_only = Qnil;
 
       /* Insert new output into buffer
         at the current end-of-output marker,
@@ -2026,18 +2125,48 @@ read_process_output (proc, channel)
        SET_PT (marker_position (p->mark));
       else
        SET_PT (ZV);
+
+      /* If the output marker is outside of the visible region, save
+        the restriction and widen.  */
+      if (! (BEGV <= point && point <= ZV))
+       Fwiden ();
+
+      /* Make sure opoint floats ahead of any new text, just as point
+        would.  */
       if (point <= opoint)
        opoint += nchars;
 
-      tem = current_buffer->read_only;
-      current_buffer->read_only = Qnil;
+      /* Insert after old_begv, but before old_zv.  */
+      if (point < XFASTINT (old_begv))
+       XFASTINT (old_begv) += nchars;
+      if (point <= XFASTINT (old_zv))
+       XFASTINT (old_zv) += nchars;
+
       /* Insert before markers in case we are inserting where
         the buffer's mark is, and the user's next command is Meta-y.  */
       insert_before_markers (chars, nchars);
-      current_buffer->read_only = tem;
       Fset_marker (p->mark, make_number (point), p->buffer);
+
       update_mode_lines++;
 
+      /* If the restriction isn't what it should be, set it.  */
+      if (XFASTINT (old_begv) != BEGV || XFASTINT (old_zv) != ZV)
+       Fnarrow_to_region (old_begv, old_zv);
+
+      /* Deactivate the mark now, so it doesn't happen
+        *after* the following command.  */
+      if (!NILP (current_buffer->mark_active))
+       {
+         if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
+           {
+             current_buffer->mark_active = Qnil;
+             call1 (Vrun_hooks, intern ("deactivate-mark-hook"));
+           }
+       }
+
+      Vdeactivate_mark = odeactivate;
+
+      current_buffer->read_only = old_read_only;
       SET_PT (opoint);
       set_buffer_internal (old);
     }
@@ -2209,7 +2338,11 @@ Output from processes can arrive in between bunches.")
    the terminal being used to communicate with PROCESS.
    This is used for various commands in shell mode.
    If NOMSG is zero, insert signal-announcements into process's buffers
-   right away.  */
+   right away.
+
+   If we can, we try to signal PROCESS by sending control characters
+   down the pipe.  This allows us to signal inferiors who have changed
+   their uid, for which killpg would return an EPERM error.  */
 
 static void
 process_send_signal (process, signo, current_group, nomsg)
@@ -2239,9 +2372,43 @@ process_send_signal (process, signo, current_group, nomsg)
   /* If we are using pgrps, get a pgrp number and make it negative.  */
   if (!NILP (current_group))
     {
+#ifdef SIGNALS_VIA_CHARACTERS
       /* If possible, send signals to the entire pgrp
         by sending an input character to it.  */
+
+      /* TERMIOS is the latest and bestest, and seems most likely to
+         work.  If the system has it, use it.  */
+#ifdef HAVE_TERMIOS
+      struct termios t;
+
+      switch (signo)
+       {
+       case SIGINT:
+         tcgetattr (XFASTINT (p->infd), &t);
+         send_process (proc, &t.c_cc[VINTR], 1);
+         return;
+
+       case SIGQUIT:
+         tcgetattr (XFASTINT (p->infd), &t);
+         send_process (proc, &t.c_cc[VQUIT], 1);
+         return;
+
+       case SIGTSTP:
+         tcgetattr (XFASTINT (p->infd), &t);
+#ifdef VSWTCH
+         send_process (proc, &t.c_cc[VSWTCH], 1);
+#else
+         send_process (proc, &t.c_cc[VSUSP], 1);
+#endif
+         return;
+       }
+
+#else /* ! HAVE_TERMIOS */
+
+      /* On Berkeley descendants, the following IOCTL's retrieve the
+        current control characters.  */
 #if defined (TIOCGLTC) && defined (TIOCGETC)
+
       struct tchars c;
       struct ltchars lc;
 
@@ -2260,13 +2427,14 @@ process_send_signal (process, signo, current_group, nomsg)
          ioctl (XFASTINT (p->infd), TIOCGLTC, &lc);
          send_process (proc, &lc.t_suspc, 1);
          return;
-#endif /* SIGTSTP */
+#endif /* ! defined (SIGTSTP) */
        }
-#endif /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
-      /* It is possible that the following code would work
-        on other kinds of USG systems, not just on the IRIS.
-        This should be tried in Emacs 19.  */
-#if defined (USG)
+
+#else /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
+
+      /* On SYSV descendants, the TCGETA ioctl retrieves the current control
+        characters.  */
+#ifdef TCGETA
       struct termio t;
       switch (signo)
        {
@@ -2283,16 +2451,23 @@ process_send_signal (process, signo, current_group, nomsg)
          ioctl (XFASTINT (p->infd), TCGETA, &t);
          send_process (proc, &t.c_cc[VSWTCH], 1);
          return;
-#endif
+#endif /* ! defined (SIGTSTP) */
        }
-#endif /* ! defined (USG) */
+#else /* ! defined (TCGETA) */
+      Your configuration files are messed up.
+      /* If your system configuration files define SIGNALS_VIA_CHARACTERS,
+        you'd better be using one of the alternatives above!  */
+#endif /* ! defined (TCGETA) */
+#endif /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
+#endif /* ! defined HAVE_TERMIOS */
+#endif /* ! defined (SIGNALS_VIA_CHARACTERS) */
 
 #ifdef TIOCGPGRP 
       /* Get the pgrp using the tty itself, if we have that.
         Otherwise, use the pty to get the pgrp.
         On pfa systems, saka@pfu.fujitsu.co.JP writes:
-        "TICGPGRP symbol defined in sys/ioctl.h at E50.
-         But, TIOCGPGRP does not work on E50 ;-P works fine on E60"
+        "TIOCGPGRP symbol defined in sys/ioctl.h at E50.
+        But, TIOCGPGRP does not work on E50 ;-P works fine on E60"
         His patch indicates that if TIOCGPGRP returns an error, then
         we should just assume that p->pid is also the process group id.  */
       {
@@ -2312,7 +2487,7 @@ process_send_signal (process, signo, current_group, nomsg)
        no_pgrp = 1;
       else
        gid = - gid;
-#else /* ! defined (TIOCGPGRP ) */
+#else  /* ! defined (TIOCGPGRP ) */
       /* Can't select pgrps on this system, so we know that
         the child itself heads the pgrp.  */
       gid = - XFASTINT (p->pid);
@@ -2462,6 +2637,13 @@ nil, indicating the current buffer's process.")
   Lisp_Object proc;
 
   proc = get_process (process);
+
+  /* Make sure the process is really alive.  */
+  if (! NILP (XPROCESS (proc)->raw_status_low))
+    update_status (XPROCESS (proc));
+  if (! EQ (XPROCESS (proc)->status, Qrun))
+    error ("Process %s not running", XSTRING (XPROCESS (proc)->name)->data);
+
   /* Sending a zero-length record is supposed to mean eof
      when TIOCREMOTE is turned on.  */
 #ifdef DID_REMOTE
@@ -2478,7 +2660,7 @@ nil, indicating the current buffer's process.")
   else
     {
       close (XPROCESS (proc)->outfd);
-      XFASTINT (XPROCESS (proc)->outfd) = open ("/dev/null", O_WRONLY);
+      XFASTINT (XPROCESS (proc)->outfd) = open (NULL_DEVICE, O_WRONLY);
     }
 #endif /* VMS */
 #endif /* did not do TOICREMOTE */
@@ -2536,6 +2718,7 @@ sigchld_handler (signo)
   int old_errno = errno;
   Lisp_Object proc;
   register struct Lisp_Process *p;
+  extern EMACS_TIME *input_available_clear_time;
 
 #ifdef BSD4_1
   extern int sigheld;
@@ -2618,6 +2801,11 @@ sigchld_handler (signo)
          if (WIFSIGNALED (w) || WIFEXITED (w))
            if (XFASTINT (p->infd))
              FD_CLR (XFASTINT (p->infd), &input_wait_mask);
+
+         /* Tell wait_reading_process_input that it needs to wake up and
+            look around.  */
+         if (input_available_clear_time)
+           EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
        }
 
        /* There was no asynchronous process found for that id.  Check
@@ -2630,7 +2818,16 @@ sigchld_handler (signo)
          if (WIFEXITED (w))
            synch_process_retcode = WRETCODE (w);
          else if (WIFSIGNALED (w))
+#ifndef VMS
            synch_process_death = sys_siglist[WTERMSIG (w)];
+#else
+           synch_process_death = sys_errlist[WTERMSIG (w)];
+#endif
+
+         /* Tell wait_reading_process_input that it needs to wake up and
+            look around.  */
+         if (input_available_clear_time)
+           EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
        }
 
       /* On some systems, we must return right away.
@@ -3021,6 +3218,8 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
        break;
     }
 
+  start_polling ();
+
   return 0;
 }