kqueue: Bring in EV_RECEIPT and EV_DISPATCH from FreeBSD
authorBen Woolley <tautolog@gmail.com>
Fri, 4 Dec 2015 07:58:21 +0000 (23:58 -0800)
committerJohn Marino <draco@marino.st>
Fri, 4 Dec 2015 09:12:24 +0000 (10:12 +0100)
EV_RECEIPT:  FreeBSD SVN 197243
EV_DISPATCH: FreeBSD SVN 197242

Since EV_RECEIPT has been on FreeBSD since release 8.1 and on OSX
since Release 10.5, it's starting to show up in 3rd party software.
And authors assume if FreeBSD has it, all BSDs have.

suggested by:   Jan Beich
contributed by: Ben Woolley

lib/libc/sys/kqueue.2
sys/kern/kern_event.c
sys/sys/event.h

index 80e0401..c6ca45b 100644 (file)
@@ -177,10 +177,24 @@ Disable the event so
 .Fn kevent
 will not return it.
 The filter itself is not disabled.
+.It EV_DISPATCH
+Disable the event source immediately after delivery of an event.
+See
+.Dv EV_DISABLE
+above.
 .It Dv EV_DELETE
 Removes the event from the kqueue.
 Events which are attached to file descriptors are automatically
 deleted on the last close of the descriptor.
+.It EV_RECEIPT
+This flag is useful for making bulk changes to a kqueue without draining
+any pending events.
+When passed as input, it forces
+.Dv EV_ERROR
+to always be returned.
+When a filter is successfully added the
+.Va data
+field will be zero.
 .It Dv EV_ONESHOT
 Causes the event to return only the first occurrence of the filter
 being triggered.
index 34f4249..08983a3 100644 (file)
@@ -745,7 +745,7 @@ kern_kevent(struct kqueue *kq, int nevents, int *res, void *uap,
                         * to post the error (see sys_poll()), then we
                         * ignore it too.
                         */
-                       if (error) {
+                       if (error || (kevp->flags & EV_RECEIPT)) {
                                kevp->flags = EV_ERROR;
                                kevp->data = error;
                                lres = *res;
@@ -1273,9 +1273,14 @@ kqueue_scan(struct kqueue *kq, struct kevent *kevp, int count,
                                kn->kn_status &= ~KN_QUEUED;
                                kn->kn_status |= KN_DELETING | KN_REPROCESS;
                        } else {
-                               if (kn->kn_flags & EV_CLEAR) {
-                                       kn->kn_data = 0;
-                                       kn->kn_fflags = 0;
+                               if (kn->kn_flags & (EV_CLEAR | EV_DISPATCH)) {
+                                       if (kn->kn_flags & EV_CLEAR) {
+                                               kn->kn_data = 0;
+                                               kn->kn_fflags = 0;
+                                       }
+                                       if (kn->kn_flags & EV_DISPATCH) {
+                                               kn->kn_status |= KN_DISABLED;
+                                       }
                                        kn->kn_status &= ~(KN_QUEUED |
                                                           KN_ACTIVE);
                                } else {
index 1710c20..c3c9508 100644 (file)
@@ -82,6 +82,8 @@ struct kevent {
 /* flags */
 #define EV_ONESHOT     0x0010          /* only report one occurrence */
 #define EV_CLEAR       0x0020          /* clear event state after reporting */
+#define EV_RECEIPT     0x0040          /* force EV_ERROR on success, data=0 */
+#define EV_DISPATCH    0x0080          /* disable event after reporting */
 
 #define EV_SYSFLAGS    0xF000          /* reserved by system */
 #define EV_FLAG1       0x2000          /* filter-specific flag */