mirror of
https://github.com/darlinghq/darling-libkqueue.git
synced 2024-11-26 21:20:38 +00:00
Only process EV_DISPATCH and EV_ONESHOT when we get a valid event
If the copyout callback for a filter indicates that the event should be ignored/dropped, we should not process EV_DISPATCH or EV_ONESHOT, as this would lead to missing actual events in the future. Some filters (e.g. EVFILT_PROC) do specifically want to process EV_ONESHOT even when dropping an event, so this also introduces a special filter ID (EVFILT_DROP_POSTPROCESS) that enables the old behavior for individual events. Additionally, rather than just using `0` as a special filter ID, this commit introduces EVFILT_DROP (to be clear about its meaning).
This commit is contained in:
parent
bcef9ea04b
commit
76d8aa3dce
@ -62,7 +62,7 @@ knote_release(struct knote *kn)
|
||||
if (/*kn->kn_flags & KNFL_KNOTE_DELETED*/ 1) {
|
||||
dbg_printf("freeing knote at %p (delayed)", kn);
|
||||
LIST_INSERT_HEAD(&kn->kn_kq->kq_tofree, kn, kn_entries2free);
|
||||
kn->kev.filter = 0;
|
||||
kn->kev.filter = EVFILT_DROP;
|
||||
} else {
|
||||
dbg_puts("this should never happen");
|
||||
}
|
||||
|
@ -75,6 +75,9 @@ struct eventfd {
|
||||
#define KNFL_PASSIVE_SOCKET (0x01) /* Socket is in listen(2) mode */
|
||||
#define KNFL_REGULAR_FILE (0x02) /* File descriptor is a regular file */
|
||||
#define KNFL_KNOTE_DELETED (0x10) /* The knote object is no longer valid */
|
||||
|
||||
#define EVFILT_DROP 0
|
||||
#define EVFILT_DROP_POSTPROCESS (EVFILT_SYSCOUNT + 1)
|
||||
|
||||
struct knote {
|
||||
struct kevent_internal_s kev;
|
||||
|
@ -86,7 +86,7 @@ evfilt_machport_copyout(struct kevent64_s *dst, struct knote *src, void *ptr)
|
||||
if (reply.header.code == 0xdead) {
|
||||
// server indicated there was actually no event available to read right now;
|
||||
// drop the event
|
||||
dst->filter = 0;
|
||||
dst->filter = EVFILT_DROP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -123,15 +123,13 @@ evfilt_machport_knote_create(struct filter *filt, struct knote *kn)
|
||||
ev.events = kn->data.events;
|
||||
ev.data.ptr = kn;
|
||||
|
||||
kn->kdata.kn_dupfd = eventfd(0, EFD_CLOEXEC);
|
||||
|
||||
int status = _dserver_rpc_kqchan_mach_port_open_4libkqueue(port, (void*)kn->kev.ext[0], kn->kev.ext[1], kn->kev.fflags, &kn->kdata.kn_dupfd);
|
||||
if (status < 0) {
|
||||
dbg_printf("evfilt_machport_open: %s", strerror(-status));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
dbg_printf("evfilt_machport_open: listening to FD %d", kn->kdata.kn_dupfd);
|
||||
dbg_printf("evfilt_machport_open: listening to FD %d for events %d", kn->kdata.kn_dupfd, ev.events);
|
||||
|
||||
fcntl(kn->kdata.kn_dupfd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
@ -209,6 +207,8 @@ evfilt_machport_knote_enable(struct filter *filt, struct knote *kn)
|
||||
ev.events = kn->data.events;
|
||||
ev.data.ptr = kn;
|
||||
|
||||
dbg_printf("enabling machport knote with ID=%llu for events %d", kn->kev.ident, ev.events);
|
||||
|
||||
if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_ADD, kn->kdata.kn_dupfd, &ev) < 0) {
|
||||
dbg_perror("epoll_ctl(2)");
|
||||
return (-1);
|
||||
@ -219,6 +219,7 @@ evfilt_machport_knote_enable(struct filter *filt, struct knote *kn)
|
||||
int
|
||||
evfilt_machport_knote_disable(struct filter *filt, struct knote *kn)
|
||||
{
|
||||
dbg_printf("disable machport knote with ID=%llu", kn->kev.ident);
|
||||
if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_DEL, kn->kdata.kn_dupfd, NULL) < 0) {
|
||||
dbg_perror("epoll_ctl(2)");
|
||||
return (-1);
|
||||
|
@ -193,45 +193,47 @@ linux_kevent_copyout(struct kqueue *kq, int nready,
|
||||
struct filter *filt;
|
||||
struct knote *kn;
|
||||
int i, nret, rv;
|
||||
struct kevent64_s* event;
|
||||
|
||||
nret = nready;
|
||||
for (i = 0; i < nready; i++) {
|
||||
ev = &epevt_get()[i];
|
||||
kn = (struct knote *) ev->data.ptr;
|
||||
event = eventlist;
|
||||
if (kn->kev.filter == 0) {
|
||||
dbg_puts("kevent copyout for zero filter, discarding!");
|
||||
nret--;
|
||||
continue;
|
||||
}
|
||||
filt = &kq->kq_filt[~(kn->kev.filter)];
|
||||
rv = filt->kf_copyout(eventlist, kn, ev);
|
||||
rv = filt->kf_copyout(event, kn, ev);
|
||||
if (slowpath(rv < 0)) {
|
||||
dbg_puts("knote_copyout failed");
|
||||
/* XXX-FIXME: hard to handle this without losing events */
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* Certain flags cause the associated knote to be deleted
|
||||
* or disabled.
|
||||
*/
|
||||
if (eventlist->flags & EV_DISPATCH)
|
||||
knote_disable(filt, kn); //FIXME: Error checking
|
||||
if (eventlist->flags & EV_ONESHOT) {
|
||||
knote_delete(filt, kn); //FIXME: Error checking
|
||||
}
|
||||
|
||||
/* If an empty kevent structure is returned, the event is discarded. */
|
||||
/* TODO: add these semantics to windows + solaris platform.c */
|
||||
|
||||
/* EV_DELETE is an internal trick to not have this event passed to the app.
|
||||
* Typically used along with EV_ONESHOT - see linux/proc.c
|
||||
*/
|
||||
if (fastpath(eventlist->filter != 0) && !(eventlist->flags & EV_DELETE)) {
|
||||
if (fastpath(event->filter != EVFILT_DROP && event->filter != EVFILT_DROP_POSTPROCESS)) {
|
||||
eventlist++;
|
||||
} else {
|
||||
dbg_puts("spurious wakeup, discarding event");
|
||||
nret--;
|
||||
if (event->filter != EVFILT_DROP_POSTPROCESS) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Certain flags cause the associated knote to be deleted
|
||||
* or disabled.
|
||||
*/
|
||||
if (event->flags & EV_DISPATCH)
|
||||
knote_disable(filt, kn); //FIXME: Error checking
|
||||
if (event->flags & EV_ONESHOT) {
|
||||
knote_delete(filt, kn); //FIXME: Error checking
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ evfilt_proc_copyout(struct kevent64_s *dst, struct knote *src, void *ptr)
|
||||
if (reply.header.code == 0xdead) {
|
||||
// server indicated there was actually no event available to read right now;
|
||||
// drop the event
|
||||
dst->filter = 0;
|
||||
dst->filter = EVFILT_DROP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ evfilt_proc_copyout(struct kevent64_s *dst, struct knote *src, void *ptr)
|
||||
// don't deliver it to the program.
|
||||
|
||||
if (!(src->kev.fflags & NOTE_FORK))
|
||||
dst->filter = 0; // drop event
|
||||
dst->filter = EVFILT_DROP; // drop event
|
||||
}
|
||||
else if (dst->fflags & NOTE_EXIT)
|
||||
{
|
||||
@ -163,11 +163,12 @@ evfilt_proc_copyout(struct kevent64_s *dst, struct knote *src, void *ptr)
|
||||
dst->flags |= EV_EOF | EV_ONESHOT;
|
||||
|
||||
// NOTE_EXIT is always announced so that we can
|
||||
// remove the knote. Add EV_DELETE to avoid passing
|
||||
// the event to the application if it is not interested
|
||||
// in this event
|
||||
// remove the knote. Avoid passing the event to
|
||||
// the application if it is not interested in
|
||||
// this event.
|
||||
// We use EVFILT_DROP_POSTPROCESS to force the EV_ONESHOT to be processed.
|
||||
if (!(src->kev.fflags & NOTE_EXIT))
|
||||
dst->flags |= EV_DELETE;
|
||||
dst->filter = EVFILT_DROP_POSTPROCESS; // drop event
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
@ -64,7 +64,7 @@ evfilt_read_copyout(struct kevent64_s *dst, struct knote *src, void *ptr)
|
||||
dst->data = get_eof_offset(src->kev.ident);
|
||||
|
||||
if (dst->data == 0) {
|
||||
dst->filter = 0; /* Will cause the kevent to be discarded */
|
||||
dst->filter = EVFILT_DROP; /* Will cause the kevent to be discarded */
|
||||
if (epoll_ctl(src->kn_epollfd, EPOLL_CTL_DEL, src->kdata.kn_eventfd, NULL) < 0) {
|
||||
dbg_perror("epoll_ctl(2)");
|
||||
return (-1);
|
||||
|
@ -174,7 +174,7 @@ evfilt_vnode_copyout(struct kevent64_s *dst, struct knote *src, void *ptr UNUSED
|
||||
dbg_printf("inotify event: %s", inotify_event_dump(evt));
|
||||
if (evt->mask & IN_IGNORED) {
|
||||
/* TODO: possibly return error when fs is unmounted */
|
||||
dst->filter = 0;
|
||||
dst->filter = EVFILT_DROP;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ scriptors reference the same file.
|
||||
*/
|
||||
if (evt->mask & IN_CLOSE_WRITE || evt->mask & IN_CLOSE_NOWRITE) {
|
||||
src->kn_flags |= EV_ONESHOT; /* KLUDGE: causes the knote to be deleted */
|
||||
dst->filter = 0; /* KLUDGE: causes the event to be discarded */
|
||||
dst->filter = EVFILT_DROP_POSTPROCESS; /* KLUDGE: causes the event to be discarded */
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user