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
This commit is contained in:
parent
701a99939f
commit
0321a7990b
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user