Commit 20ef56db authored by Paul Eggert's avatar Paul Eggert

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.
parent a4e6c042
2012-09-05 Paul Eggert <eggert@cs.ucla.edu>
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 <dmantipov@yandex.ru>
Remove redundant or unused things here and there.
......
......@@ -41,7 +41,7 @@ static struct atimer *stopped_atimers;
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 set_alarm (void);
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 @@ run_timers (void)
/* 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 @@ alarm_signal_handler (int signo)
#endif
}
static void
deliver_alarm_signal (int sig)
{
handle_on_main_thread (sig, handle_alarm_signal);
}
/* Call alarm_signal_handler for pending timers. */
/* Call alarm signal handler for pending timers. */
void
do_pending_atimers (void)
......@@ -412,7 +412,7 @@ turn_on_atimers (bool on)
{
if (on)
{
signal (SIGALRM, alarm_signal_handler);
signal (SIGALRM, deliver_alarm_signal);
set_alarm ();
}
else
......@@ -426,5 +426,5 @@ init_atimer (void)
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);
}
......@@ -3207,18 +3207,19 @@ syms_of_data (void)
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 @@ init_data (void)
if (!initialized)
return;
#endif /* CANNOT_DUMP */
signal (SIGFPE, arith_error);
signal (SIGFPE, deliver_arith_signal);
}
......@@ -5552,17 +5552,15 @@ marginal_area_string (struct window *w, enum window_part part,
#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 @@ window_change_signal (int signalnum) /* If we don't have an argument, */
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 @@ window_change_signal (int signalnum) /* If we don't have an argument, */
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 @@ init_display (void)
#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. */
......
......@@ -275,14 +275,6 @@ static int fatal_error_code;
/* 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 @@ static void *ns_pool;
/* 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 @@ fatal_error_backtrace (int sig, int backtrace_limit)
#ifdef SIGDANGER
/* Handler for SIGDANGER. */
void
memory_warning_signal (int sig)
{
signal (sig, memory_warning_signal);
SIGNAL_THREAD_CHECK (sig);
static void deliver_danger_signal (int);
static void
handle_danger_signal (int 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 @@ main (int argc, char **argv)
# 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 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
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 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
/* 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 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
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 */
}
......
......@@ -37,9 +37,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
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 @@ extern double logb (double);
# 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 @@ Rounds the value toward zero. */)
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 @@ matherr (struct exception *x)
void
init_floatfns (void)
{
#ifdef FLOAT_CATCH_SIGILL
signal (SIGILL, float_error);
#endif
in_float = 0;
}
......
......@@ -449,9 +449,8 @@ static void restore_getcjmp (jmp_buf);
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 process_special_events (void);
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 @@ kbd_buffer_get_event (KBOARD **kbp,
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 @@ process_pending_signals (void)
/* 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 @@ input_available_signal (int signo)
#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 @@ add_user_signal (int sig, const char *name)
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 @@ handle_user_signal (int sig)
}
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 @@ clear_waiting_for_input (void)
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,10 +10800,15 @@ interrupt_signal (int signalnum) /* If we don't have an argument, some */
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
enough times, then quit anyway. See bug#6585. */
......@@ -11404,17 +11402,17 @@ init_keyboard (void)
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
......
......@@ -3256,9 +3256,6 @@ extern bool display_arg;
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
......
This diff is collapsed.
......@@ -1551,6 +1551,40 @@ sys_sigsetmask (sigset_t new_mask)
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 @@ init_signals (void)
{
sigemptyset (&empty_mask);
#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
main_thread = pthread_self ();
#endif
#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST
if (! initialized)
{
......
......@@ -133,24 +133,5 @@ char *strsignal (int);
#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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment