Page MenuHomeFreeBSD

D30286.diff
No OneTemporary

D30286.diff

diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
--- 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 @@
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
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1496,6 +1496,13 @@
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 @@
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
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -138,6 +138,7 @@
#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
--- a/tests/sys/kqueue/libkqueue/user.c
+++ b/tests/sys/kqueue/libkqueue/user.c
@@ -60,6 +60,32 @@
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 @@
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 @@
add_and_delete();
event_wait();
+ event_wait_keepudata();
disable_and_enable();
+ disable_and_enable_keepudata();
oneshot();
/* TODO: try different fflags operations */

File Metadata

Mime Type
text/plain
Expires
Wed, Dec 18, 10:51 PM (19 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15496678
Default Alt Text
D30286.diff (3 KB)

Event Timeline