Skip to content

Commit

Permalink
mach: use signal kqueue instead of sigwait (JuliaLang#22041)
Browse files Browse the repository at this point in the history
this may help avoid getting spurious sigwait notifications
  • Loading branch information
vtjnash committed Mar 6, 2018
1 parent 2f826b5 commit e542b28
Showing 1 changed file with 66 additions and 5 deletions.
71 changes: 66 additions & 5 deletions src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@
// Figure out the best signals/timers to use for this platform
#ifdef __APPLE__ // Darwin's mach ports allow signal-free thread management
#define HAVE_MACH
#define HAVE_KEVENT
#elif defined(__FreeBSD__) // generic bsd
#define HAVE_ITIMER
#define HAVE_KEVENT
#else // generic linux
#define HAVE_TIMER
#endif

#ifdef HAVE_KEVENT
#include <sys/event.h>
#endif

// 8M signal stack, same as default stack size and enough
// for reasonable finalizers.
// Should also be enough for parallel GC when we have it =)
Expand Down Expand Up @@ -174,7 +180,7 @@ static int is_addr_on_stack(jl_ptls_t ptls, void *addr)
#endif
}

void sigdie_handler(int sig, siginfo_t *info, void *context)
static void sigdie_handler(int sig, siginfo_t *info, void *context)
{
jl_ptls_t ptls = jl_get_ptls_states();
sigset_t sset;
Expand Down Expand Up @@ -511,7 +517,7 @@ void jl_install_thread_signal_handler(jl_ptls_t ptls)
ptls->signal_stack = signal_stack;
}

void jl_sigsetset(sigset_t *sset)
static void jl_sigsetset(sigset_t *sset)
{
sigemptyset(sset);
sigaddset(sset, SIGINT);
Expand All @@ -528,21 +534,76 @@ void jl_sigsetset(sigset_t *sset)
#endif
}

#ifdef HAVE_KEVENT
static void kqueue_signal(int *sigqueue, struct kevent *ev, int sig)
{
if (*sigqueue == -1)
return;
EV_SET(ev, sig, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
if (kevent(*sigqueue, ev, 1, NULL, 0, NULL)) {
perror("signal kevent");
close(*sigqueue);
*sigqueue = -1;
}
else {
signal(sig, SIG_IGN);
}
}
#endif

static void *signal_listener(void *arg)
{
static uintptr_t bt_data[JL_MAX_BT_SIZE + 1];
static size_t bt_size = 0;
sigset_t sset;
int sig, critical, profile;
jl_sigsetset(&sset);
#ifdef HAVE_KEVENT
struct kevent ev;
int sigqueue = kqueue();
if (sigqueue == -1) {
perror("signal kqueue");
}
else {
kqueue_signal(&sigqueue, &ev, SIGINT);
kqueue_signal(&sigqueue, &ev, SIGTERM);
kqueue_signal(&sigqueue, &ev, SIGABRT);
kqueue_signal(&sigqueue, &ev, SIGQUIT);
#ifdef SIGINFO
kqueue_signal(&sigqueue, &ev, SIGINFO);
#else
kqueue_signal(&sigqueue, &ev, SIGUSR1);
#endif
#ifdef HAVE_ITIMER
kqueue_signal(&sigqueue, &ev, SIGPROF);
#endif
}
#endif
while (1) {
profile = 0;
sig = 0;
errno = 0;
#ifdef HAVE_KEVENT
if (sigqueue != -1) {
int nevents = kevent(sigqueue, NULL, 0, &ev, 1, NULL);
if (nevents == -1) {
if (errno == EINTR)
continue;
perror("signal kevent");
}
if (nevents != 1) {
close(sigqueue);
sigqueue = -1;
continue;
}
sig = ev.ident;
}
else
#endif
if (sigwait(&sset, &sig)) {
sig = SIGABRT; // this branch can't occur, unless we had stack memory corruption of sset
}
if (!sig || errno == EINTR) {
else if (!sig || errno == EINTR) {
// This should never happen, but it has been observed to occur
// when this thread gets used to handle run a signal handler (without SA_RESTART).
// It would be nice to prohibit the kernel from doing that, by blocking signals on this thread,
Expand Down Expand Up @@ -668,15 +729,15 @@ void restore_signals(void)
}
}

void fpe_handler(int sig, siginfo_t *info, void *context)
static void fpe_handler(int sig, siginfo_t *info, void *context)
{
(void)info;
jl_ptls_t ptls = jl_get_ptls_states();
jl_unblock_signal(sig);
jl_throw_in_ctx(ptls, jl_diverror_exception, context);
}

void sigint_handler(int sig)
static void sigint_handler(int sig)
{
jl_sigint_passed = 1;
}
Expand Down

0 comments on commit e542b28

Please sign in to comment.