Skip to content

Commit 796a77b

Browse files
committed
Handle absence of EVFILT_USER with kevent backend.
Some kqueue implementations do not have EVFILT_USER. We can work around this by creating a timer implementation with a very small timeout.[1] [1] Thanks to this post, which provided the idea for the workaround: https://lists.macosforge.org/pipermail/libdispatch-dev/2009-September/000010.html
1 parent a2f7b07 commit 796a77b

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

src/event/event_kevent.c

+36
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ _evfiltstr(short filt)
104104
#ifdef EVFILT_FS
105105
_evfilt2(EVFILT_FS);
106106
#endif
107+
#ifdef EVFILT_USER
107108
_evfilt2(EVFILT_USER);
109+
#endif
108110
#ifdef EVFILT_SOCK
109111
_evfilt2(EVFILT_SOCK);
110112
#endif
@@ -532,11 +534,17 @@ _dispatch_kevent_merge_muxed(dispatch_kevent_t ke)
532534
}
533535
}
534536

537+
#define DISPATCH_KEVENT_ERSATZ_EVFILT_USER_MASK 0xfffffe00
538+
535539
DISPATCH_NOINLINE
536540
static void
537541
_dispatch_kevent_drain(dispatch_kevent_t ke)
538542
{
543+
#ifdef EVFILT_USER
539544
if (ke->filter == EVFILT_USER) {
545+
#else
546+
if (ke->filter == EVFILT_TIMER && ke->ident == DISPATCH_KEVENT_ERSATZ_EVFILT_USER_MASK) {
547+
#endif
540548
_dispatch_kevent_mgr_debug("received", ke);
541549
return;
542550
}
@@ -583,10 +591,17 @@ static void
583591
_dispatch_kq_create(intptr_t *fd_ptr)
584592
{
585593
static const dispatch_kevent_s kev = {
594+
#ifdef EVFILT_USER
586595
.ident = 1,
587596
.filter = EVFILT_USER,
588597
.flags = EV_ADD|EV_CLEAR,
589598
.udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER,
599+
#else
600+
.ident = DISPATCH_KEVENT_ERSATZ_EVFILT_USER_MASK,
601+
.filter = EVFILT_TIMER,
602+
.flags = EV_ADD|EV_DISABLE,
603+
.data = 1,
604+
#endif
590605
};
591606
int kqfd;
592607

@@ -730,6 +745,10 @@ _dispatch_kq_poll(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n,
730745
(void)avail;
731746
const struct timespec timeout_immediately = {}, *timeout = NULL;
732747
if (flags & KEVENT_FLAG_IMMEDIATE) timeout = &timeout_immediately;
748+
#ifdef EVFILT_USER
749+
const struct timespec timeout_1ms = {.tv_sec = 0, .tv_nsec = 1000000}
750+
if (ke.ident == DISPATCH_KEVENT_ERSATZ_EVFILT_USER_MASK) timeout = &timeout_1ms;
751+
#endif
733752
r = kevent(kqfd, ke, n, ke_out, n_out, timeout);
734753
#endif
735754
#if DISPATCH_USE_KEVENT_WORKLOOP
@@ -789,9 +808,15 @@ _dispatch_kq_drain(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n,
789808

790809
#if DISPATCH_DEBUG
791810
for (r = 0; r < n; r++) {
811+
#ifdef EVFILT_USER
792812
if (ke[r].filter != EVFILT_USER || DISPATCH_MGR_QUEUE_DEBUG) {
793813
_dispatch_kevent_debug_n(NULL, ke + r, r, n);
794814
}
815+
#else
816+
if (DISPATCH_MGR_QUEUE_DEBUG) {
817+
_dispatch_kevent_debug_n(NULL, ke + r, r, n);
818+
}
819+
#endif
795820
}
796821
#endif
797822

@@ -923,9 +948,13 @@ _dispatch_kq_deferred_update(dispatch_wlh_t wlh, dispatch_kevent_t ke)
923948
ke->udata);
924949
dispatch_kevent_t dk = _dispatch_kq_deferred_reuse_slot(wlh, ddi, slot);
925950
*dk = *ke;
951+
#ifdef EVFILT_USER
926952
if (ke->filter != EVFILT_USER) {
927953
_dispatch_kevent_mgr_debug("deferred", ke);
928954
}
955+
#else
956+
_dispatch_kevent_mgr_debug("deferred", ke);
957+
#endif
929958
} else {
930959
_dispatch_kq_update_one(wlh, ke);
931960
}
@@ -1887,10 +1916,17 @@ _dispatch_event_loop_poke(dispatch_wlh_t wlh, uint64_t dq_state, uint32_t flags)
18871916
{
18881917
if (wlh == DISPATCH_WLH_MANAGER) {
18891918
dispatch_kevent_s ke = (dispatch_kevent_s){
1919+
#ifdef EVFILT_USER
18901920
.ident = 1,
18911921
.filter = EVFILT_USER,
18921922
.fflags = NOTE_TRIGGER,
18931923
.udata = (dispatch_kevent_udata_t)DISPATCH_WLH_MANAGER,
1924+
#else
1925+
.ident = DISPATCH_KEVENT_ERSATZ_EVFILT_USER_MASK,
1926+
.filter = EVFILT_TIMER,
1927+
.flags = EV_ADD|EV_ENABLE,
1928+
.data = 1
1929+
#endif
18941930
};
18951931
return _dispatch_kq_deferred_update(DISPATCH_WLH_ANON, &ke);
18961932
} else if (wlh && wlh != DISPATCH_WLH_ANON) {

0 commit comments

Comments
 (0)