Assume POSIX 1003.1-1988 or later for fcntl.h.
[bpt/emacs.git] / src / sysdep.c
index efebb49..7c5c144 100644 (file)
@@ -289,10 +289,6 @@ wait_for_termination_1 (pid_t pid, int interruptible)
 {
   while (1)
     {
-#ifdef WINDOWSNT
-      wait (0);
-      break;
-#else /* not WINDOWSNT */
       int status;
       int wait_result = waitpid (pid, &status, 0);
       if (wait_result < 0)
@@ -306,7 +302,8 @@ wait_for_termination_1 (pid_t pid, int interruptible)
          break;
        }
 
-#endif /* not WINDOWSNT */
+      /* Note: the MS-Windows emulation of waitpid calls QUIT
+        internally.  */
       if (interruptible)
        QUIT;
     }
@@ -452,7 +449,7 @@ sys_suspend (void)
 #if defined (SIGTSTP) && !defined (MSDOS)
 
   {
-    int pgrp = EMACS_GETPGRP (0);
+    pid_t pgrp = getpgrp ();
     EMACS_KILLPG (pgrp, SIGTSTP);
   }
 
@@ -683,6 +680,75 @@ ignore_sigio (void)
 }
 
 \f
+/* Saving and restoring the process group of Emacs's terminal.  */
+
+/* The process group of which Emacs was a member when it initially
+   started.
+
+   If Emacs was in its own process group (i.e. inherited_pgroup ==
+   getpid ()), then we know we're running under a shell with job
+   control (Emacs would never be run as part of a pipeline).
+   Everything is fine.
+
+   If Emacs was not in its own process group, then we know we're
+   running under a shell (or a caller) that doesn't know how to
+   separate itself from Emacs (like sh).  Emacs must be in its own
+   process group in order to receive SIGIO correctly.  In this
+   situation, we put ourselves in our own pgroup, forcibly set the
+   tty's pgroup to our pgroup, and make sure to restore and reinstate
+   the tty's pgroup just like any other terminal setting.  If
+   inherited_group was not the tty's pgroup, then we'll get a
+   SIGTTmumble when we try to change the tty's pgroup, and a CONT if
+   it goes foreground in the future, which is what should happen.  */
+
+static pid_t inherited_pgroup;
+
+void
+init_foreground_group (void)
+{
+  pid_t pgrp = getpgrp ();
+  inherited_pgroup = getpid () == pgrp ? 0 : pgrp;
+}
+
+/* Safely set a controlling terminal FD's process group to PGID.
+   If we are not in the foreground already, POSIX requires tcsetpgrp
+   to deliver a SIGTTOU signal, which would stop us.  This is an
+   annoyance, so temporarily ignore the signal.
+
+   In practice, platforms lacking SIGTTOU also lack tcsetpgrp, so
+   skip all this unless SIGTTOU is defined.  */
+static void
+tcsetpgrp_without_stopping (int fd, pid_t pgid)
+{
+#ifdef SIGTTOU
+  signal_handler_t handler;
+  block_input ();
+  handler = signal (SIGTTOU, SIG_IGN);
+  tcsetpgrp (fd, pgid);
+  signal (SIGTTOU, handler);
+  unblock_input ();
+#endif
+}
+
+/* Split off the foreground process group to Emacs alone.  When we are
+   in the foreground, but not started in our own process group,
+   redirect the tty device handle FD to point to our own process
+   group.  FD must be the file descriptor of the controlling tty.  */
+static void
+narrow_foreground_group (int fd)
+{
+  if (inherited_pgroup && setpgid (0, 0) == 0)
+    tcsetpgrp_without_stopping (fd, getpid ());
+}
+
+/* Set the tty to our original foreground group.  */
+static void
+widen_foreground_group (int fd)
+{
+  if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0)
+    tcsetpgrp_without_stopping (fd, inherited_pgroup);
+}
+\f
 /* Getting and setting emacs_tty structures.  */
 
 /* Set *TC to the parameters associated with the terminal FD.
@@ -799,6 +865,8 @@ init_sys_modes (struct tty_display_info *tty_out)
   if (!tty_out->output)
     return;                     /* The tty is suspended. */
 
+  narrow_foreground_group (fileno (tty_out->input));
+
   if (! tty_out->old_tty)
     tty_out->old_tty = xmalloc (sizeof *tty_out->old_tty);
 
@@ -968,8 +1036,7 @@ init_sys_modes (struct tty_display_info *tty_out)
 #endif
 #endif
 
-#ifdef F_SETFL
-#ifdef F_GETOWN                /* F_SETFL does not imply existence of F_GETOWN */
+#ifdef F_GETOWN
   if (interrupt_input)
     {
       old_fcntl_owner[fileno (tty_out->input)] =
@@ -987,7 +1054,6 @@ init_sys_modes (struct tty_display_info *tty_out)
 #endif /* HAVE_GPM */
     }
 #endif /* F_GETOWN */
-#endif /* F_SETFL */
 
 #ifdef _IOFBF
   /* This symbol is defined on recent USG systems.
@@ -1207,8 +1273,8 @@ reset_sys_modes (struct tty_display_info *tty_out)
   fsync (fileno (tty_out->output));
 #endif
 
-#ifdef F_SETFL
-#ifdef F_SETOWN                /* F_SETFL does not imply existence of F_SETOWN */
+#ifndef DOS_NT
+#ifdef F_SETOWN
   if (interrupt_input)
     {
       reset_sigio (fileno (tty_out->input));
@@ -1216,11 +1282,9 @@ reset_sys_modes (struct tty_display_info *tty_out)
              old_fcntl_owner[fileno (tty_out->input)]);
     }
 #endif /* F_SETOWN */
-#ifdef O_NDELAY
   fcntl (fileno (tty_out->input), F_SETFL,
-         fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NDELAY);
+         fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NONBLOCK);
 #endif
-#endif /* F_SETFL */
 
   if (tty_out->old_tty)
     while (emacs_set_tty (fileno (tty_out->input),
@@ -1231,6 +1295,7 @@ reset_sys_modes (struct tty_display_info *tty_out)
   dos_ttcooked ();
 #endif
 
+  widen_foreground_group (fileno (tty_out->input));
 }
 \f
 #ifdef HAVE_PTYS
@@ -1543,12 +1608,20 @@ deliver_thread_signal (int sig, signal_handler_t handler)
   errno = old_errno;
 }
 \f
-#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
-static char *my_sys_siglist[NSIG];
-# ifdef sys_siglist
-#  undef sys_siglist
+#if !HAVE_DECL_SYS_SIGLIST
+# undef sys_siglist
+# ifdef _sys_siglist
+#  define sys_siglist _sys_siglist
+# else
+#  define sys_siglist my_sys_siglist
+static char const *sys_siglist[NSIG];
 # endif
-# define sys_siglist my_sys_siglist
+#endif
+
+#ifdef _sys_nsig
+# define sys_siglist_entries _sys_nsig
+#else
+# define sys_siglist_entries NSIG
 #endif
 
 /* Handle bus errors, invalid instruction, etc.  */
@@ -1611,7 +1684,7 @@ init_signals (bool dumping)
   main_thread = pthread_self ();
 #endif
 
-#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
+#if !HAVE_DECL_SYS_SIGLIST && !defined _sys_siglist
   if (! initialized)
     {
       sys_siglist[SIGABRT] = "Aborted";
@@ -1759,7 +1832,7 @@ init_signals (bool dumping)
       sys_siglist[SIGXFSZ] = "File size limit exceeded";
 # endif
     }
-#endif /* !defined HAVE_STRSIGNAL && !defined HAVE_DECL_SYS_SIGLIST */
+#endif /* !HAVE_DECL_SYS_SIGLIST && !_sys_siglist */
 
   /* Don't alter signal handlers if dumping.  On some machines,
      changing signal handlers sets static data that would make signals
@@ -2280,40 +2353,27 @@ set_file_times (int fd, const char *filename,
   return fdutimens (fd, filename, timespec);
 }
 \f
-#ifndef HAVE_STRSIGNAL
-char *
-strsignal (int code)
+/* Like strsignal, except async-signal-safe, and this function typically
+   returns a string in the C locale rather than the current locale.  */
+char const *
+safe_strsignal (int code)
 {
-  char *signame = 0;
+  char const *signame = 0;
 
-  if (0 <= code && code < NSIG)
-    {
-      /* Cast to suppress warning if the table has const char *.  */
-      signame = (char *) sys_siglist[code];
-    }
+  if (0 <= code && code < sys_siglist_entries)
+    signame = sys_siglist[code];
+  if (! signame)
+    signame = "Unknown signal";
 
   return signame;
 }
-#endif /* HAVE_STRSIGNAL */
 \f
 #ifndef DOS_NT
 /* For make-serial-process  */
 int
 serial_open (char *port)
 {
-  int fd = -1;
-
-  fd = emacs_open ((char*) port,
-                  O_RDWR
-#ifdef O_NONBLOCK
-                  | O_NONBLOCK
-#else
-                  | O_NDELAY
-#endif
-#ifdef O_NOCTTY
-                  | O_NOCTTY
-#endif
-                  , 0);
+  int fd = emacs_open (port, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
   if (fd < 0)
     {
       error ("Could not open %s: %s",
@@ -2532,8 +2592,7 @@ list_system_processes (void)
      process.  */
   procdir = build_string ("/proc");
   match = build_string ("[0-9]+");
-  proclist = directory_files_internal (procdir, Qnil, match, Qt, 0,
-                                      Qnil, Qnil);
+  proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil);
 
   /* `proclist' gives process IDs as strings.  Destructively convert
      each string into a number.  */