Commit 0321a799 authored by Nathaniel Wesley Filardo's avatar Nathaniel Wesley Filardo Committed by John Baldwin
Browse files

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@gmail.com>
Obtained from:	CheriBSD
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D30286
parent 701a9993
......@@ -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.
......
......@@ -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 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td,
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 {
......
......@@ -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 */
......
......@@ -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 */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment