@@ -474,12 +474,24 @@ _dispatch_event_merge_signal(dispatch_muxnote_t dmn)
474
474
{
475
475
dispatch_unote_linkage_t dul , dul_next ;
476
476
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 );
483
495
}
484
496
}
485
497
0 commit comments