Handle sigmask better with nested signal handlers.
* 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
This commit is contained in:
parent
1edb4a2ec6
commit
1e952f0a7a
10 changed files with 91 additions and 62 deletions
|
@ -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
|
||||
|
|
38
src/atimer.c
38
src/atimer.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
12
src/sound.c
12
src/sound.c
|
@ -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. */
|
||||
|
|
21
src/sysdep.c
21
src/sysdep.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
10
src/term.c
10
src/term.c
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue