Skip to content

Commit 6a54c47

Browse files
MadCoderdas
authored andcommitted
Fix improper double-fire of signal sources on Linux
Signed-off-by: Daniel A. Steffen <dsteffen@apple.com>
1 parent cfdc94d commit 6a54c47

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

src/event/event_epoll.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -474,12 +474,24 @@ _dispatch_event_merge_signal(dispatch_muxnote_t dmn)
474474
{
475475
dispatch_unote_linkage_t dul, dul_next;
476476
struct signalfd_siginfo si;
477-
478-
dispatch_assume(read(dmn->dmn_fd, &si, sizeof(si)) == sizeof(si));
479-
480-
TAILQ_FOREACH_SAFE(dul, &dmn->dmn_readers_head, du_link, dul_next) {
481-
dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul);
482-
dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_CLEAR, 1, 0, 0);
477+
ssize_t rc;
478+
479+
// Linux has the weirdest semantics around signals: if it finds a thread
480+
// that has not masked a process wide-signal, it may deliver it to this
481+
// thread, meaning that the signalfd may have been made readable, but the
482+
// signal consumed through the legacy delivery mechanism.
483+
//
484+
// Because of this we can get a misfire of the signalfd yielding EAGAIN the
485+
// first time around. The _dispatch_muxnote_signal_block_and_raise() hack
486+
// will kick in, the thread with the wrong mask will be fixed up, and the
487+
// signal delivered to us again properly.
488+
if ((rc = read(dmn->dmn_fd, &si, sizeof(si))) == sizeof(si)) {
489+
TAILQ_FOREACH_SAFE(dul, &dmn->dmn_readers_head, du_link, dul_next) {
490+
dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul);
491+
dux_merge_evt(du._du, EV_ADD|EV_ENABLE|EV_CLEAR, 1, 0, 0);
492+
}
493+
} else {
494+
dispatch_assume(rc == -1 && errno == EAGAIN);
483495
}
484496
}
485497

0 commit comments

Comments
 (0)