Assume POSIX 1003.1-1988 or later for signal.h.
[bpt/emacs.git] / src / sysdep.c
index dbfd9ef..5291c5d 100644 (file)
@@ -54,6 +54,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef WINDOWSNT
 #define read sys_read
 #define write sys_write
+#ifndef STDERR_FILENO
+#define STDERR_FILENO fileno(GetStdHandle(STD_ERROR_HANDLE))
+#endif
 #include <windows.h>
 #endif /* not WINDOWSNT */
 
@@ -98,7 +101,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define _P_WAIT 0
 int _cdecl _spawnlp (int, const char *, const char *, ...);
 int _cdecl _getpid (void);
-extern char *getwd (char *);
 #endif
 
 #include "syssignal.h"
@@ -131,12 +133,12 @@ char*
 get_current_dir_name (void)
 {
   char *buf;
-  char *pwd;
+  char *pwd = getenv ("PWD");
   struct stat dotstat, pwdstat;
-  /* If PWD is accurate, use it instead of calling getwd.  PWD is
+  /* If PWD is accurate, use it instead of calling getcwd.  PWD is
      sometimes a nicer name, and using it may avoid a fatal error if a
      parent directory is searchable but not readable.  */
-    if ((pwd = getenv ("PWD")) != 0
+  if (pwd
       && (IS_DIRECTORY_SEP (*pwd) || (*pwd && IS_DEVICE_SEP (pwd[1])))
       && stat (pwd, &pwdstat) == 0
       && stat (".", &dotstat) == 0
@@ -152,7 +154,6 @@ get_current_dir_name (void)
         return NULL;
       strcpy (buf, pwd);
     }
-#ifdef HAVE_GETCWD
   else
     {
       size_t buf_size = 1024;
@@ -176,22 +177,6 @@ get_current_dir_name (void)
             return NULL;
         }
     }
-#else
-  else
-    {
-      /* We need MAXPATHLEN here.  */
-      buf = malloc (MAXPATHLEN + 1);
-      if (!buf)
-        return NULL;
-      if (getwd (buf) == NULL)
-        {
-          int tmp_errno = errno;
-          free (buf);
-          errno = tmp_errno;
-          return NULL;
-        }
-    }
-#endif
   return buf;
 }
 #endif
@@ -279,78 +264,76 @@ init_baud_rate (int fd)
 
 \f
 
-/* Set nonzero to make following function work under dbx
-   (at least for bsd).  */
-int wait_debugging EXTERNALLY_VISIBLE;
-
 #ifndef MSDOS
 
-static void
-wait_for_termination_1 (pid_t pid, int interruptible)
+/* Wait for the subprocess with process id CHILD to terminate or change status.
+   CHILD must be a child process that has not been reaped.
+   If STATUS is non-null, store the waitpid-style exit status into *STATUS
+   and tell wait_reading_process_output that it needs to look around.
+   Use waitpid-style OPTIONS when waiting.
+   If INTERRUPTIBLE, this function is interruptible by a signal.
+
+   Return CHILD if successful, 0 if no status is available;
+   the latter is possible only when options & NOHANG.  */
+static pid_t
+get_child_status (pid_t child, int *status, int options, bool interruptible)
 {
-  while (1)
-    {
-#if (defined (BSD_SYSTEM) || defined (HPUX)) && !defined (__GNU__)
-      /* Note that kill returns -1 even if the process is just a zombie now.
-        But inevitably a SIGCHLD interrupt should be generated
-        and child_sig will do waitpid and make the process go away.  */
-      /* There is some indication that there is a bug involved with
-        termination of subprocesses, perhaps involving a kernel bug too,
-        but no idea what it is.  Just as a hunch we signal SIGCHLD to see
-        if that causes the problem to go away or get worse.  */
-      sigset_t sigchild_mask;
-      sigemptyset (&sigchild_mask);
-      sigaddset (&sigchild_mask, SIGCHLD);
-      pthread_sigmask (SIG_SETMASK, &sigchild_mask, 0);
-
-      if (0 > kill (pid, 0))
-       {
-         pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
-         kill (getpid (), SIGCHLD);
-         break;
-       }
-      if (wait_debugging)
-       sleep (1);
-      else
-       sigsuspend (&empty_mask);
-#else /* not BSD_SYSTEM, and not HPUX version >= 6 */
-#ifdef WINDOWSNT
-      wait (0);
-      break;
-#else /* not WINDOWSNT */
-      sigset_t blocked;
-      sigemptyset (&blocked);
-      sigaddset (&blocked, SIGCHLD);
-      pthread_sigmask (SIG_BLOCK, &blocked, 0);
-      errno = 0;
-      if (kill (pid, 0) == -1 && errno == ESRCH)
-       {
-         pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
-         break;
-       }
+  pid_t pid;
 
-      sigsuspend (&empty_mask);
-#endif /* not WINDOWSNT */
-#endif /* not BSD_SYSTEM, and not HPUX version >= 6 */
+  /* Invoke waitpid only with a known process ID; do not invoke
+     waitpid with a nonpositive argument.  Otherwise, Emacs might
+     reap an unwanted process by mistake.  For example, invoking
+     waitpid (-1, ...) can mess up glib by reaping glib's subprocesses,
+     so that another thread running glib won't find them.  */
+  eassert (0 < child);
+
+  while ((pid = waitpid (child, status, options)) < 0)
+    {
+      /* Check that CHILD is a child process that has not been reaped,
+        and that STATUS and OPTIONS are valid.  Otherwise abort,
+        as continuing after this internal error could cause Emacs to
+        become confused and kill innocent-victim processes.  */
+      if (errno != EINTR)
+       emacs_abort ();
+
+      /* Note: the MS-Windows emulation of waitpid calls QUIT
+        internally.  */
       if (interruptible)
        QUIT;
     }
-}
 
-/* Wait for subprocess with process id `pid' to terminate and
-   make sure it will get eliminated (not remain forever as a zombie) */
+  /* If successful and status is requested, tell wait_reading_process_output
+     that it needs to wake up and look around.  */
+  if (pid && status && input_available_clear_time)
+    *input_available_clear_time = make_emacs_time (0, 0);
 
+  return pid;
+}
+
+/* Wait for the subprocess with process id CHILD to terminate.
+   CHILD must be a child process that has not been reaped.
+   If STATUS is non-null, store the waitpid-style exit status into *STATUS
+   and tell wait_reading_process_output that it needs to look around.
+   If INTERRUPTIBLE, this function is interruptible by a signal.  */
 void
-wait_for_termination (pid_t pid)
+wait_for_termination (pid_t child, int *status, bool interruptible)
 {
-  wait_for_termination_1 (pid, 0);
+  get_child_status (child, status, 0, interruptible);
 }
 
-/* Like the above, but allow keyboard interruption. */
-void
-interruptible_wait_for_termination (pid_t pid)
+/* Report whether the subprocess with process id CHILD has changed status.
+   Termination counts as a change of status.
+   CHILD must be a child process that has not been reaped.
+   If STATUS is non-null, store the waitpid-style exit status into *STATUS
+   and tell wait_reading_process_output that it needs to look around.
+   Use waitpid-style OPTIONS to check status, but do not wait.
+
+   Return CHILD if successful, 0 if no status is available because
+   the process's state has not changed.  */
+pid_t
+child_status_changed (pid_t child, int *status, int options)
 {
-  wait_for_termination_1 (pid, 1);
+  return get_child_status (child, status, WNOHANG | options, 0);
 }
 
 /*
@@ -474,20 +457,15 @@ static void restore_signal_handlers (struct save_signal *);
 void
 sys_suspend (void)
 {
-#if defined (SIGTSTP) && !defined (MSDOS)
-
-  {
-    int pgrp = EMACS_GETPGRP (0);
-    EMACS_KILLPG (pgrp, SIGTSTP);
-  }
-
-#else /* No SIGTSTP */
+#ifndef DOS_NT
+  kill (0, SIGTSTP);
+#else
 /* On a system where suspending is not implemented,
    instead fork a subshell and let it talk directly to the terminal
    while we wait.  */
   sys_subshell ();
 
-#endif /* no SIGTSTP */
+#endif
 }
 
 /* Fork a subshell.  */
@@ -499,7 +477,8 @@ sys_subshell (void)
   int st;
   char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS.  */
 #endif
-  int pid;
+  pid_t pid;
+  int status;
   struct save_signal saved_handlers[5];
   Lisp_Object dir;
   unsigned char *volatile str_volatile = 0;
@@ -537,7 +516,6 @@ sys_subshell (void)
 #ifdef DOS_NT
   pid = 0;
   save_signal_handlers (saved_handlers);
-  synch_process_alive = 1;
 #else
   pid = vfork ();
   if (pid == -1)
@@ -549,7 +527,7 @@ sys_subshell (void)
       const char *sh = 0;
 
 #ifdef DOS_NT    /* MW, Aug 1993 */
-      getwd (oldwd);
+      getcwd (oldwd, sizeof oldwd);
       if (sh == 0)
        sh = (char *) egetenv ("SUSPEND");      /* KFS, 1994-12-14 */
 #endif
@@ -606,14 +584,12 @@ sys_subshell (void)
   /* Do this now if we did not do it before.  */
 #ifndef MSDOS
   save_signal_handlers (saved_handlers);
-  synch_process_alive = 1;
 #endif
 
 #ifndef DOS_NT
-  wait_for_termination (pid);
+  wait_for_termination (pid, &status, 0);
 #endif
   restore_signal_handlers (saved_handlers);
-  synch_process_alive = 0;
 }
 
 static void
@@ -708,6 +684,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.
@@ -824,6 +869,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);
 
@@ -993,8 +1040,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)] =
@@ -1012,7 +1058,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.
@@ -1232,8 +1277,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));
@@ -1241,11 +1286,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),
@@ -1256,6 +1299,7 @@ reset_sys_modes (struct tty_display_info *tty_out)
   dos_ttcooked ();
 #endif
 
+  widen_foreground_group (fileno (tty_out->input));
 }
 \f
 #ifdef HAVE_PTYS
@@ -1438,40 +1482,78 @@ init_system_name (void)
 \f
 sigset_t empty_mask;
 
-/* Store into *ACTION a signal action suitable for Emacs, with handler
-   HANDLER.  */
-void
-emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
+static struct sigaction process_fatal_action;
+
+static int
+emacs_sigaction_flags (void)
 {
-  sigemptyset (&action->sa_mask);
-  action->sa_handler = handler;
-  action->sa_flags = 0;
-#if defined (SA_RESTART)
+#ifdef SA_RESTART
   /* SA_RESTART causes interruptible functions with timeouts (e.g.,
      'select') to reset their timeout on some platforms (e.g.,
      HP-UX 11), which is not what we want.  Also, when Emacs is
      interactive, we don't want SA_RESTART because we need to poll
      for pending input so we need long-running syscalls to be interrupted
-     after a signal that sets the interrupt_input_pending flag.  */
-  /* Non-interactive keyboard input goes through stdio, where we always
-     want restartable system calls.  */
+     after a signal that sets pending_signals.
+
+     Non-interactive keyboard input goes through stdio, where we
+     always want restartable system calls.  */
   if (noninteractive)
-    action->sa_flags = SA_RESTART;
+    return SA_RESTART;
+#endif
+  return 0;
+}
+
+/* Store into *ACTION a signal action suitable for Emacs, with handler
+   HANDLER.  */
+void
+emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
+{
+  sigemptyset (&action->sa_mask);
+
+  /* When handling a signal, block nonfatal system signals that are caught
+     by Emacs.  This makes race conditions less likely.  */
+  sigaddset (&action->sa_mask, SIGALRM);
+  sigaddset (&action->sa_mask, SIGCHLD);
+#ifdef SIGDANGER
+  sigaddset (&action->sa_mask, SIGDANGER);
+#endif
+#ifdef PROFILER_CPU_SUPPORT
+  sigaddset (&action->sa_mask, SIGPROF);
 #endif
+#ifdef SIGWINCH
+  sigaddset (&action->sa_mask, SIGWINCH);
+#endif
+  if (! noninteractive)
+    {
+      sigaddset (&action->sa_mask, SIGINT);
+      sigaddset (&action->sa_mask, SIGQUIT);
+#ifdef USABLE_SIGIO
+      sigaddset (&action->sa_mask, SIGIO);
+#endif
+    }
+
+  if (! IEEE_FLOATING_POINT)
+    sigaddset (&action->sa_mask, SIGFPE);
+
+  action->sa_handler = handler;
+  action->sa_flags = emacs_sigaction_flags ();
 }
 
 #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
 static pthread_t main_thread;
 #endif
 
-/* If we are on the main thread, handle the signal SIG with HANDLER.
+/* SIG has arrived at the current process.  Deliver it to the main
+   thread, which should handle it with HANDLER.
+
+   If we are on the main thread, handle the signal SIG with HANDLER.
    Otherwise, redirect the signal to the main thread, blocking it from
    this thread.  POSIX says any thread can receive a signal that is
    associated with a process, process group, or asynchronous event.
    On GNU/Linux that is not true, but for other systems (FreeBSD at
    least) it is.  */
 void
-handle_on_main_thread (int sig, signal_handler_t handler)
+deliver_process_signal (int sig, signal_handler_t handler)
 {
   /* Preserve errno, to avoid race conditions with signal handlers that
      might change errno.  Races can occur even in single-threaded hosts.  */
@@ -1494,45 +1576,128 @@ handle_on_main_thread (int sig, signal_handler_t handler)
 
   errno = old_errno;
 }
+
+/* Static location to save a fatal backtrace in a thread.
+   FIXME: If two subsidiary threads fail simultaneously, the resulting
+   backtrace may be garbage.  */
+enum { BACKTRACE_LIMIT_MAX = 500 };
+static void *thread_backtrace_buffer[BACKTRACE_LIMIT_MAX + 1];
+static int thread_backtrace_npointers;
+
+/* SIG has arrived at the current thread.
+   If we are on the main thread, handle the signal SIG with HANDLER.
+   Otherwise, this is a fatal error in the handling thread.  */
+static void
+deliver_thread_signal (int sig, signal_handler_t handler)
+{
+  int old_errno = errno;
+
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+  if (! pthread_equal (pthread_self (), main_thread))
+    {
+      thread_backtrace_npointers
+       = backtrace (thread_backtrace_buffer, BACKTRACE_LIMIT_MAX);
+      sigaction (sig, &process_fatal_action, 0);
+      pthread_kill (main_thread, sig);
+
+      /* Avoid further damage while the main thread is exiting.  */
+      while (1)
+       sigsuspend (&empty_mask);
+    }
+#endif
+
+  handler (sig);
+  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.  */
+static void
+handle_fatal_signal (int sig)
+{
+  terminate_due_to_signal (sig, 40);
+}
+
+static void
+deliver_fatal_signal (int sig)
+{
+  deliver_process_signal (sig, handle_fatal_signal);
+}
+
+static void
+deliver_fatal_thread_signal (int sig)
+{
+  deliver_thread_signal (sig, handle_fatal_signal);
+}
+
+static _Noreturn void
+handle_arith_signal (int sig)
+{
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+  xsignal0 (Qarith_error);
+}
+
+static void
+deliver_arith_signal (int sig)
+{
+  deliver_thread_signal (sig, handle_arith_signal);
+}
+
+/* Treat SIG as a terminating signal, unless it is already ignored and
+   we are in --batch mode.  Among other things, this makes nohup work.  */
+static void
+maybe_fatal_sig (int sig)
+{
+  bool catch_sig = !noninteractive;
+  if (!catch_sig)
+    {
+      struct sigaction old_action;
+      sigaction (sig, 0, &old_action);
+      catch_sig = old_action.sa_handler != SIG_IGN;
+    }
+  if (catch_sig)
+    sigaction (sig, &process_fatal_action, 0);
+}
+
 void
-init_signals (void)
+init_signals (bool dumping)
 {
+  struct sigaction thread_fatal_action;
+  struct sigaction action;
+
   sigemptyset (&empty_mask);
 
 #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
   main_thread = pthread_self ();
 #endif
 
-#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
+#if !HAVE_DECL_SYS_SIGLIST && !defined _sys_siglist
   if (! initialized)
     {
-# ifdef SIGABRT
       sys_siglist[SIGABRT] = "Aborted";
-# endif
 # ifdef SIGAIO
       sys_siglist[SIGAIO] = "LAN I/O interrupt";
 # endif
-# ifdef SIGALRM
       sys_siglist[SIGALRM] = "Alarm clock";
-# endif
 # ifdef SIGBUS
       sys_siglist[SIGBUS] = "Bus error";
 # endif
-# ifdef SIGCLD
-      sys_siglist[SIGCLD] = "Child status changed";
-# endif
-# ifdef SIGCHLD
       sys_siglist[SIGCHLD] = "Child status changed";
-# endif
 # ifdef SIGCONT
       sys_siglist[SIGCONT] = "Continued";
 # endif
@@ -1545,24 +1710,16 @@ init_signals (void)
 # ifdef SIGEMT
       sys_siglist[SIGEMT] = "Emulation trap";
 # endif
-# ifdef SIGFPE
       sys_siglist[SIGFPE] = "Arithmetic exception";
-# endif
 # ifdef SIGFREEZE
       sys_siglist[SIGFREEZE] = "SIGFREEZE";
 # endif
 # ifdef SIGGRANT
       sys_siglist[SIGGRANT] = "Monitor mode granted";
 # endif
-# ifdef SIGHUP
       sys_siglist[SIGHUP] = "Hangup";
-# endif
-# ifdef SIGILL
       sys_siglist[SIGILL] = "Illegal instruction";
-# endif
-# ifdef SIGINT
       sys_siglist[SIGINT] = "Interrupt";
-# endif
 # ifdef SIGIO
       sys_siglist[SIGIO] = "I/O possible";
 # endif
@@ -1572,9 +1729,7 @@ init_signals (void)
 # ifdef SIGIOT
       sys_siglist[SIGIOT] = "IOT trap";
 # endif
-# ifdef SIGKILL
       sys_siglist[SIGKILL] = "Killed";
-# endif
 # ifdef SIGLOST
       sys_siglist[SIGLOST] = "Resource lost";
 # endif
@@ -1587,9 +1742,7 @@ init_signals (void)
 # ifdef SIGPHONE
       sys_siglist[SIGWIND] = "SIGPHONE";
 # endif
-# ifdef SIGPIPE
       sys_siglist[SIGPIPE] = "Broken pipe";
-# endif
 # ifdef SIGPOLL
       sys_siglist[SIGPOLL] = "Pollable event occurred";
 # endif
@@ -1602,18 +1755,14 @@ init_signals (void)
 # ifdef SIGPWR
       sys_siglist[SIGPWR] = "Power-fail restart";
 # endif
-# ifdef SIGQUIT
       sys_siglist[SIGQUIT] = "Quit";
-# endif
 # ifdef SIGRETRACT
       sys_siglist[SIGRETRACT] = "Need to relinquish monitor mode";
 # endif
 # ifdef SIGSAK
       sys_siglist[SIGSAK] = "Secure attention";
 # endif
-# ifdef SIGSEGV
       sys_siglist[SIGSEGV] = "Segmentation violation";
-# endif
 # ifdef SIGSOUND
       sys_siglist[SIGSOUND] = "Sound completed";
 # endif
@@ -1626,9 +1775,7 @@ init_signals (void)
 # ifdef SIGSYS
       sys_siglist[SIGSYS] = "Bad argument to system call";
 # endif
-# ifdef SIGTERM
       sys_siglist[SIGTERM] = "Terminated";
-# endif
 # ifdef SIGTHAW
       sys_siglist[SIGTHAW] = "SIGTHAW";
 # endif
@@ -1672,7 +1819,130 @@ init_signals (void)
       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
+     fail to work right when the dumped Emacs is run.  */
+  if (dumping)
+    return;
+
+  sigfillset (&process_fatal_action.sa_mask);
+  process_fatal_action.sa_handler = deliver_fatal_signal;
+  process_fatal_action.sa_flags = emacs_sigaction_flags ();
+
+  sigfillset (&thread_fatal_action.sa_mask);
+  thread_fatal_action.sa_handler = deliver_fatal_thread_signal;
+  thread_fatal_action.sa_flags = process_fatal_action.sa_flags;
+
+  /* SIGINT may need special treatment on MS-Windows.  See
+     http://lists.gnu.org/archive/html/emacs-devel/2010-09/msg01062.html
+     Please update the doc of kill-emacs, kill-emacs-hook, and
+     NEWS if you change this.  */
+
+  maybe_fatal_sig (SIGHUP);
+  maybe_fatal_sig (SIGINT);
+  maybe_fatal_sig (SIGTERM);
+
+  /* Emacs checks for write errors, so it can safely ignore SIGPIPE.
+     However, in batch mode leave SIGPIPE alone, as that causes Emacs
+     to behave more like typical batch applications do.  */
+  if (! noninteractive)
+    signal (SIGPIPE, SIG_IGN);
+
+  sigaction (SIGQUIT, &process_fatal_action, 0);
+  sigaction (SIGILL, &thread_fatal_action, 0);
+  sigaction (SIGTRAP, &thread_fatal_action, 0);
+
+  /* Typically SIGFPE is thread-specific and is fatal, like SIGILL.
+     But on a non-IEEE host SIGFPE can come from a trap in the Lisp
+     interpreter's floating point operations, so treat SIGFPE as an
+     arith-error if it arises in the main thread.  */
+  if (IEEE_FLOATING_POINT)
+    sigaction (SIGFPE, &thread_fatal_action, 0);
+  else
+    {
+      emacs_sigaction_init (&action, deliver_arith_signal);
+      sigaction (SIGFPE, &action, 0);
+    }
+
+#ifdef SIGUSR1
+  add_user_signal (SIGUSR1, "sigusr1");
+#endif
+#ifdef SIGUSR2
+  add_user_signal (SIGUSR2, "sigusr2");
+#endif
+  sigaction (SIGABRT, &thread_fatal_action, 0);
+#ifdef SIGPRE
+  sigaction (SIGPRE, &thread_fatal_action, 0);
+#endif
+#ifdef SIGORE
+  sigaction (SIGORE, &thread_fatal_action, 0);
+#endif
+#ifdef SIGUME
+  sigaction (SIGUME, &thread_fatal_action, 0);
+#endif
+#ifdef SIGDLK
+  sigaction (SIGDLK, &process_fatal_action, 0);
+#endif
+#ifdef SIGCPULIM
+  sigaction (SIGCPULIM, &process_fatal_action, 0);
+#endif
+#ifdef SIGIOT
+  sigaction (SIGIOT, &thread_fatal_action, 0);
+#endif
+#ifdef SIGEMT
+  sigaction (SIGEMT, &thread_fatal_action, 0);
+#endif
+#ifdef SIGBUS
+  sigaction (SIGBUS, &thread_fatal_action, 0);
+#endif
+  sigaction (SIGSEGV, &thread_fatal_action, 0);
+#ifdef SIGSYS
+  sigaction (SIGSYS, &thread_fatal_action, 0);
+#endif
+  sigaction (SIGTERM, &process_fatal_action, 0);
+#ifdef SIGPROF
+  signal (SIGPROF, SIG_IGN);
+#endif
+#ifdef SIGVTALRM
+  sigaction (SIGVTALRM, &process_fatal_action, 0);
+#endif
+#ifdef SIGXCPU
+  sigaction (SIGXCPU, &process_fatal_action, 0);
+#endif
+#ifdef SIGXFSZ
+  sigaction (SIGXFSZ, &process_fatal_action, 0);
+#endif
+
+#ifdef SIGDANGER
+  /* This just means available memory is getting low.  */
+  emacs_sigaction_init (&action, deliver_danger_signal);
+  sigaction (SIGDANGER, &action, 0);
+#endif
+
+  /* AIX-specific signals.  */
+#ifdef SIGGRANT
+  sigaction (SIGGRANT, &process_fatal_action, 0);
+#endif
+#ifdef SIGMIGRATE
+  sigaction (SIGMIGRATE, &process_fatal_action, 0);
+#endif
+#ifdef SIGMSG
+  sigaction (SIGMSG, &process_fatal_action, 0);
+#endif
+#ifdef SIGRETRACT
+  sigaction (SIGRETRACT, &process_fatal_action, 0);
+#endif
+#ifdef SIGSAK
+  sigaction (SIGSAK, &process_fatal_action, 0);
+#endif
+#ifdef SIGSOUND
+  sigaction (SIGSOUND, &process_fatal_action, 0);
+#endif
+#ifdef SIGTALRM
+  sigaction (SIGTALRM, &thread_fatal_action, 0);
+#endif
 }
 \f
 #ifndef HAVE_RANDOM
@@ -1811,23 +2081,36 @@ snprintf (char *buf, size_t bufsize, char const *format, ...)
 void
 emacs_backtrace (int backtrace_limit)
 {
-  enum { BACKTRACE_LIMIT_MAX = 500 };
-  void *buffer[BACKTRACE_LIMIT_MAX + 1];
+  void *main_backtrace_buffer[BACKTRACE_LIMIT_MAX + 1];
   int bounded_limit = min (backtrace_limit, BACKTRACE_LIMIT_MAX);
-  int npointers = backtrace (buffer, bounded_limit + 1);
+  void *buffer;
+  int npointers;
+
+  if (thread_backtrace_npointers)
+    {
+      buffer = thread_backtrace_buffer;
+      npointers = thread_backtrace_npointers;
+    }
+  else
+    {
+      buffer = main_backtrace_buffer;
+      npointers = backtrace (buffer, bounded_limit + 1);
+    }
+
   if (npointers)
-    ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12));
-  backtrace_symbols_fd (buffer, bounded_limit, STDERR_FILENO);
-  if (bounded_limit < npointers)
-    ignore_value (write (STDERR_FILENO, "...\n", 4));
+    {
+      ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12));
+      backtrace_symbols_fd (buffer, npointers, STDERR_FILENO);
+      if (bounded_limit < npointers)
+       ignore_value (write (STDERR_FILENO, "...\n", 4));
+    }
 }
 \f
 #ifndef HAVE_NTGUI
-/* Using emacs_abort lets GDB return from a breakpoint here.  */
 void
 emacs_abort (void)
 {
-  fatal_error_backtrace (SIGABRT, 10);
+  terminate_due_to_signal (SIGABRT, 10);
 }
 #endif
 
@@ -1910,7 +2193,8 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte)
            {
              /* I originally used `QUIT' but that might causes files to
                 be truncated if you hit C-g in the middle of it.  --Stef  */
-             process_pending_signals ();
+             if (pending_signals)
+               process_pending_signals ();
              continue;
            }
          else
@@ -1941,82 +2225,6 @@ emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE])
                       &emacs_norealloc_allocator, careadlinkatcwd);
 }
 \f
-#ifdef USG
-/*
- *     All of the following are for USG.
- *
- *     On USG systems the system calls are INTERRUPTIBLE by signals
- *     that the user program has elected to catch.  Thus the system call
- *     must be retried in these cases.  To handle this without massive
- *     changes in the source code, we remap the standard system call names
- *     to names for our own functions in sysdep.c that do the system call
- *     with retries.  Actually, for portability reasons, it is good
- *     programming practice, as this example shows, to limit all actual
- *     system calls to a single occurrence in the source.  Sure, this
- *     adds an extra level of function call overhead but it is almost
- *     always negligible.   Fred Fish, Unisoft Systems Inc.
- */
-
-/*
- *     Warning, this function may not duplicate 4.2 action properly
- *     under error conditions.
- */
-
-#if !defined (HAVE_GETWD) || defined (BROKEN_GETWD)
-
-#ifndef MAXPATHLEN
-/* In 4.1, param.h fails to define this.  */
-#define MAXPATHLEN 1024
-#endif
-
-char *
-getwd (char *pathname)
-{
-  char *npath, *spath;
-  extern char *getcwd (char *, size_t);
-
-  BLOCK_INPUT;                 /* getcwd uses malloc */
-  spath = npath = getcwd ((char *) 0, MAXPATHLEN);
-  if (spath == 0)
-    {
-      UNBLOCK_INPUT;
-      return spath;
-    }
-  /* On Altos 3068, getcwd can return @hostname/dir, so discard
-     up to first slash.  Should be harmless on other systems.  */
-  while (*npath && *npath != '/')
-    npath++;
-  strcpy (pathname, npath);
-  free (spath);                        /* getcwd uses malloc */
-  UNBLOCK_INPUT;
-  return pathname;
-}
-
-#endif /* !defined (HAVE_GETWD) || defined (BROKEN_GETWD) */
-#endif /* USG */
-\f
-/* Directory routines for systems that don't have them. */
-
-#ifdef HAVE_DIRENT_H
-
-#include <dirent.h>
-
-#if !defined (HAVE_CLOSEDIR)
-
-int
-closedir (DIR *dirp /* stream from opendir */)
-{
-  int rtnval;
-
-  rtnval = emacs_close (dirp->dd_fd);
-  xfree (dirp);
-
-  return rtnval;
-}
-#endif /* not HAVE_CLOSEDIR */
-#endif /* HAVE_DIRENT_H */
-
-\f
 /* Return a struct timeval that is roughly equivalent to T.
    Use the least timeval not less than T.
    Return an extremal value if the result would overflow.  */
@@ -2056,40 +2264,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",
@@ -2422,7 +2617,7 @@ get_up_time (void)
   FILE *fup;
   EMACS_TIME up = make_emacs_time (0, 0);
 
-  BLOCK_INPUT;
+  block_input ();
   fup = fopen ("/proc/uptime", "r");
 
   if (fup)
@@ -2453,7 +2648,7 @@ get_up_time (void)
        }
       fclose (fup);
     }
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   return up;
 }
@@ -2467,7 +2662,7 @@ procfs_ttyname (int rdev)
   FILE *fdev = NULL;
   char name[PATH_MAX];
 
-  BLOCK_INPUT;
+  block_input ();
   fdev = fopen ("/proc/tty/drivers", "r");
 
   if (fdev)
@@ -2499,7 +2694,7 @@ procfs_ttyname (int rdev)
        }
       fclose (fdev);
     }
-  UNBLOCK_INPUT;
+  unblock_input ();
   return build_string (name);
 }
 
@@ -2509,7 +2704,7 @@ procfs_get_total_memory (void)
   FILE *fmem = NULL;
   unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
 
-  BLOCK_INPUT;
+  block_input ();
   fmem = fopen ("/proc/meminfo", "r");
 
   if (fmem)
@@ -2528,7 +2723,7 @@ procfs_get_total_memory (void)
        }
       fclose (fmem);
     }
-  UNBLOCK_INPUT;
+  unblock_input ();
   return retval;
 }
 
@@ -2574,17 +2769,17 @@ system_process_attributes (Lisp_Object pid)
   /* euid egid */
   uid = st.st_uid;
   attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs);
-  BLOCK_INPUT;
+  block_input ();
   pw = getpwuid (uid);
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (pw)
     attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
 
   gid = st.st_gid;
   attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid)), attrs);
-  BLOCK_INPUT;
+  block_input ();
   gr = getgrgid (gid);
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (gr)
     attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
 
@@ -2812,17 +3007,17 @@ system_process_attributes (Lisp_Object pid)
   /* euid egid */
   uid = st.st_uid;
   attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs);
-  BLOCK_INPUT;
+  block_input ();
   pw = getpwuid (uid);
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (pw)
     attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
 
   gid = st.st_gid;
   attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid)), attrs);
-  BLOCK_INPUT;
+  block_input ();
   gr = getgrgid (gid);
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (gr)
     attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
 
@@ -2943,17 +3138,17 @@ system_process_attributes (Lisp_Object pid)
 
   attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (proc.ki_uid)), attrs);
 
-  BLOCK_INPUT;
+  block_input ();
   pw = getpwuid (proc.ki_uid);
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (pw)
     attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
 
   attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (proc.ki_svgid)), attrs);
 
-  BLOCK_INPUT;
+  block_input ();
   gr = getgrgid (proc.ki_svgid);
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (gr)
     attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
 
@@ -2993,9 +3188,9 @@ system_process_attributes (Lisp_Object pid)
   attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (proc.ki_pgid)), attrs);
   attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (proc.ki_sid)),  attrs);
 
-  BLOCK_INPUT;
+  block_input ();
   ttyname = proc.ki_tdev == NODEV ? NULL : devname (proc.ki_tdev, S_IFCHR);
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (ttyname)
     attrs = Fcons (Fcons (Qtty, build_string (ttyname)), attrs);