diff --git a/src/signal-handling.c b/src/signal-handling.c index 5838edb6a584d..78968c05ed91e 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -53,12 +53,32 @@ static int jl_check_force_sigint(void) return 0; } -// Force sigint requires pressing `Ctrl-C` repeatedly. -// Ignore sigint for a short time after that to avoid rethrowing sigint too -// quickly again. (Code that has this issue is inherently racy but this is -// an interactive feature anyway.) +#ifndef _OS_WINDOWS_ +// Not thread local, should only be accessed by the signal handler thread. +static volatile int jl_sigint_passed = 0; +static sigset_t jl_sigint_sset; +#endif + static int jl_ignore_sigint(void) { + // On Unix, we get the SIGINT before the debugger which makes it very + // hard to interrupt a running process in the debugger with `Ctrl-C`. + // Manually raise a `SIGINT` on current thread with the signal temporarily + // unblocked and use it's behavior to decide if we need to handle the signal. +#ifndef _OS_WINDOWS_ + jl_sigint_passed = 0; + pthread_sigmask(SIG_UNBLOCK, &jl_sigint_sset, NULL); + // This can swallow an external `SIGINT` but it's not an issue + // since we don't deliver the same number of signals anyway. + pthread_kill(pthread_self(), SIGINT); + pthread_sigmask(SIG_BLOCK, &jl_sigint_sset, NULL); + if (!jl_sigint_passed) + return 1; +#endif + // Force sigint requires pressing `Ctrl-C` repeatedly. + // Ignore sigint for a short time after that to avoid rethrowing sigint too + // quickly again. (Code that has this issue is inherently racy but this is + // an interactive feature anyway.) return jl_disable_sigint_time && jl_disable_sigint_time > uv_hrtime(); } diff --git a/src/signals-unix.c b/src/signals-unix.c index f9cea3354e1cb..64d38f2942c89 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -519,12 +519,14 @@ static void *signal_listener(void *arg) # endif #endif if (sig == SIGINT) { - if (exit_on_sigint) { + if (jl_ignore_sigint()) { + continue; + } + else if (exit_on_sigint) { critical = 1; } else { - if (!jl_ignore_sigint()) - jl_try_deliver_sigint(); + jl_try_deliver_sigint(); continue; } } @@ -600,6 +602,9 @@ static void *signal_listener(void *arg) void restore_signals(void) { + sigemptyset(&jl_sigint_sset); + sigaddset(&jl_sigint_sset, SIGINT); + sigset_t sset; jl_sigsetset(&sset); sigprocmask(SIG_SETMASK, &sset, 0); @@ -625,6 +630,11 @@ void fpe_handler(int sig, siginfo_t *info, void *context) jl_throw_in_ctx(ptls, jl_diverror_exception, context); } +void sigint_handler(int sig) +{ + jl_sigint_passed = 1; +} + void jl_install_default_signal_handlers(void) { struct sigaction actf; @@ -635,6 +645,14 @@ void jl_install_default_signal_handlers(void) 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"); } diff --git a/src/signals-win.c b/src/signals-win.c index 5388ac33aadf7..c8901e153ef3c 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -79,10 +79,11 @@ void __cdecl crt_sig_handler(int sig, int num) break; case SIGINT: signal(SIGINT, (void (__cdecl *)(int))crt_sig_handler); - if (exit_on_sigint) - jl_exit(130); // 128 + SIGINT - if (!jl_ignore_sigint()) + if (!jl_ignore_sigint()) { + if (exit_on_sigint) + jl_exit(130); // 128 + SIGINT jl_try_throw_sigint(); + } break; default: // SIGSEGV, (SSIGTERM, IGILL) memset(&Context, 0, sizeof(Context)); @@ -179,10 +180,11 @@ static BOOL WINAPI sigint_handler(DWORD wsig) //This needs winapi types to guara // etc. default: sig = SIGTERM; break; } - if (exit_on_sigint) - jl_exit(128 + sig); // 128 + SIGINT - if (!jl_ignore_sigint()) + if (!jl_ignore_sigint()) { + if (exit_on_sigint) + jl_exit(128 + sig); // 128 + SIGINT jl_try_deliver_sigint(); + } return 1; }