git: 0321a7990b27 - main - kqueue: Add EV_KEEPUDATA flag

John Baldwin jhb at FreeBSD.org
Fri Sep 24 00:32:35 UTC 2021


The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=0321a7990b277702fa0b4f8366121bf53d03cb64

commit 0321a7990b277702fa0b4f8366121bf53d03cb64
Author:     Nathaniel Wesley Filardo <nfilardo at microsoft.com>
AuthorDate: 2021-09-24 00:31:39 +0000
Commit:     John Baldwin <jhb at FreeBSD.org>
CommitDate: 2021-09-24 00:31:39 +0000

    kqueue: Add EV_KEEPUDATA flag
    
    When this flag is set, operations that update an existing kevent will
    not change the udata field.  This can be used to NOTE_TRIGGER or
    EV_{EN,DIS}ABLE events without overwriting the stashed pointer.
    
    Reviewed by:    Domagoj Stolfa <domagoj.stolfa at gmail.com>
    Obtained from:  CheriBSD
    Sponsored by:   Microsoft
    Differential Revision:  https://reviews.freebsd.org/D30286
---
 lib/libc/sys/kqueue.2             | 17 ++++++++++-
 sys/kern/kern_event.c             | 10 ++++++-
 sys/sys/event.h                   |  1 +
 tests/sys/kqueue/libkqueue/user.c | 60 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
index ed737c626ef8..3ded4ae3d8f7 100644
--- a/lib/libc/sys/kqueue.2
+++ b/lib/libc/sys/kqueue.2
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 7, 2021
+.Dd September 23, 2021
 .Dt KQUEUE 2
 .Os
 .Sh NAME
@@ -262,6 +262,21 @@ Filters may set this flag to indicate filter-specific EOF condition.
 See
 .Sx RETURN VALUES
 below.
+.It Dv EV_KEEPUDATA
+Causes
+.Fn kevent
+to leave unchanged any
+.Fa udata
+associated with an existing event.  This allows other aspects of the
+event to be modified without requiring the caller to know the
+.Fa udata
+value presently associated.
+This is especially useful with
+.Dv NOTE_TRIGGER
+or flags like
+.Dv EV_ENABLE.
+This flag may not be used with
+.Dv EV_ADD.
 .El
 .Pp
 The predefined system filters are listed below.
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index db505b234268..5fa5bf9cad06 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1496,6 +1496,13 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td,
 		return EINVAL;
 
 	if (kev->flags & EV_ADD) {
+		/* Reject an invalid flag pair early */
+		if (kev->flags & EV_KEEPUDATA) {
+			tkn = NULL;
+			error = EINVAL;
+			goto done;
+		}
+
 		/*
 		 * Prevent waiting with locks.  Non-sleepable
 		 * allocation failures are handled in the loop, only
@@ -1684,7 +1691,8 @@ findkn:
 	kn_enter_flux(kn);
 	KQ_UNLOCK(kq);
 	knl = kn_list_lock(kn);
-	kn->kn_kevent.udata = kev->udata;
+	if ((kev->flags & EV_KEEPUDATA) == 0)
+		kn->kn_kevent.udata = kev->udata;
 	if (!fops->f_isfd && fops->f_touch != NULL) {
 		fops->f_touch(kn, kev, EVENT_REGISTER);
 	} else {
diff --git a/sys/sys/event.h b/sys/sys/event.h
index 80ed1268c8a1..f1bdc7e2a80e 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -138,6 +138,7 @@ struct kevent32_freebsd11 {
 #define EV_ENABLE	0x0004		/* enable event */
 #define EV_DISABLE	0x0008		/* disable event (not reported) */
 #define EV_FORCEONESHOT	0x0100		/* enable _ONESHOT and force trigger */
+#define EV_KEEPUDATA	0x0200		/* do not update the udata field */
 
 /* flags */
 #define EV_ONESHOT	0x0010		/* only report one occurrence */
diff --git a/tests/sys/kqueue/libkqueue/user.c b/tests/sys/kqueue/libkqueue/user.c
index 3844251ff4ba..1f66234c4cda 100644
--- a/tests/sys/kqueue/libkqueue/user.c
+++ b/tests/sys/kqueue/libkqueue/user.c
@@ -60,6 +60,32 @@ event_wait(void)
     success();
 }
 
+static void
+event_wait_keepudata(void)
+{
+    const char *test_id = "kevent(EVFILT_USER, wait w/ EV_KEEPUDATA)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    test_no_kevents();
+
+    kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, &kev);
+    kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_KEEPUDATA, NOTE_TRIGGER, 0,
+        NULL);
+
+    kev.fflags &= ~NOTE_FFCTRLMASK;
+    kev.fflags &= ~NOTE_TRIGGER;
+    kev.flags = EV_CLEAR;
+    kev.udata = &kev;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    test_no_kevents();
+
+    success();
+}
+
+
 static void
 disable_and_enable(void)
 {
@@ -88,6 +114,38 @@ disable_and_enable(void)
     success();
 }
 
+static void
+disable_and_enable_keepudata(void)
+{
+    const char *test_id =
+        "kevent(EVFILT_USER, EV_DISABLE and EV_ENABLE w/ EV_KEEPUDATA)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    test_no_kevents();
+
+    kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, &kev);
+    kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DISABLE | EV_KEEPUDATA, 0, 0,
+        NULL);
+
+    /* Trigger the event, but since it is disabled, nothing will happen. */
+    kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_KEEPUDATA, NOTE_TRIGGER, 0, NULL);
+    test_no_kevents();
+
+    kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ENABLE | EV_KEEPUDATA, 0, 0,
+        NULL);
+    kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_KEEPUDATA, NOTE_TRIGGER, 0, NULL);
+
+    kev.flags = EV_CLEAR;
+    kev.fflags &= ~NOTE_FFCTRLMASK;
+    kev.fflags &= ~NOTE_TRIGGER;
+    kev.udata = &kev;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    success();
+}
+
 static void
 oneshot(void)
 {
@@ -120,7 +178,9 @@ test_evfilt_user(void)
 
     add_and_delete();
     event_wait();
+    event_wait_keepudata();
     disable_and_enable();
+    disable_and_enable_keepudata();
     oneshot();
     /* TODO: try different fflags operations */
 


More information about the dev-commits-src-all mailing list