Skip to content

Commit

Permalink
Add option to only install essential signal handlers
Browse files Browse the repository at this point in the history
When embedding Julia, it is useful to opt out of some of the signal
handlers (especially SIGINT). But opting out of SIGSEGV makes it very
difficult to use multiple Julia threads, since the GC safepoint
implementation relies on segv_handler().

This patch provides a third option to embedders, which installs the
essential signal handlers but skips the optional ones. It might make
sense for this to be the default when embedding, but I've kept the other
two options for backwards compatibility.
  • Loading branch information
jonathan-conder-sm committed May 28, 2023
1 parent 248ceda commit b900d67
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 37 deletions.
4 changes: 2 additions & 2 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel)
jl_init_uv();
init_stdio();
restore_fp_env();
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON)
if (jl_options.handle_signals != JL_OPTIONS_HANDLE_SIGNALS_OFF)
restore_signals();

jl_init_intrinsic_properties();
Expand Down Expand Up @@ -811,7 +811,7 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel)
jl_init_tasks();
jl_init_threading();
jl_init_threadinginfra();
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON)
if (jl_options.handle_signals != JL_OPTIONS_HANDLE_SIGNALS_OFF)
jl_install_default_signal_handlers();

jl_gc_init();
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -2287,6 +2287,7 @@ JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT;

#define JL_OPTIONS_HANDLE_SIGNALS_ON 1
#define JL_OPTIONS_HANDLE_SIGNALS_OFF 0
#define JL_OPTIONS_HANDLE_SIGNALS_ESSENTIAL 2

#define JL_OPTIONS_USE_SYSIMAGE_NATIVE_CODE_YES 1
#define JL_OPTIONS_USE_SYSIMAGE_NATIVE_CODE_NO 0
Expand Down
91 changes: 57 additions & 34 deletions src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,10 @@ void jl_install_thread_signal_handler(jl_ptls_t ptls)
}

const static int sigwait_sigs[] = {
SIGINT, SIGTERM, SIGQUIT,
SIGINT, SIGTERM, SIGQUIT, 0,
};

const static int sigwait_sigs_essential[] = {
#ifdef SIGINFO
SIGINFO,
#else
Expand All @@ -660,7 +663,11 @@ const static int sigwait_sigs[] = {
static void jl_sigsetset(sigset_t *sset)
{
sigemptyset(sset);
for (const int *sig = sigwait_sigs; *sig; sig++)
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) {
for (const int *sig = sigwait_sigs; *sig; sig++)
sigaddset(sset, *sig);
}
for (const int *sig = sigwait_sigs_essential; *sig; sig++)
sigaddset(sset, *sig);
}

Expand Down Expand Up @@ -719,11 +726,19 @@ static void *signal_listener(void *arg)
perror("signal kqueue");
}
else {
for (const int *sig = sigwait_sigs; *sig; sig++)
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) {
for (const int *sig = sigwait_sigs; *sig; sig++)
kqueue_signal(&sigqueue, &ev, *sig);
}
for (const int *sig = sigwait_sigs_essential; *sig; sig++)
kqueue_signal(&sigqueue, &ev, *sig);
if (sigqueue == -1) {
// re-enable sigwait for these
for (const int *sig = sigwait_sigs; *sig; sig++)
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) {
for (const int *sig = sigwait_sigs; *sig; sig++)
signal(*sig, SIG_DFL);
}
for (const int *sig = sigwait_sigs_essential; *sig; sig++)
signal(*sig, SIG_DFL);
}
}
Expand All @@ -742,7 +757,11 @@ static void *signal_listener(void *arg)
if (nevents != 1) {
close(sigqueue);
sigqueue = -1;
for (const int *sig = sigwait_sigs; *sig; sig++)
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) {
for (const int *sig = sigwait_sigs; *sig; sig++)
signal(*sig, SIG_DFL);
}
for (const int *sig = sigwait_sigs_essential; *sig; sig++)
signal(*sig, SIG_DFL);
continue;
}
Expand Down Expand Up @@ -996,27 +1015,29 @@ static void sigint_handler(int sig)

void jl_install_default_signal_handlers(void)
{
struct sigaction actf;
memset(&actf, 0, sizeof(struct sigaction));
sigemptyset(&actf.sa_mask);
actf.sa_sigaction = fpe_handler;
actf.sa_flags = SA_ONSTACK | SA_SIGINFO;
if (sigaction(SIGFPE, &actf, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
struct sigaction actint;
memset(&actint, 0, sizeof(struct sigaction));
sigemptyset(&actint.sa_mask);
actint.sa_handler = sigint_handler;
actint.sa_flags = 0;
if (sigaction(SIGINT, &actint, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGPIPE");
}
if (signal(SIGTRAP, SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGTRAP");
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) {
struct sigaction actf;
memset(&actf, 0, sizeof(struct sigaction));
sigemptyset(&actf.sa_mask);
actf.sa_sigaction = fpe_handler;
actf.sa_flags = SA_ONSTACK | SA_SIGINFO;
if (sigaction(SIGFPE, &actf, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
struct sigaction actint;
memset(&actint, 0, sizeof(struct sigaction));
sigemptyset(&actint.sa_mask);
actint.sa_handler = sigint_handler;
actint.sa_flags = 0;
if (sigaction(SIGINT, &actint, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGPIPE");
}
if (signal(SIGTRAP, SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGTRAP");
}
}

#if defined(HAVE_MACH)
Expand All @@ -1039,14 +1060,16 @@ void jl_install_default_signal_handlers(void)
sigemptyset(&act_die.sa_mask);
act_die.sa_sigaction = sigdie_handler;
act_die.sa_flags = SA_SIGINFO | SA_RESETHAND;
if (sigaction(SIGILL, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGABRT, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGSYS, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) {
if (sigaction(SIGILL, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGABRT, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGSYS, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
}
// need to ensure the following signals are not SIG_IGN, even though they will be blocked
act_die.sa_flags = SA_SIGINFO | SA_RESTART | SA_RESETHAND;
Expand Down
2 changes: 1 addition & 1 deletion src/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -1719,7 +1719,7 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi)
}
#endif

if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON)
if (jl_options.handle_signals != JL_OPTIONS_HANDLE_SIGNALS_OFF)
jl_install_thread_signal_handler(ptls);

return ct;
Expand Down

0 comments on commit b900d67

Please sign in to comment.