Skip to content

SR-4201: DispatchSourceSignal not working on Linux #231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/event/event_epoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,28 @@ _dispatch_muxnote_dispose(dispatch_muxnote_t dmn)
free(dmn);
}

static pthread_t manager_thread;

static void
_dispatch_muxnote_signal_block_and_raise(int signo)
{
// On linux, for signals to be delivered to the signalfd, signals
// must be blocked, else any thread that hasn't them blocked may
// receive them. Fix that by lazily noticing, blocking said signal,
// and raising the signal again when it happens
_dispatch_sigmask();
pthread_kill(manager_thread, signo);
}

static dispatch_muxnote_t
_dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
{
static sigset_t signals_with_unotes;
static struct sigaction sa = {
.sa_handler = _dispatch_muxnote_signal_block_and_raise,
.sa_flags = SA_RESTART,
};

dispatch_muxnote_t dmn;
struct stat sb;
int fd = du._du->du_ident;
Expand All @@ -129,13 +148,17 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)

switch (filter) {
case EVFILT_SIGNAL:
if (!sigismember(&signals_with_unotes, du._du->du_ident)) {
manager_thread = pthread_self();
sigaddset(&signals_with_unotes, du._du->du_ident);
sigaction(du._du->du_ident, &sa, NULL);
}
sigemptyset(&sigmask);
sigaddset(&sigmask, du._du->du_ident);
fd = signalfd(-1, &sigmask, SFD_NONBLOCK | SFD_CLOEXEC);
if (fd < 0) {
return NULL;
}
sigprocmask(SIG_BLOCK, &sigmask, NULL);
break;

case EVFILT_WRITE:
Expand Down
23 changes: 23 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,29 @@ dispatch_atfork_child(void)
_dispatch_unsafe_fork = 0;
}

int
_dispatch_sigmask(void)
{
sigset_t mask;
int r = 0;

/* Workaround: 6269619 Not all signals can be delivered on any thread */
r |= sigfillset(&mask);
r |= sigdelset(&mask, SIGILL);
r |= sigdelset(&mask, SIGTRAP);
#if HAVE_DECL_SIGEMT
r |= sigdelset(&mask, SIGEMT);
#endif
r |= sigdelset(&mask, SIGFPE);
r |= sigdelset(&mask, SIGBUS);
r |= sigdelset(&mask, SIGSEGV);
r |= sigdelset(&mask, SIGSYS);
r |= sigdelset(&mask, SIGPIPE);
r |= sigdelset(&mask, SIGPROF);
r |= pthread_sigmask(SIG_BLOCK, &mask, NULL);
(void)dispatch_assume_zero(r);
}

#pragma mark -
#pragma mark dispatch_globals

Expand Down
2 changes: 2 additions & 0 deletions src/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,8 @@ extern int _dispatch_evfilt_machport_direct_enabled;
#endif // DISPATCH_USE_EVFILT_MACHPORT_DIRECT


int _dispatch_sigmask(void);

/* #includes dependent on internal.h */
#include "object_internal.h"
#include "semaphore_internal.h"
Expand Down
40 changes: 2 additions & 38 deletions src/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ static void _dispatch_worker_thread2(int priority, int options, void *context);
#endif
#if DISPATCH_USE_PTHREAD_POOL
static void *_dispatch_worker_thread(void *context);
static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset);
#endif

#if DISPATCH_COCOA_COMPAT
Expand Down Expand Up @@ -5466,13 +5465,8 @@ _dispatch_worker_thread(void *context)
pqc->dpq_thread_configure();
}

sigset_t mask;
int r;
// workaround tweaks the kernel workqueue does for us
r = sigfillset(&mask);
(void)dispatch_assume_zero(r);
r = _dispatch_pthread_sigmask(SIG_BLOCK, &mask, NULL);
(void)dispatch_assume_zero(r);
_dispatch_sigmask();
_dispatch_introspection_thread_add();

const int64_t timeout = 5ull * NSEC_PER_SEC;
Expand All @@ -5489,37 +5483,6 @@ _dispatch_worker_thread(void *context)

return NULL;
}

int
_dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset)
{
int r;

/* Workaround: 6269619 Not all signals can be delivered on any thread */

r = sigdelset(set, SIGILL);
(void)dispatch_assume_zero(r);
r = sigdelset(set, SIGTRAP);
(void)dispatch_assume_zero(r);
#if HAVE_DECL_SIGEMT
r = sigdelset(set, SIGEMT);
(void)dispatch_assume_zero(r);
#endif
r = sigdelset(set, SIGFPE);
(void)dispatch_assume_zero(r);
r = sigdelset(set, SIGBUS);
(void)dispatch_assume_zero(r);
r = sigdelset(set, SIGSEGV);
(void)dispatch_assume_zero(r);
r = sigdelset(set, SIGSYS);
(void)dispatch_assume_zero(r);
r = sigdelset(set, SIGPIPE);
(void)dispatch_assume_zero(r);
r = sigdelset(set, SIGPROF);
(void)dispatch_assume_zero(r);

return pthread_sigmask(how, set, oset);
}
#endif // DISPATCH_USE_PTHREAD_POOL

#pragma mark -
Expand Down Expand Up @@ -5749,6 +5712,7 @@ dispatch_main(void)
pthread_key_t dispatch_main_key;
pthread_key_create(&dispatch_main_key, _dispatch_sig_thread);
pthread_setspecific(dispatch_main_key, &dispatch_main_key);
_dispatch_sigmask();
#endif
pthread_exit(NULL);
DISPATCH_INTERNAL_CRASH(errno, "pthread_exit() returned");
Expand Down