]> git.eshelyaron.com Git - emacs.git/commitdiff
Handle sigmask better with nested signal handlers.
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 25 Mar 2014 14:43:26 +0000 (07:43 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 25 Mar 2014 14:43:26 +0000 (07:43 -0700)
* atimer.c (sigmask_atimers): Remove.
Remaining use rewritten to use body of this function.
* atimer.c (block_atimers, unblock_atimers):
* callproc.c (block_child_signal, unblock_child_signal):
* sysdep.c (block_tty_out_signal, unblock_tty_out_signal):
New arg OLDSET.  All callers changed.
* atimer.c (block_atimers, unblock_atimers):
* callproc.c (block_child_signal, unblock_child_signal):
* keyboard.c (handle_interrupt):
* sound.c (vox_configure, vox_close):
Restore the old signal mask rather than unilaterally clearing bits
from the mask, in case a handler is running within another
handler.  All callers changed.
* lisp.h, process.c, process.h, term.c:
Adjust decls and callers to match new API.
* sysdep.c (emacs_sigaction_init): Don't worry about masking SIGFPE;
signal handlers aren't supposed to use floating point anyway.
(handle_arith_signal): Unblock just SIGFPE rather than clearing mask.

Fixes: debbugs:15561
src/ChangeLog
src/atimer.c
src/callproc.c
src/keyboard.c
src/lisp.h
src/process.c
src/process.h
src/sound.c
src/sysdep.c
src/term.c

index d9e99722319bd3ac241c25a61657571bfc7336a1..44ebe76555c0d50791442c0ff6732ab312f8230c 100644 (file)
@@ -1,3 +1,25 @@
+2014-03-25  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Handle sigmask better with nested signal handlers  (Bug#15561).
+       * atimer.c (sigmask_atimers): Remove.
+       Remaining use rewritten to use body of this function.
+       * atimer.c (block_atimers, unblock_atimers):
+       * callproc.c (block_child_signal, unblock_child_signal):
+       * sysdep.c (block_tty_out_signal, unblock_tty_out_signal):
+       New arg OLDSET.  All callers changed.
+       * atimer.c (block_atimers, unblock_atimers):
+       * callproc.c (block_child_signal, unblock_child_signal):
+       * keyboard.c (handle_interrupt):
+       * sound.c (vox_configure, vox_close):
+       Restore the old signal mask rather than unilaterally clearing bits
+       from the mask, in case a handler is running within another
+       handler.  All callers changed.
+       * lisp.h, process.c, process.h, term.c:
+       Adjust decls and callers to match new API.
+       * sysdep.c (emacs_sigaction_init): Don't worry about masking SIGFPE;
+       signal handlers aren't supposed to use floating point anyway.
+       (handle_arith_signal): Unblock just SIGFPE rather than clearing mask.
+
 2014-03-23  Daniel Colascione  <dancol@dancol.org>
 
        Split gc_sweep into discrete functions for legibility and better
index d98ddac0171c41b785cceb964900e171e439a652..a5a2b0714e3b82570c2b2efc864beeb17542b67a 100644 (file)
@@ -50,22 +50,17 @@ static bool alarm_timer_ok;
 /* Block/unblock SIGALRM.  */
 
 static void
-sigmask_atimers (int how)
+block_atimers (sigset_t *oldset)
 {
   sigset_t blocked;
   sigemptyset (&blocked);
   sigaddset (&blocked, SIGALRM);
-  pthread_sigmask (how, &blocked, 0);
+  pthread_sigmask (SIG_BLOCK, &blocked, oldset);
 }
 static void
-block_atimers (void)
+unblock_atimers (sigset_t const *oldset)
 {
-  sigmask_atimers (SIG_BLOCK);
-}
-static void
-unblock_atimers (void)
-{
-  sigmask_atimers (SIG_UNBLOCK);
+  pthread_sigmask (SIG_SETMASK, oldset, 0);
 }
 
 /* Function prototypes.  */
@@ -98,6 +93,7 @@ start_atimer (enum atimer_type type, struct timespec timestamp,
              atimer_callback fn, void *client_data)
 {
   struct atimer *t;
+  sigset_t oldset;
 
   /* Round TIME up to the next full second if we don't have
      itimers.  */
@@ -122,7 +118,7 @@ start_atimer (enum atimer_type type, struct timespec timestamp,
   t->fn = fn;
   t->client_data = client_data;
 
-  block_atimers ();
+  block_atimers (&oldset);
 
   /* Compute the timer's expiration time.  */
   switch (type)
@@ -143,7 +139,7 @@ start_atimer (enum atimer_type type, struct timespec timestamp,
 
   /* Insert the timer in the list of active atimers.  */
   schedule_atimer (t);
-  unblock_atimers ();
+  unblock_atimers (&oldset);
 
   /* Arrange for a SIGALRM at the time the next atimer is ripe.  */
   set_alarm ();
@@ -158,8 +154,9 @@ void
 cancel_atimer (struct atimer *timer)
 {
   int i;
+  sigset_t oldset;
 
-  block_atimers ();
+  block_atimers (&oldset);
 
   for (i = 0; i < 2; ++i)
     {
@@ -186,7 +183,7 @@ cancel_atimer (struct atimer *timer)
        }
     }
 
-  unblock_atimers ();
+  unblock_atimers (&oldset);
 }
 
 
@@ -217,7 +214,8 @@ append_atimer_lists (struct atimer *list_1, struct atimer *list_2)
 void
 stop_other_atimers (struct atimer *t)
 {
-  block_atimers ();
+  sigset_t oldset;
+  block_atimers (&oldset);
 
   if (t)
     {
@@ -242,7 +240,7 @@ stop_other_atimers (struct atimer *t)
 
   stopped_atimers = append_atimer_lists (atimers, stopped_atimers);
   atimers = t;
-  unblock_atimers ();
+  unblock_atimers (&oldset);
 }
 
 
@@ -256,8 +254,9 @@ run_all_atimers (void)
     {
       struct atimer *t = atimers;
       struct atimer *next;
+      sigset_t oldset;
 
-      block_atimers ();
+      block_atimers (&oldset);
       atimers = stopped_atimers;
       stopped_atimers = NULL;
 
@@ -268,7 +267,7 @@ run_all_atimers (void)
          t = next;
        }
 
-      unblock_atimers ();
+      unblock_atimers (&oldset);
     }
 }
 
@@ -381,9 +380,10 @@ do_pending_atimers (void)
 {
   if (atimers)
     {
-      block_atimers ();
+      sigset_t oldset;
+      block_atimers (&oldset);
       run_timers ();
-      unblock_atimers ();
+      unblock_atimers (&oldset);
     }
 }
 
index 0831291b0dd3bead229d30f338dd109fbf925f01..2147c173655eb5067ebd259451603b5f734f1da8 100644 (file)
@@ -108,20 +108,20 @@ static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int, ptrdiff_t);
 /* Block SIGCHLD.  */
 
 void
-block_child_signal (void)
+block_child_signal (sigset_t *oldset)
 {
   sigset_t blocked;
   sigemptyset (&blocked);
   sigaddset (&blocked, SIGCHLD);
-  pthread_sigmask (SIG_BLOCK, &blocked, 0);
+  pthread_sigmask (SIG_BLOCK, &blocked, oldset);
 }
 
 /* Unblock SIGCHLD.  */
 
 void
-unblock_child_signal (void)
+unblock_child_signal (sigset_t const *oldset)
 {
-  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+  pthread_sigmask (SIG_SETMASK, oldset, 0);
 }
 
 /* Return the current buffer's working directory, or the home
@@ -162,7 +162,8 @@ encode_current_directory (void)
 void
 record_kill_process (struct Lisp_Process *p, Lisp_Object tempfile)
 {
-  block_child_signal ();
+  sigset_t oldset;
+  block_child_signal (&oldset);
 
   if (p->alive)
     {
@@ -171,7 +172,7 @@ record_kill_process (struct Lisp_Process *p, Lisp_Object tempfile)
       kill (- p->pid, SIGKILL);
     }
 
-  unblock_child_signal ();
+  unblock_child_signal (&oldset);
 }
 
 /* Clean up files, file descriptors and processes created by Fcall_process.  */
@@ -313,6 +314,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
   char *tempfile = NULL;
   int pid;
 #else
+  sigset_t oldset;
   pid_t pid;
 #endif
   int child_errno;
@@ -629,7 +631,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
 #ifndef MSDOS
 
   block_input ();
-  block_child_signal ();
+  block_child_signal (&oldset);
 
 #ifdef WINDOWSNT
   pid = child_setup (filefd, fd_output, fd_error, new_argv, 0, current_dir);
@@ -671,7 +673,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
 
   if (pid == 0)
     {
-      unblock_child_signal ();
+      unblock_child_signal (&oldset);
 
       setsid ();
 
@@ -707,7 +709,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
        }
     }
 
-  unblock_child_signal ();
+  unblock_child_signal (&oldset);
   unblock_input ();
 
 #endif /* not MSDOS */
index 038ce6ea601c39b7f631d44b33fd9bab75fb0c17..2b3de6e27c220ae0a1972e06a49e3468d4996014 100644 (file)
@@ -10295,6 +10295,9 @@ static void
 handle_interrupt (bool in_signal_handler)
 {
   char c;
+  sigset_t blocked;
+  sigemptyset (&blocked);
+  sigaddset (&blocked, SIGINT);
 
   cancel_echoing ();
 
@@ -10306,9 +10309,6 @@ handle_interrupt (bool in_signal_handler)
          /* If SIGINT isn't blocked, don't let us be interrupted by
             a SIGINT.  It might be harmful due to non-reentrancy
             in I/O functions.  */
-         sigset_t blocked;
-         sigemptyset (&blocked);
-         sigaddset (&blocked, SIGINT);
          pthread_sigmask (SIG_BLOCK, &blocked, 0);
        }
 
@@ -10393,7 +10393,7 @@ handle_interrupt (bool in_signal_handler)
          struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
          immediate_quit = 0;
-         pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+         pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
          saved = gl_state;
          GCPRO4 (saved.object, saved.global_code,
                  saved.current_syntax_table, saved.old_prop);
@@ -10414,7 +10414,7 @@ handle_interrupt (bool in_signal_handler)
         }
     }
 
-  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+  pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
 
 /* TODO: The longjmp in this call throws the NS event loop integration off,
          and it seems to do fine without this.  Probably some attention
index df8f3120a8e989e6dbfa7aa87a736d7dbc5aae93..98f6c8b4d8dec640304d0488c97103e11d00bcef 100644 (file)
@@ -4238,8 +4238,8 @@ extern void init_sigio (int);
 extern void sys_subshell (void);
 extern void sys_suspend (void);
 extern void discard_tty_input (void);
-extern void block_tty_out_signal (void);
-extern void unblock_tty_out_signal (void);
+extern void block_tty_out_signal (sigset_t *);
+extern void unblock_tty_out_signal (sigset_t const *);
 extern void init_sys_modes (struct tty_display_info *);
 extern void reset_sys_modes (struct tty_display_info *);
 extern void init_all_sys_modes (void);
index fd34eb08d9d583962d7dd36a1ff47969d3081f09..fe365a136deaba062957cd2a8116328ec8df0223 100644 (file)
@@ -1663,6 +1663,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
   bool pty_flag = 0;
   char pty_name[PTY_NAME_SIZE];
   Lisp_Object lisp_pty_name = Qnil;
+  sigset_t oldset;
 
   inchannel = outchannel = -1;
 
@@ -1728,7 +1729,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
   setup_process_coding_systems (process);
 
   block_input ();
-  block_child_signal ();
+  block_child_signal (&oldset);
 
 #ifndef WINDOWSNT
   /* vfork, and prevent local vars from being clobbered by the vfork.  */
@@ -1852,7 +1853,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
       signal (SIGPIPE, SIG_DFL);
 
       /* Stop blocking SIGCHLD in the child.  */
-      unblock_child_signal ();
+      unblock_child_signal (&oldset);
 
       if (pty_flag)
        child_setup_tty (xforkout);
@@ -1871,7 +1872,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
     p->alive = 1;
 
   /* Stop blocking in the parent.  */
-  unblock_child_signal ();
+  unblock_child_signal (&oldset);
   unblock_input ();
 
   if (pid < 0)
@@ -7070,8 +7071,9 @@ void
 catch_child_signal (void)
 {
   struct sigaction action, old_action;
+  sigset_t oldset;
   emacs_sigaction_init (&action, deliver_child_signal);
-  block_child_signal ();
+  block_child_signal (&oldset);
   sigaction (SIGCHLD, &action, &old_action);
   eassert (! (old_action.sa_flags & SA_SIGINFO));
 
@@ -7080,7 +7082,7 @@ catch_child_signal (void)
       = (old_action.sa_handler == SIG_DFL || old_action.sa_handler == SIG_IGN
         ? dummy_handler
         : old_action.sa_handler);
-  unblock_child_signal ();
+  unblock_child_signal (&oldset);
 }
 
 \f
index c3481f295f5b88d7a862d00d544ccb03da98fbef..842554bdef430f57e5611dc01848f9aa4f6ed8f0 100644 (file)
@@ -213,8 +213,8 @@ enum
 
 /* Defined in callproc.c.  */
 
-extern void block_child_signal (void);
-extern void unblock_child_signal (void);
+extern void block_child_signal (sigset_t *);
+extern void unblock_child_signal (sigset_t const *);
 extern Lisp_Object encode_current_directory (void);
 extern void record_kill_process (struct Lisp_Process *, Lisp_Object);
 
index a95678812e1a6ac12e7c06777e567bbc55652fd8..7046f4e8e3265b218aa46127b536c1a4af07ef20 100644 (file)
@@ -702,7 +702,7 @@ vox_configure (struct sound_device *sd)
 {
   int val;
 #ifdef USABLE_SIGIO
-  sigset_t blocked;
+  sigset_t oldset, blocked;
 #endif
 
   eassert (sd->fd >= 0);
@@ -714,7 +714,7 @@ vox_configure (struct sound_device *sd)
 #ifdef USABLE_SIGIO
   sigemptyset (&blocked);
   sigaddset (&blocked, SIGIO);
-  pthread_sigmask (SIG_BLOCK, &blocked, 0);
+  pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
 #endif
 
   val = sd->format;
@@ -748,7 +748,7 @@ vox_configure (struct sound_device *sd)
 
   turn_on_atimers (1);
 #ifdef USABLE_SIGIO
-  pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
+  pthread_sigmask (SIG_SETMASK, &oldset, 0);
 #endif
 }
 
@@ -764,10 +764,10 @@ vox_close (struct sound_device *sd)
         be interrupted by a signal.  Block the ones we know to cause
         troubles.  */
 #ifdef USABLE_SIGIO
-      sigset_t blocked;
+      sigset_t blocked, oldset;
       sigemptyset (&blocked);
       sigaddset (&blocked, SIGIO);
-      pthread_sigmask (SIG_BLOCK, &blocked, 0);
+      pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
 #endif
       turn_on_atimers (0);
 
@@ -776,7 +776,7 @@ vox_close (struct sound_device *sd)
 
       turn_on_atimers (1);
 #ifdef USABLE_SIGIO
-      pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
+      pthread_sigmask (SIG_SETMASK, &oldset, 0);
 #endif
 
       /* Close the device.  */
index 6ec8eecb2874d7dd5d66c47154c04ec6e36efeec..af9f4801cec9bb7ff3adef4a665c0599b24aca80 100644 (file)
@@ -692,21 +692,21 @@ init_foreground_group (void)
 /* Block and unblock SIGTTOU.  */
 
 void
-block_tty_out_signal (void)
+block_tty_out_signal (sigset_t *oldset)
 {
 #ifdef SIGTTOU
   sigset_t blocked;
   sigemptyset (&blocked);
   sigaddset (&blocked, SIGTTOU);
-  pthread_sigmask (SIG_BLOCK, &blocked, 0);
+  pthread_sigmask (SIG_BLOCK, &blocked, oldset);
 #endif
 }
 
 void
-unblock_tty_out_signal (void)
+unblock_tty_out_signal (sigset_t const *oldset)
 {
 #ifdef SIGTTOU
-  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+  pthread_sigmask (SIG_SETMASK, oldset, 0);
 #endif
 }
 
@@ -721,10 +721,11 @@ static void
 tcsetpgrp_without_stopping (int fd, pid_t pgid)
 {
 #ifdef SIGTTOU
+  sigset_t oldset;
   block_input ();
-  block_tty_out_signal ();
+  block_tty_out_signal (&oldset);
   tcsetpgrp (fd, pgid);
-  unblock_tty_out_signal ();
+  unblock_tty_out_signal (&oldset);
   unblock_input ();
 #endif
 }
@@ -1525,9 +1526,6 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
 #endif
     }
 
-  if (! IEEE_FLOATING_POINT)
-    sigaddset (&action->sa_mask, SIGFPE);
-
   action->sa_handler = handler;
   action->sa_flags = emacs_sigaction_flags ();
 }
@@ -1643,7 +1641,10 @@ deliver_fatal_thread_signal (int sig)
 static _Noreturn void
 handle_arith_signal (int sig)
 {
-  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+  sigset_t blocked;
+  sigemptyset (&blocked);
+  sigaddset (&blocked, sig);
+  pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
   xsignal0 (Qarith_error);
 }
 
index 3bcbb70aff64a16d809d1577280db650767ec331..df5fc17a0c092e8642aabb926650c209fb88d8f6 100644 (file)
@@ -3944,9 +3944,10 @@ dissociate_if_controlling_tty (int fd)
       /* setsid failed, presumably because Emacs is already a process
         group leader.  Fall back on the obsolescent way to dissociate
         a controlling tty.  */
-      block_tty_out_signal ();
+      sigset_t oldset;
+      block_tty_out_signal (&oldset);
       ioctl (fd, TIOCNOTTY, 0);
-      unblock_tty_out_signal ();
+      unblock_tty_out_signal (&oldset);
 #endif
     }
 }
@@ -3970,6 +3971,7 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
   int status;
   struct tty_display_info *tty = NULL;
   struct terminal *terminal = NULL;
+  sigset_t oldset;
   bool ctty = false;  /* True if asked to open controlling tty.  */
 
   if (!terminal_type)
@@ -4059,11 +4061,11 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
 
   /* On some systems, tgetent tries to access the controlling
      terminal.  */
-  block_tty_out_signal ();
+  block_tty_out_signal (&oldset);
   status = tgetent (tty->termcap_term_buffer, terminal_type);
   if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
     emacs_abort ();
-  unblock_tty_out_signal ();
+  unblock_tty_out_signal (&oldset);
 
   if (status < 0)
     {