@@ -467,12 +467,24 @@ _dispatch_event_merge_signal(dispatch_muxnote_t dmn)
467
467
{
468
468
dispatch_unote_linkage_t dul , dul_next ;
469
469
struct signalfd_siginfo si ;
470
-
471
- dispatch_assume (read (dmn -> dmn_fd , & si , sizeof (si )) == sizeof (si ));
472
-
473
- TAILQ_FOREACH_SAFE (dul , & dmn -> dmn_readers_head , du_link , dul_next ) {
474
- dispatch_unote_t du = _dispatch_unote_linkage_get_unote (dul );
475
- dux_merge_evt (du ._du , EV_ADD |EV_ENABLE |EV_CLEAR , 1 , 0 , 0 );
470
+ ssize_t rc ;
471
+
472
+ // Linux has the weirdest semantics around signals: if it finds a thread
473
+ // that has not masked a process wide-signal, it may deliver it to this
474
+ // thread, meaning that the signalfd may have been made readable, but the
475
+ // signal consumed through the legacy delivery mechanism.
476
+ //
477
+ // Because of this we can get a misfire of the signalfd yielding EAGAIN the
478
+ // first time around. The _dispatch_muxnote_signal_block_and_raise() hack
479
+ // will kick in, the thread with the wrong mask will be fixed up, and the
480
+ // signal delivered to us again properly.
481
+ if ((rc = read (dmn -> dmn_fd , & si , sizeof (si ))) == sizeof (si )) {
482
+ TAILQ_FOREACH_SAFE (dul , & dmn -> dmn_readers_head , du_link , dul_next ) {
483
+ dispatch_unote_t du = _dispatch_unote_linkage_get_unote (dul );
484
+ dux_merge_evt (du ._du , EV_ADD |EV_ENABLE |EV_CLEAR , 1 , 0 , 0 );
485
+ }
486
+ } else {
487
+ dispatch_assume (rc == -1 && errno == EAGAIN );
476
488
}
477
489
}
478
490
0 commit comments