Skip to content

Commit 62741ca

Browse files
committed
SR-4201: DispatchSourceSignal not working on Linux
The observed bug is that signals sent to the main thread after it called dispatch_main were not triggering the event handler of a DispatchSourceSignal that had been previously created and activated to handle that signal. This patch addresses the problem by: - export _dispatch_sigmask() as the way to block signals in a process using dispatch - call it when dispatch_main() is called - each time dispatch registers a signal handler, register a sigaction that will catch signals for threads with wrong masks and will fix the thread configuration then raise the signal again by directing a pthread_kill to the manager thread so that it is delivered to the signalfd as expected. Patch by Pierre Habouzit <phabouzit@apple.com> from PR-231 with minor compilation fixes by Dave Grove.
1 parent 7ca0a63 commit 62741ca

File tree

4 files changed

+51
-39
lines changed

4 files changed

+51
-39
lines changed

src/event/event_epoll.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,28 @@ _dispatch_muxnote_dispose(dispatch_muxnote_t dmn)
117117
free(dmn);
118118
}
119119

120+
static pthread_t manager_thread;
121+
122+
static void
123+
_dispatch_muxnote_signal_block_and_raise(int signo)
124+
{
125+
// On linux, for signals to be delivered to the signalfd, signals
126+
// must be blocked, else any thread that hasn't them blocked may
127+
// receive them. Fix that by lazily noticing, blocking said signal,
128+
// and raising the signal again when it happens
129+
_dispatch_sigmask();
130+
pthread_kill(manager_thread, signo);
131+
}
132+
120133
static dispatch_muxnote_t
121134
_dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
122135
{
136+
static sigset_t signals_with_unotes;
137+
static struct sigaction sa = {
138+
.sa_handler = _dispatch_muxnote_signal_block_and_raise,
139+
.sa_flags = SA_RESTART,
140+
};
141+
123142
dispatch_muxnote_t dmn;
124143
struct stat sb;
125144
int fd = du._du->du_ident;
@@ -129,13 +148,17 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
129148

130149
switch (filter) {
131150
case EVFILT_SIGNAL:
151+
if (!sigismember(&signals_with_unotes, du._du->du_ident)) {
152+
manager_thread = pthread_self();
153+
sigaddset(&signals_with_unotes, du._du->du_ident);
154+
sigaction(du._du->du_ident, &sa, NULL);
155+
}
132156
sigemptyset(&sigmask);
133157
sigaddset(&sigmask, du._du->du_ident);
134158
fd = signalfd(-1, &sigmask, SFD_NONBLOCK | SFD_CLOEXEC);
135159
if (fd < 0) {
136160
return NULL;
137161
}
138-
sigprocmask(SIG_BLOCK, &sigmask, NULL);
139162
break;
140163

141164
case EVFILT_WRITE:

src/init.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,29 @@ dispatch_atfork_child(void)
7272
_dispatch_unsafe_fork = 0;
7373
}
7474

75+
int
76+
_dispatch_sigmask(void)
77+
{
78+
sigset_t mask;
79+
int r = 0;
80+
81+
/* Workaround: 6269619 Not all signals can be delivered on any thread */
82+
r |= sigfillset(&mask);
83+
r |= sigdelset(&mask, SIGILL);
84+
r |= sigdelset(&mask, SIGTRAP);
85+
#if HAVE_DECL_SIGEMT
86+
r |= sigdelset(&mask, SIGEMT);
87+
#endif
88+
r |= sigdelset(&mask, SIGFPE);
89+
r |= sigdelset(&mask, SIGBUS);
90+
r |= sigdelset(&mask, SIGSEGV);
91+
r |= sigdelset(&mask, SIGSYS);
92+
r |= sigdelset(&mask, SIGPIPE);
93+
r |= sigdelset(&mask, SIGPROF);
94+
r |= pthread_sigmask(SIG_BLOCK, &mask, NULL);
95+
(void)dispatch_assume_zero(r);
96+
}
97+
7598
#pragma mark -
7699
#pragma mark dispatch_globals
77100

src/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,8 @@ extern int _dispatch_evfilt_machport_direct_enabled;
990990
#endif // DISPATCH_USE_EVFILT_MACHPORT_DIRECT
991991

992992

993+
int _dispatch_sigmask(void);
994+
993995
/* #includes dependent on internal.h */
994996
#include "object_internal.h"
995997
#include "semaphore_internal.h"

src/queue.c

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ static void _dispatch_worker_thread2(int priority, int options, void *context);
6666
#endif
6767
#if DISPATCH_USE_PTHREAD_POOL
6868
static void *_dispatch_worker_thread(void *context);
69-
static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset);
7069
#endif
7170

7271
#if DISPATCH_COCOA_COMPAT
@@ -5466,13 +5465,8 @@ _dispatch_worker_thread(void *context)
54665465
pqc->dpq_thread_configure();
54675466
}
54685467

5469-
sigset_t mask;
5470-
int r;
54715468
// workaround tweaks the kernel workqueue does for us
5472-
r = sigfillset(&mask);
5473-
(void)dispatch_assume_zero(r);
5474-
r = _dispatch_pthread_sigmask(SIG_BLOCK, &mask, NULL);
5475-
(void)dispatch_assume_zero(r);
5469+
_dispatch_sigmask();
54765470
_dispatch_introspection_thread_add();
54775471

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

54905484
return NULL;
54915485
}
5492-
5493-
int
5494-
_dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset)
5495-
{
5496-
int r;
5497-
5498-
/* Workaround: 6269619 Not all signals can be delivered on any thread */
5499-
5500-
r = sigdelset(set, SIGILL);
5501-
(void)dispatch_assume_zero(r);
5502-
r = sigdelset(set, SIGTRAP);
5503-
(void)dispatch_assume_zero(r);
5504-
#if HAVE_DECL_SIGEMT
5505-
r = sigdelset(set, SIGEMT);
5506-
(void)dispatch_assume_zero(r);
5507-
#endif
5508-
r = sigdelset(set, SIGFPE);
5509-
(void)dispatch_assume_zero(r);
5510-
r = sigdelset(set, SIGBUS);
5511-
(void)dispatch_assume_zero(r);
5512-
r = sigdelset(set, SIGSEGV);
5513-
(void)dispatch_assume_zero(r);
5514-
r = sigdelset(set, SIGSYS);
5515-
(void)dispatch_assume_zero(r);
5516-
r = sigdelset(set, SIGPIPE);
5517-
(void)dispatch_assume_zero(r);
5518-
r = sigdelset(set, SIGPROF);
5519-
(void)dispatch_assume_zero(r);
5520-
5521-
return pthread_sigmask(how, set, oset);
5522-
}
55235486
#endif // DISPATCH_USE_PTHREAD_POOL
55245487

55255488
#pragma mark -
@@ -5749,6 +5712,7 @@ dispatch_main(void)
57495712
pthread_key_t dispatch_main_key;
57505713
pthread_key_create(&dispatch_main_key, _dispatch_sig_thread);
57515714
pthread_setspecific(dispatch_main_key, &dispatch_main_key);
5715+
_dispatch_sigmask();
57525716
#endif
57535717
pthread_exit(NULL);
57545718
DISPATCH_INTERNAL_CRASH(errno, "pthread_exit() returned");

0 commit comments

Comments
 (0)