mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-26 19:18:50 +00:00
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.
This commit is contained in:
parent
a4e6c042f8
commit
20ef56dbc8
@ -1,3 +1,53 @@
|
||||
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.
|
||||
|
24
src/atimer.c
24
src/atimer.c
@ -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);
|
||||
}
|
||||
|
17
src/data.c
17
src/data.c
@ -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. */
|
||||
|
98
src/emacs.c
98
src/emacs.c
@ -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
|
||||
|
262
src/process.c
262
src/process.c
@ -124,6 +124,14 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#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 @@ get_process (register Lisp_Object name)
|
||||
#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 @@ nil, indicating the current buffer's process. */)
|
||||
#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 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
|
||||
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 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
||||
|
||||
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 @@ read_process_output (Lisp_Object proc, register int channel)
|
||||
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_process (volatile Lisp_Object proc, const char *volatile buf,
|
||||
/* 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 @@ process has been transmitted to the serial port. */)
|
||||
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;
|
||||
pid_t pid;
|
||||
int w;
|
||||
Lisp_Object tail;
|
||||
|
||||
SIGNAL_THREAD_CHECK (signo);
|
||||
do
|
||||
pid = waitpid (-1, &w, WNOHANG | WUNTRACED);
|
||||
while (pid < 0 && errno == EINTR);
|
||||
|
||||
while (1)
|
||||
/* 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))
|
||||
{
|
||||
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
|
||||
Lisp_Object xpid = XCAR (tail);
|
||||
if ((INTEGERP (xpid) && pid == XINT (xpid))
|
||||
|| (FLOATP (xpid) && pid == XFLOAT_DATA (xpid)))
|
||||
{
|
||||
errno = 0;
|
||||
pid = waitpid (-1, &w, WNOHANG | WUNTRACED);
|
||||
XSETCAR (tail, Qnil);
|
||||
return true;
|
||||
}
|
||||
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. */
|
||||
/* 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))
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
proc = XCDR (XCAR (tail));
|
||||
p = XPROCESS (proc);
|
||||
if (EQ (p->type, Qreal) && p->pid == pid)
|
||||
break;
|
||||
p = 0;
|
||||
FD_CLR (p->infd, &input_wait_mask);
|
||||
FD_CLR (p->infd, &non_keyboard_wait_mask);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
/* Change the status of the process that was found. */
|
||||
if (p != 0)
|
||||
{
|
||||
int clear_desc_flag = 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);
|
||||
|
||||
p->tick = ++process_tick;
|
||||
p->raw_status = w;
|
||||
p->raw_status_new = 1;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* If process has terminated, stop waiting for its output. */
|
||||
if ((WIFSIGNALED (w) || WIFEXITED (w))
|
||||
&& p->infd >= 0)
|
||||
clear_desc_flag = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
/* 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 @@ init_process_emacs (void)
|
||||
#ifndef CANNOT_DUMP
|
||||
if (! noninteractive || initialized)
|
||||
#endif
|
||||
signal (SIGCHLD, sigchld_handler);
|
||||
signal (SIGCHLD, deliver_child_signal);
|
||||
#endif
|
||||
|
||||
FD_ZERO (&input_wait_mask);
|
||||
|
38
src/sysdep.c
38
src/sysdep.c
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user