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