emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] /srv/bzr/emacs/trunk r109893: Fix race conditions with sig


From: Paul Eggert
Subject: [Emacs-diffs] /srv/bzr/emacs/trunk r109893: Fix race conditions with signal handlers and errno.
Date: Wed, 05 Sep 2012 14:33:53 -0700
User-agent: Bazaar (2.5.0)

------------------------------------------------------------
revno: 109893
committer: Paul Eggert <address@hidden>
branch nick: trunk
timestamp: Wed 2012-09-05 14:33:53 -0700
message:
  Fix race conditions with signal handlers and errno.
  
  Be more systematic about preserving errno whenever a signal
  handler returns, even if it's not in the main thread.  Do this by
  renaming signal handlers to distinguish between signal delivery
  and signal handling.  All uses changed.
  * atimer.c (deliver_alarm_signal): Rename from alarm_signal_handler.
  * data.c (deliver_arith_signal): Rename from arith_error.
  * dispnew.c (deliver_window_change_signal): Rename from
  window_change_signal.
  * emacs.c (deliver_error_signal): Rename from fatal_error_signal.
  (deliver_danger_signal) [SIGDANGER]: Rename from memory_warning_signal.
  * keyboard.c (deliver_input_available_signal): Rename from
  input_available_signal.
  (deliver_user_signal): Rename from handle_user_signal.
  (deliver_interrupt_signal): Rename from interrupt_signal.
  * process.c (deliver_pipe_signal): Rename from send_process_trap.
  (deliver_child_signal): Rename from sigchld_handler.
  * atimer.c (handle_alarm_signal):
  * data.c (handle_arith_signal):
  * dispnew.c (handle_window_change_signal):
  * emacs.c (handle_fatal_signal, handle_danger_signal):
  * keyboard.c (handle_input_available_signal):
  * keyboard.c (handle_user_signal, handle_interrupt_signal):
  * process.c (handle_pipe_signal, handle_child_signal):
  New functions, with the actual signal-handling code taken from the
  original respective signal handlers, sans the sporadic attempts to
  preserve errno, since that's now done by handle_on_main_thread.
  * atimer.c (alarm_signal_handler): Remove unnecessary decl.
  * emacs.c, floatfns.c, lisp.h: Remove unused FLOAT_CATCH_SIGKILL cruft.
  * emacs.c (main_thread) [FORWARD_SIGNAL_TO_MAIN_THREAD]:
  Move to sysdep.c.
  (main) [FORWARD_SIGNAL_TO_MAIN_THREAD]:
  Move initialization of main_thread to sysdep.c's init_signals.
  * process.c (waitpid) [!WNOHANG]: #define to wait; that's good enough for
  our usage, and simplifies the mainline code.
  (record_child_status_change): New static function, as a helper
  for handle_child_signal, and with most of the old child handler's
  contents.
  (CAN_HANDLE_MULTIPLE_CHILDREN): New constant.
  (handle_child_signal): Use the above.
  * sysdep.c (main_thread) [FORWARD_SIGNAL_TO_MAIN_THREAD]:
  Moved here from emacs.c.
  (init_signals) [FORWARD_SIGNAL_TO_MAIN_THREAD]: Initialize it;
  code moved here from emacs.c's main function.
  * sysdep.c, syssignal.h (handle_on_main_thread): New function,
  replacing the old SIGNAL_THREAD_CHECK.  All uses changed.  This
  lets callers save and restore errno properly.
modified:
  src/ChangeLog
  src/atimer.c
  src/data.c
  src/dispnew.c
  src/emacs.c
  src/floatfns.c
  src/keyboard.c
  src/lisp.h
  src/process.c
  src/sysdep.c
  src/syssignal.h
=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2012-09-05 17:05:32 +0000
+++ b/src/ChangeLog     2012-09-05 21:33:53 +0000
@@ -1,3 +1,53 @@
+2012-09-05  Paul Eggert  <address@hidden>
+
+       Fix race conditions with signal handlers and errno.
+       Be more systematic about preserving errno whenever a signal
+       handler returns, even if it's not in the main thread.  Do this by
+       renaming signal handlers to distinguish between signal delivery
+       and signal handling.  All uses changed.
+       * atimer.c (deliver_alarm_signal): Rename from alarm_signal_handler.
+       * data.c (deliver_arith_signal): Rename from arith_error.
+       * dispnew.c (deliver_window_change_signal): Rename from
+       window_change_signal.
+       * emacs.c (deliver_error_signal): Rename from fatal_error_signal.
+       (deliver_danger_signal) [SIGDANGER]: Rename from memory_warning_signal.
+       * keyboard.c (deliver_input_available_signal): Rename from
+       input_available_signal.
+       (deliver_user_signal): Rename from handle_user_signal.
+       (deliver_interrupt_signal): Rename from interrupt_signal.
+       * process.c (deliver_pipe_signal): Rename from send_process_trap.
+       (deliver_child_signal): Rename from sigchld_handler.
+       * atimer.c (handle_alarm_signal):
+       * data.c (handle_arith_signal):
+       * dispnew.c (handle_window_change_signal):
+       * emacs.c (handle_fatal_signal, handle_danger_signal):
+       * keyboard.c (handle_input_available_signal):
+       * keyboard.c (handle_user_signal, handle_interrupt_signal):
+       * process.c (handle_pipe_signal, handle_child_signal):
+       New functions, with the actual signal-handling code taken from the
+       original respective signal handlers, sans the sporadic attempts to
+       preserve errno, since that's now done by handle_on_main_thread.
+       * atimer.c (alarm_signal_handler): Remove unnecessary decl.
+       * emacs.c, floatfns.c, lisp.h: Remove unused FLOAT_CATCH_SIGKILL cruft.
+       * emacs.c (main_thread) [FORWARD_SIGNAL_TO_MAIN_THREAD]:
+       Move to sysdep.c.
+       (main) [FORWARD_SIGNAL_TO_MAIN_THREAD]:
+       Move initialization of main_thread to sysdep.c's init_signals.
+       * process.c (waitpid) [!WNOHANG]: #define to wait; that's good enough 
for
+       our usage, and simplifies the mainline code.
+       (record_child_status_change): New static function, as a helper
+       for handle_child_signal, and with most of the old child handler's
+       contents.
+       (CAN_HANDLE_MULTIPLE_CHILDREN): New constant.
+       (handle_child_signal): Use the above.
+       * sysdep.c (main_thread) [FORWARD_SIGNAL_TO_MAIN_THREAD]:
+       Moved here from emacs.c.
+       (init_signals) [FORWARD_SIGNAL_TO_MAIN_THREAD]: Initialize it;
+       code moved here from emacs.c's main function.
+       * sysdep.c, syssignal.h (handle_on_main_thread): New function,
+       replacing the old SIGNAL_THREAD_CHECK.  All uses changed.  This
+       lets callers save and restore errno properly.
+
 2012-09-05  Dmitry Antipov  <address@hidden>
 
        Remove redundant or unused things here and there.

=== modified file 'src/atimer.c'
--- a/src/atimer.c      2012-08-23 08:27:08 +0000
+++ b/src/atimer.c      2012-09-05 21:33:53 +0000
@@ -41,7 +41,7 @@
 
 static struct atimer *atimers;
 
-/* Non-zero means alarm_signal_handler has found ripe timers but
+/* Non-zero means alarm signal handler has found ripe timers but
    interrupt_input_blocked was non-zero.  In this case, timer
    functions are not called until the next UNBLOCK_INPUT because timer
    functions are expected to call X, and X cannot be assumed to be
@@ -60,8 +60,6 @@
 static void schedule_atimer (struct atimer *);
 static struct atimer *append_atimer_lists (struct atimer *,
                                            struct atimer *);
-static void alarm_signal_handler (int signo);
-
 
 /* Start a new atimer of type TYPE.  TIME specifies when the timer is
    ripe.  FN is the function to call when the timer fires.
@@ -374,13 +372,9 @@
 /* Signal handler for SIGALRM.  SIGNO is the signal number, i.e.
    SIGALRM.  */
 
-void
-alarm_signal_handler (int signo)
+static void
+handle_alarm_signal (int sig)
 {
-#ifndef SYNC_INPUT
-  SIGNAL_THREAD_CHECK (signo);
-#endif
-
   pending_atimers = 1;
 #ifdef SYNC_INPUT
   pending_signals = 1;
@@ -389,8 +383,14 @@
 #endif
 }
 
-
-/* Call alarm_signal_handler for pending timers.  */
+static void
+deliver_alarm_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_alarm_signal);
+}
+
+
+/* Call alarm signal handler for pending timers.  */
 
 void
 do_pending_atimers (void)
@@ -412,7 +412,7 @@
 {
   if (on)
     {
-      signal (SIGALRM, alarm_signal_handler);
+      signal (SIGALRM, deliver_alarm_signal);
       set_alarm ();
     }
   else
@@ -426,5 +426,5 @@
   free_atimers = stopped_atimers = atimers = NULL;
   pending_atimers = 0;
   /* pending_signals is initialized in init_keyboard.*/
-  signal (SIGALRM, alarm_signal_handler);
+  signal (SIGALRM, deliver_alarm_signal);
 }

=== modified file 'src/data.c'
--- a/src/data.c        2012-09-04 17:34:54 +0000
+++ b/src/data.c        2012-09-05 21:33:53 +0000
@@ -3207,18 +3207,19 @@
   XSYMBOL (intern_c_string ("most-negative-fixnum"))->constant = 1;
 }
 
-#ifndef FORWARD_SIGNAL_TO_MAIN_THREAD
-_Noreturn
-#endif
-static void
-arith_error (int signo)
+static _Noreturn void
+handle_arith_signal (int sig)
 {
   sigsetmask (SIGEMPTYMASK);
-
-  SIGNAL_THREAD_CHECK (signo);
   xsignal0 (Qarith_error);
 }
 
+static void
+deliver_arith_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_arith_signal);
+}
+
 void
 init_data (void)
 {
@@ -3230,5 +3231,5 @@
   if (!initialized)
     return;
 #endif /* CANNOT_DUMP */
-  signal (SIGFPE, arith_error);
+  signal (SIGFPE, deliver_arith_signal);
 }

=== modified file 'src/dispnew.c'
--- a/src/dispnew.c     2012-09-04 17:34:54 +0000
+++ b/src/dispnew.c     2012-09-05 21:33:53 +0000
@@ -5552,17 +5552,15 @@
 
 #ifdef SIGWINCH
 
+static void deliver_window_change_signal (int);
+
 static void
-window_change_signal (int signalnum) /* If we don't have an argument, */
-                               /* some compilers complain in signal calls.  */
+handle_window_change_signal (int sig)
 {
   int width, height;
-  int old_errno = errno;
-
   struct tty_display_info *tty;
 
-  signal (SIGWINCH, window_change_signal);
-  SIGNAL_THREAD_CHECK (signalnum);
+  signal (SIGWINCH, deliver_window_change_signal);
 
   /* The frame size change obviously applies to a single
      termcap-controlled terminal, but we can't decide which.
@@ -5591,8 +5589,12 @@
           change_frame_size (XFRAME (frame), height, width, 0, 1, 0);
     }
   }
+}
 
-  errno = old_errno;
+static void
+deliver_window_change_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_window_change_signal);
 }
 #endif /* SIGWINCH */
 
@@ -5604,7 +5606,7 @@
 void
 do_pending_window_change (bool safe)
 {
-  /* If window_change_signal should have run before, run it now.  */
+  /* If window change signal handler should have run before, run it now.  */
   if (redisplaying_p && !safe)
     return;
 
@@ -6173,7 +6175,7 @@
 #ifndef CANNOT_DUMP
   if (initialized)
 #endif /* CANNOT_DUMP */
-    signal (SIGWINCH, window_change_signal);
+    signal (SIGWINCH, deliver_window_change_signal);
 #endif /* SIGWINCH */
 
   /* If running as a daemon, no need to initialize any frames/terminal. */

=== modified file 'src/emacs.c'
--- a/src/emacs.c       2012-09-04 18:29:04 +0000
+++ b/src/emacs.c       2012-09-05 21:33:53 +0000
@@ -275,14 +275,6 @@
 /* True if handling a fatal error already.  */
 bool fatal_error_in_progress;
 
-#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
-/* When compiled with GTK and running under Gnome,
-   multiple threads may be created.  Keep track of our main
-   thread to make sure signals are delivered to it (see syssignal.h).  */
-
-pthread_t main_thread;
-#endif
-
 #ifdef HAVE_NS
 /* NS autrelease pool, for memory management.  */
 static void *ns_pool;
@@ -291,16 +283,18 @@
 
 
 /* Handle bus errors, invalid instruction, etc.  */
-#ifndef FLOAT_CATCH_SIGILL
-static
-#endif
-void
-fatal_error_signal (int sig)
+static void
+handle_fatal_signal (int sig)
 {
-  SIGNAL_THREAD_CHECK (sig);
   fatal_error_backtrace (sig, 10);
 }
 
+static void
+deliver_fatal_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_fatal_signal);
+}
+
 /* Report a fatal error due to signal SIG, output a backtrace of at
    most BACKTRACE_LIMIT lines, and exit.  */
 _Noreturn void
@@ -340,17 +334,23 @@
 #ifdef SIGDANGER
 
 /* Handler for SIGDANGER.  */
-void
-memory_warning_signal (int sig)
+static void deliver_danger_signal (int);
+
+static void
+handle_danger_signal (int sig)
 {
-  signal (sig, memory_warning_signal);
-  SIGNAL_THREAD_CHECK (sig);
-
+  signal (sig, deliver_danger_signal);
   malloc_warning ("Operating system warns that virtual memory is running 
low.\n");
 
   /* It might be unsafe to call do_auto_save now.  */
   force_auto_save_soon ();
 }
+
+static void
+deliver_danger_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_danger_signal);
+}
 #endif
 
 /* Code for dealing with Lisp access to the Unix command line.  */
@@ -851,10 +851,6 @@
 # endif /* not SYNC_INPUT */
 #endif /* not SYSTEM_MALLOC */
 
-#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
-  main_thread = pthread_self ();
-#endif /* FORWARD_SIGNAL_TO_MAIN_THREAD */
-
 #if defined (MSDOS) || defined (WINDOWSNT)
   /* We do all file input/output as binary files.  When we need to translate
      newlines, we do that manually.  */
@@ -1120,7 +1116,7 @@
         That makes nohup work.  */
       if (! noninteractive
          || signal (SIGHUP, SIG_IGN) != SIG_IGN)
-       signal (SIGHUP, fatal_error_signal);
+       signal (SIGHUP, deliver_fatal_signal);
       sigunblock (sigmask (SIGHUP));
     }
 
@@ -1135,9 +1131,9 @@
       /* Don't catch these signals in batch mode if dumping.
         On some machines, this sets static data that would make
         signal fail to work right when the dumped Emacs is run.  */
-      signal (SIGQUIT, fatal_error_signal);
-      signal (SIGILL, fatal_error_signal);
-      signal (SIGTRAP, fatal_error_signal);
+      signal (SIGQUIT, deliver_fatal_signal);
+      signal (SIGILL, deliver_fatal_signal);
+      signal (SIGTRAP, deliver_fatal_signal);
 #ifdef SIGUSR1
       add_user_signal (SIGUSR1, "sigusr1");
 #endif
@@ -1145,68 +1141,68 @@
       add_user_signal (SIGUSR2, "sigusr2");
 #endif
 #ifdef SIGABRT
-      signal (SIGABRT, fatal_error_signal);
+      signal (SIGABRT, deliver_fatal_signal);
 #endif
 #ifdef SIGHWE
-      signal (SIGHWE, fatal_error_signal);
+      signal (SIGHWE, deliver_fatal_signal);
 #endif
 #ifdef SIGPRE
-      signal (SIGPRE, fatal_error_signal);
+      signal (SIGPRE, deliver_fatal_signal);
 #endif
 #ifdef SIGORE
-      signal (SIGORE, fatal_error_signal);
+      signal (SIGORE, deliver_fatal_signal);
 #endif
 #ifdef SIGUME
-      signal (SIGUME, fatal_error_signal);
+      signal (SIGUME, deliver_fatal_signal);
 #endif
 #ifdef SIGDLK
-      signal (SIGDLK, fatal_error_signal);
+      signal (SIGDLK, deliver_fatal_signal);
 #endif
 #ifdef SIGCPULIM
-      signal (SIGCPULIM, fatal_error_signal);
+      signal (SIGCPULIM, deliver_fatal_signal);
 #endif
 #ifdef SIGIOT
       /* This is missing on some systems - OS/2, for example.  */
-      signal (SIGIOT, fatal_error_signal);
+      signal (SIGIOT, deliver_fatal_signal);
 #endif
 #ifdef SIGEMT
-      signal (SIGEMT, fatal_error_signal);
+      signal (SIGEMT, deliver_fatal_signal);
 #endif
-      signal (SIGFPE, fatal_error_signal);
+      signal (SIGFPE, deliver_fatal_signal);
 #ifdef SIGBUS
-      signal (SIGBUS, fatal_error_signal);
+      signal (SIGBUS, deliver_fatal_signal);
 #endif
-      signal (SIGSEGV, fatal_error_signal);
+      signal (SIGSEGV, deliver_fatal_signal);
 #ifdef SIGSYS
-      signal (SIGSYS, fatal_error_signal);
+      signal (SIGSYS, deliver_fatal_signal);
 #endif
       /*  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.
       */
-      if (noninteractive) signal (SIGINT, fatal_error_signal);
-      signal (SIGTERM, fatal_error_signal);
+      if (noninteractive) signal (SIGINT, deliver_fatal_signal);
+      signal (SIGTERM, deliver_fatal_signal);
 #ifdef SIGXCPU
-      signal (SIGXCPU, fatal_error_signal);
+      signal (SIGXCPU, deliver_fatal_signal);
 #endif
 #ifdef SIGXFSZ
-      signal (SIGXFSZ, fatal_error_signal);
+      signal (SIGXFSZ, deliver_fatal_signal);
 #endif /* SIGXFSZ */
 
 #ifdef SIGDANGER
       /* This just means available memory is getting low.  */
-      signal (SIGDANGER, memory_warning_signal);
+      signal (SIGDANGER, deliver_danger_signal);
 #endif
 
 #ifdef AIX
 /* 20 is SIGCHLD, 21 is SIGTTIN, 22 is SIGTTOU.  */
-      signal (SIGXCPU, fatal_error_signal);
-      signal (SIGIOINT, fatal_error_signal);
-      signal (SIGGRANT, fatal_error_signal);
-      signal (SIGRETRACT, fatal_error_signal);
-      signal (SIGSOUND, fatal_error_signal);
-      signal (SIGMSG, fatal_error_signal);
+      signal (SIGXCPU, deliver_fatal_signal);
+      signal (SIGIOINT, deliver_fatal_signal);
+      signal (SIGGRANT, deliver_fatal_signal);
+      signal (SIGRETRACT, deliver_fatal_signal);
+      signal (SIGSOUND, deliver_fatal_signal);
+      signal (SIGMSG, deliver_fatal_signal);
 #endif /* AIX */
     }
 

=== modified file 'src/floatfns.c'
--- a/src/floatfns.c    2012-09-05 07:18:46 +0000
+++ b/src/floatfns.c    2012-09-05 21:33:53 +0000
@@ -37,9 +37,6 @@
    Define FLOAT_CHECK_ERRNO if the float library routines set errno.
    This has no effect if HAVE_MATHERR is defined.
 
-   Define FLOAT_CATCH_SIGILL if the float library routines signal SIGILL.
-   (What systems actually do this?  Please let us know.)
-
    Define FLOAT_CHECK_DOMAIN if the float library doesn't handle errors by
    either setting errno, or signaling SIGFPE/SIGILL.  Otherwise, domain and
    range checking will happen before calling the float routines.  This has
@@ -99,10 +96,6 @@
 # include <errno.h>
 #endif
 
-#ifdef FLOAT_CATCH_SIGILL
-static void float_error ();
-#endif
-
 /* True while executing in floating point.
    This tells float_error what to do.  */
 
@@ -947,31 +940,6 @@
   return make_float (d);
 }
 
-#ifdef FLOAT_CATCH_SIGILL
-static void
-float_error (int signo)
-{
-  if (! in_float)
-    fatal_error_signal (signo);
-
-#ifdef BSD_SYSTEM
-  sigsetmask (SIGEMPTYMASK);
-#else
-  /* Must reestablish handler each time it is called.  */
-  signal (SIGILL, float_error);
-#endif /* BSD_SYSTEM */
-
-  SIGNAL_THREAD_CHECK (signo);
-  in_float = 0;
-
-  xsignal1 (Qarith_error, float_error_arg);
-}
-
-/* Another idea was to replace the library function `infnan'
-   where SIGILL is signaled.  */
-
-#endif /* FLOAT_CATCH_SIGILL */
-
 #ifdef HAVE_MATHERR
 int
 matherr (struct exception *x)
@@ -1006,9 +974,6 @@
 void
 init_floatfns (void)
 {
-#ifdef FLOAT_CATCH_SIGILL
-  signal (SIGILL, float_error);
-#endif
   in_float = 0;
 }
 

=== modified file 'src/keyboard.c'
--- a/src/keyboard.c    2012-09-04 17:34:54 +0000
+++ b/src/keyboard.c    2012-09-05 21:33:53 +0000
@@ -449,9 +449,8 @@
 static Lisp_Object apply_modifiers (int, Lisp_Object);
 static void clear_event (struct input_event *);
 static Lisp_Object restore_kboard_configuration (Lisp_Object);
-static void interrupt_signal (int signalnum);
 #ifdef SIGIO
-static void input_available_signal (int signo);
+static void deliver_input_available_signal (int signo);
 #endif
 static void handle_interrupt (void);
 static _Noreturn void quit_throw_to_read_char (int);
@@ -459,7 +458,7 @@
 static void timer_start_idle (void);
 static void timer_stop_idle (void);
 static void timer_resume_idle (void);
-static void handle_user_signal (int);
+static void deliver_user_signal (int);
 static char *find_user_signal_name (int);
 static int store_user_signal_events (void);
 
@@ -3833,7 +3832,7 @@
       unhold_keyboard_input ();
 #ifdef SIGIO
       if (!noninteractive)
-        signal (SIGIO, input_available_signal);
+        signal (SIGIO, deliver_input_available_signal);
 #endif /* SIGIO */
       start_polling ();
     }
@@ -7236,12 +7235,8 @@
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
 
 static void
-input_available_signal (int signo)
+handle_input_available_signal (int sig)
 {
-  /* Must preserve main program's value of errno.  */
-  int old_errno = errno;
-  SIGNAL_THREAD_CHECK (signo);
-
 #ifdef SYNC_INPUT
   interrupt_input_pending = 1;
   pending_signals = 1;
@@ -7253,8 +7248,12 @@
 #ifndef SYNC_INPUT
   handle_async_input ();
 #endif
+}
 
-  errno = old_errno;
+static void
+deliver_input_available_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_input_available_signal);
 }
 #endif /* SIGIO */
 
@@ -7310,18 +7309,15 @@
   p->next = user_signals;
   user_signals = p;
 
-  signal (sig, handle_user_signal);
+  signal (sig, deliver_user_signal);
 }
 
 static void
 handle_user_signal (int sig)
 {
-  int old_errno = errno;
   struct user_signal_info *p;
   const char *special_event_name = NULL;
 
-  SIGNAL_THREAD_CHECK (sig);
-
   if (SYMBOLP (Vdebug_on_event))
     special_event_name = SSDATA (SYMBOL_NAME (Vdebug_on_event));
 
@@ -7355,8 +7351,12 @@
          }
        break;
       }
+}
 
-  errno = old_errno;
+static void
+deliver_user_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_user_signal);
 }
 
 static char *
@@ -10776,17 +10776,10 @@
    Otherwise, tell QUIT to kill Emacs.  */
 
 static void
-interrupt_signal (int signalnum)       /* If we don't have an argument, some */
-                                       /* compilers complain in signal calls.  
*/
+handle_interrupt_signal (int sig)
 {
-  /* Must preserve main program's value of errno.  */
-  int old_errno = errno;
-  struct terminal *terminal;
-
-  SIGNAL_THREAD_CHECK (signalnum);
-
   /* See if we have an active terminal on our controlling tty.  */
-  terminal = get_named_tty ("/dev/tty");
+  struct terminal *terminal = get_named_tty ("/dev/tty");
   if (!terminal)
     {
       /* If there are no frames there, let's pretend that we are a
@@ -10807,9 +10800,14 @@
 
       handle_interrupt ();
     }
-
-  errno = old_errno;
-}
+}
+
+static void
+deliver_interrupt_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_interrupt_signal);
+}
+
 
 /* If Emacs is stuck because `inhibit-quit' is true, then keep track
    of the number of times C-g has been requested.  If C-g is pressed
@@ -11404,17 +11402,17 @@
          SIGINT.  There is special code in interrupt_signal to exit
          Emacs on SIGINT when there are no termcap frames on the
          controlling terminal.  */
-      signal (SIGINT, interrupt_signal);
+      signal (SIGINT, deliver_interrupt_signal);
 #ifndef DOS_NT
       /* For systems with SysV TERMIO, C-g is set up for both SIGINT and
         SIGQUIT and we can't tell which one it will give us.  */
-      signal (SIGQUIT, interrupt_signal);
+      signal (SIGQUIT, deliver_interrupt_signal);
 #endif /* not DOS_NT */
     }
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
 #ifdef SIGIO
   if (!noninteractive)
-    signal (SIGIO, input_available_signal);
+    signal (SIGIO, deliver_input_available_signal);
 #endif /* SIGIO */
 
 /* Use interrupt input by default, if it works and noninterrupt input

=== modified file 'src/lisp.h'
--- a/src/lisp.h        2012-09-05 17:05:32 +0000
+++ b/src/lisp.h        2012-09-05 21:33:53 +0000
@@ -3256,9 +3256,6 @@
 extern Lisp_Object decode_env_path (const char *, const char *);
 extern Lisp_Object empty_unibyte_string, empty_multibyte_string;
 extern Lisp_Object Qfile_name_handler_alist;
-#ifdef FLOAT_CATCH_SIGILL
-extern void fatal_error_signal (int);
-#endif
 extern _Noreturn void fatal_error_backtrace (int, int);
 extern Lisp_Object Qkill_emacs;
 #if HAVE_SETLOCALE

=== modified file 'src/process.c'
--- a/src/process.c     2012-09-04 17:34:54 +0000
+++ b/src/process.c     2012-09-05 21:33:53 +0000
@@ -124,6 +124,14 @@
 #include "xgselect.h"
 #endif
 
+#ifndef WNOHANG
+# undef waitpid
+# define waitpid(pid, status, options) wait (status)
+#endif
+#ifndef WUNTRACED
+# define WUNTRACED 0
+#endif
+
 /* Work around GCC 4.7.0 bug with strict overflow checking; see
    <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>.
    These lines can be removed once the GCC bug is fixed.  */
@@ -801,7 +809,7 @@
 #ifdef SIGCHLD
 /* Fdelete_process promises to immediately forget about the process, but in
    reality, Emacs needs to remember those processes until they have been
-   treated by sigchld_handler; otherwise this handler would consider the
+   treated by the SIGCHLD handler; otherwise this handler would consider the
    process as being synchronous and say that the synchronous process is
    dead.  */
 static Lisp_Object deleted_pid_list;
@@ -849,7 +857,8 @@
 #endif
        {
          Fkill_process (process, Qnil);
-         /* Do this now, since remove_process will make sigchld_handler do 
nothing.  */
+         /* Do this now, since remove_process will make the
+            SIGCHLD handler do nothing.  */
          pset_status (p, Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil)));
          p->tick = ++process_tick;
          status_notify (p);
@@ -1728,7 +1737,7 @@
   if (inchannel > max_process_desc)
     max_process_desc = inchannel;
 
-  /* Until we store the proper pid, enable sigchld_handler
+  /* Until we store the proper pid, enable the SIGCHLD handler
      to recognize an unknown pid as standing for this process.
      It is very important not to let this `marker' value stay
      in the table after this function has returned; if it does
@@ -4956,8 +4965,8 @@
 
                  if (p->pid == -2)
                    {
-                     /* If the EIO occurs on a pty, sigchld_handler's
-                        waitpid() will not find the process object to
+                     /* If the EIO occurs on a pty, the SIGCHLD handler's
+                        waitpid call will not find the process object to
                         delete.  Do it here.  */
                      p->tick = ++process_tick;
                      pset_status (p, Qfailed);
@@ -5422,18 +5431,19 @@
 static jmp_buf send_process_frame;
 static Lisp_Object process_sent_to;
 
-#ifndef FORWARD_SIGNAL_TO_MAIN_THREAD
-static _Noreturn void send_process_trap (int);
-#endif
-
-static void
-send_process_trap (int ignore)
+static _Noreturn void
+handle_pipe_signal (int sig)
 {
-  SIGNAL_THREAD_CHECK (SIGPIPE);
   sigunblock (sigmask (SIGPIPE));
   _longjmp (send_process_frame, 1);
 }
 
+static void
+deliver_pipe_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_pipe_signal);
+}
+
 /* In send_process, when a write fails temporarily,
    wait_reading_process_output is called.  It may execute user code,
    e.g. timers, that attempts to write new data to the same process.
@@ -5663,7 +5673,7 @@
              /* Send this batch, using one or more write calls.  */
              ptrdiff_t written = 0;
              int outfd = p->outfd;
-             old_sigpipe = (void (*) (int)) signal (SIGPIPE, 
send_process_trap);
+             old_sigpipe = signal (SIGPIPE, deliver_pipe_signal);
 #ifdef DATAGRAM_SOCKETS
              if (DATAGRAM_CHAN_P (outfd))
                {
@@ -6397,143 +6407,135 @@
    indirectly; if it does, that is a bug  */
 
 #ifdef SIGCHLD
-static void
-sigchld_handler (int signo)
+
+/* Record one child's changed status.  Return true if a child was found.  */
+static bool
+record_child_status_change (void)
 {
-  int old_errno = errno;
   Lisp_Object proc;
   struct Lisp_Process *p;
-
-  SIGNAL_THREAD_CHECK (signo);
-
-  while (1)
-    {
-      pid_t pid;
-      int w;
-      Lisp_Object tail;
-
-#ifdef WNOHANG
-#ifndef WUNTRACED
-#define WUNTRACED 0
-#endif /* no WUNTRACED */
-      /* Keep trying to get a status until we get a definitive result.  */
-      do
-       {
-         errno = 0;
-         pid = waitpid (-1, &w, WNOHANG | WUNTRACED);
-       }
-      while (pid < 0 && errno == EINTR);
-
-      if (pid <= 0)
-       {
-         /* PID == 0 means no processes found, PID == -1 means a real
-            failure.  We have done all our job, so return.  */
-
-         errno = old_errno;
-         return;
-       }
-#else
-      pid = wait (&w);
-#endif /* no WNOHANG */
-
-      /* Find the process that signaled us, and record its status.  */
-
-      /* The process can have been deleted by Fdelete_process.  */
-      for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail))
-       {
-         Lisp_Object xpid = XCAR (tail);
-         if ((INTEGERP (xpid) && pid == XINT (xpid))
-             || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid)))
-           {
-             XSETCAR (tail, Qnil);
-             goto sigchld_end_of_loop;
-           }
-       }
-
-      /* Otherwise, if it is asynchronous, it is in Vprocess_alist.  */
+  pid_t pid;
+  int w;
+  Lisp_Object tail;
+
+  do
+    pid = waitpid (-1, &w, WNOHANG | WUNTRACED);
+  while (pid < 0 && errno == EINTR);
+
+  /* PID == 0 means no processes found, PID == -1 means a real failure.
+     Either way, we have done all our job.  */
+  if (pid <= 0)
+    return false;
+
+  /* Find the process that signaled us, and record its status.  */
+
+  /* The process can have been deleted by Fdelete_process.  */
+  for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail))
+    {
+      Lisp_Object xpid = XCAR (tail);
+      if ((INTEGERP (xpid) && pid == XINT (xpid))
+         || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid)))
+       {
+         XSETCAR (tail, Qnil);
+         return true;
+       }
+    }
+
+  /* Otherwise, if it is asynchronous, it is in Vprocess_alist.  */
+  p = 0;
+  for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+    {
+      proc = XCDR (XCAR (tail));
+      p = XPROCESS (proc);
+      if (EQ (p->type, Qreal) && p->pid == pid)
+       break;
       p = 0;
-      for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
-       {
-         proc = XCDR (XCAR (tail));
-         p = XPROCESS (proc);
-         if (EQ (p->type, Qreal) && p->pid == pid)
-           break;
-         p = 0;
-       }
-
-      /* Look for an asynchronous process whose pid hasn't been filled
-        in yet.  */
-      if (p == 0)
-       for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
-         {
-           proc = XCDR (XCAR (tail));
-           p = XPROCESS (proc);
-           if (p->pid == -1)
-             break;
-           p = 0;
-         }
-
-      /* Change the status of the process that was found.  */
-      if (p != 0)
-       {
-         int clear_desc_flag = 0;
-
-         p->tick = ++process_tick;
-         p->raw_status = w;
-         p->raw_status_new = 1;
-
-         /* If process has terminated, stop waiting for its output.  */
-         if ((WIFSIGNALED (w) || WIFEXITED (w))
-             && p->infd >= 0)
-           clear_desc_flag = 1;
-
-         /* We use clear_desc_flag to avoid a compiler bug in Microsoft C.  */
-         if (clear_desc_flag)
-           {
-             FD_CLR (p->infd, &input_wait_mask);
-             FD_CLR (p->infd, &non_keyboard_wait_mask);
-           }
-
-         /* Tell wait_reading_process_output that it needs to wake up and
-            look around.  */
-         if (input_available_clear_time)
-           *input_available_clear_time = make_emacs_time (0, 0);
-       }
-
-      /* There was no asynchronous process found for that pid: we have
-        a synchronous process.  */
-      else
-       {
-         synch_process_alive = 0;
-
-         /* Report the status of the synchronous process.  */
-         if (WIFEXITED (w))
-           synch_process_retcode = WEXITSTATUS (w);
-         else if (WIFSIGNALED (w))
-           synch_process_termsig = WTERMSIG (w);
-
-         /* Tell wait_reading_process_output that it needs to wake up and
-            look around.  */
-         if (input_available_clear_time)
-           *input_available_clear_time = make_emacs_time (0, 0);
-       }
-
-    sigchld_end_of_loop:
-      ;
-
-      /* On some systems, we must return right away.
-        If any more processes want to signal us, we will
-        get another signal.
-        Otherwise (on systems that have WNOHANG), loop around
-        to use up all the processes that have something to tell us.  */
+    }
+
+  /* Look for an asynchronous process whose pid hasn't been filled
+     in yet.  */
+  if (! p)
+    for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+      {
+       proc = XCDR (XCAR (tail));
+       p = XPROCESS (proc);
+       if (p->pid == -1)
+         break;
+       p = 0;
+      }
+
+  /* Change the status of the process that was found.  */
+  if (p)
+    {
+      int clear_desc_flag = 0;
+
+      p->tick = ++process_tick;
+      p->raw_status = w;
+      p->raw_status_new = 1;
+
+      /* If process has terminated, stop waiting for its output.  */
+      if ((WIFSIGNALED (w) || WIFEXITED (w))
+         && p->infd >= 0)
+       clear_desc_flag = 1;
+
+      /* We use clear_desc_flag to avoid a compiler bug in Microsoft C.  */
+      if (clear_desc_flag)
+       {
+         FD_CLR (p->infd, &input_wait_mask);
+         FD_CLR (p->infd, &non_keyboard_wait_mask);
+       }
+
+      /* Tell wait_reading_process_output that it needs to wake up and
+        look around.  */
+      if (input_available_clear_time)
+       *input_available_clear_time = make_emacs_time (0, 0);
+    }
+  /* There was no asynchronous process found for that pid: we have
+     a synchronous process.  */
+  else
+    {
+      synch_process_alive = 0;
+
+      /* Report the status of the synchronous process.  */
+      if (WIFEXITED (w))
+       synch_process_retcode = WEXITSTATUS (w);
+      else if (WIFSIGNALED (w))
+       synch_process_termsig = WTERMSIG (w);
+
+      /* Tell wait_reading_process_output that it needs to wake up and
+        look around.  */
+      if (input_available_clear_time)
+       *input_available_clear_time = make_emacs_time (0, 0);
+    }
+
+  return true;
+}
+
+/* On some systems, the SIGCHLD handler must return right away.  If
+   any more processes want to signal us, we will get another signal.
+   Otherwise, loop around to use up all the processes that have
+   something to tell us.  */
 #if (defined WINDOWSNT \
      || (defined USG && !defined GNU_LINUX \
         && !(defined HPUX && defined WNOHANG)))
-      errno = old_errno;
-      return;
-#endif /* USG, but not HPUX with WNOHANG */
-    }
-}
+enum { CAN_HANDLE_MULTIPLE_CHILDREN = 1 };
+#else
+enum { CAN_HANDLE_MULTIPLE_CHILDREN = 0 };
+#endif
+
+static void
+handle_child_signal (int sig)
+{
+  while (record_child_status_change () && CAN_HANDLE_MULTIPLE_CHILDREN)
+    continue;
+}
+
+static void
+deliver_child_signal (int sig)
+{
+  handle_on_main_thread (sig, handle_child_signal);
+}
+
 #endif /* SIGCHLD */
 
 
@@ -7387,7 +7389,7 @@
 #ifndef CANNOT_DUMP
   if (! noninteractive || initialized)
 #endif
-    signal (SIGCHLD, sigchld_handler);
+    signal (SIGCHLD, deliver_child_signal);
 #endif
 
   FD_ZERO (&input_wait_mask);

=== modified file 'src/sysdep.c'
--- a/src/sysdep.c      2012-09-04 18:29:04 +0000
+++ b/src/sysdep.c      2012-09-05 21:33:53 +0000
@@ -1551,6 +1551,40 @@
   return (old_mask);
 }
 
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+pthread_t main_thread;
+#endif
+
+/* 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)
+{
+  /* Preserve errno, to avoid race conditions with signal handlers that
+     might change errno.  Races can occur even in single-threaded hosts.  */
+  int old_errno = errno;
+
+  bool on_main_thread = true;
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+  if (! pthread_equal (pthread_self (), main_thread))
+    {
+      sigset_t blocked;
+      sigemptyset (&blocked);
+      sigaddset (&blocked, sig);
+      pthread_sigmask (SIG_BLOCK, &blocked, 0);
+      pthread_kill (main_thread, sig);
+      on_main_thread = false;
+    }
+#endif
+  if (on_main_thread)
+    handler (sig);
+
+  errno = old_errno;
+}
 
 #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
 static char *my_sys_siglist[NSIG];
@@ -1565,6 +1599,10 @@
 {
   sigemptyset (&empty_mask);
 
+#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
+  main_thread = pthread_self ();
+#endif
+
 #if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
   if (! initialized)
     {

=== modified file 'src/syssignal.h'
--- a/src/syssignal.h   2012-07-13 01:19:06 +0000
+++ b/src/syssignal.h   2012-09-05 21:33:53 +0000
@@ -133,24 +133,5 @@
 
 #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
 extern pthread_t main_thread;
-#define SIGNAL_THREAD_CHECK(signo)                                      \
-  do {                                                                  \
-    if (!pthread_equal (pthread_self (), main_thread))                 \
-      {                                                                 \
-        /* POSIX says any thread can receive the signal.  On GNU/Linux  \
-           that is not true, but for other systems (FreeBSD at least)   \
-           it is.  So direct the signal to the correct thread and block \
-           it from this thread.  */                                     \
-        sigset_t new_mask;                                              \
-                                                                        \
-        sigemptyset (&new_mask);                                        \
-        sigaddset (&new_mask, signo);                                   \
-        pthread_sigmask (SIG_BLOCK, &new_mask, 0);                      \
-        pthread_kill (main_thread, signo);                              \
-        return;                                                         \
-      }                                                                 \
-   } while (0)
-
-#else /* not FORWARD_SIGNAL_TO_MAIN_THREAD */
-#define SIGNAL_THREAD_CHECK(signo)
-#endif /* not FORWARD_SIGNAL_TO_MAIN_THREAD */
+void handle_on_main_thread (int, signal_handler_t);
+#endif


reply via email to

[Prev in Thread] Current Thread [Next in Thread]