Add abstime kqueue(2) timers and expand struct kevent members.

This change implements NOTE_ABSTIME flag for EVFILT_TIMER, which
specifies that the data field contains absolute time to fire the
event.

To make this useful, data member of the struct kevent must be extended
to 64bit.  Using the opportunity, I also added ext members.  This
changes struct kevent almost to Apple struct kevent64, except I did
not changed type of ident and udata, the later would cause serious API
incompatibilities.

The type of ident was kept uintptr_t since EVFILT_AIO returns a
pointer in this field, and e.g. CHERI is sensitive to the type
(discussed with brooks, jhb).

Unlike Apple kevent64, symbol versioning allows us to claim ABI
compatibility and still name the new syscall kevent(2).  Compat shims
are provided for both host native and compat32.

Requested by:	bapt
Reviewed by:	bapt, brooks, ngie (previous version)
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D11025
This commit is contained in:
kib 2017-06-17 00:57:26 +00:00
parent e36c6375d5
commit d7f022a3ab
15 changed files with 391 additions and 67 deletions

View File

@ -139,11 +139,7 @@ ATF_TC_BODY(proc1, tc)
printf(" NOTE_FORK");
}
if (event[0].fflags & NOTE_CHILD)
#ifdef __FreeBSD__
printf(" NOTE_CHILD, parent = %" PRIdPTR, event[0].data);
#else
printf(" NOTE_CHILD, parent = %" PRId64, event[0].data);
#endif
printf("\n");
}

View File

@ -127,11 +127,7 @@ ATF_TC_BODY(sig, tc)
if (n == 0)
continue;
#ifdef __FreeBSD__
(void)printf("sig: kevent flags: 0x%x, data: %" PRIdPTR " (# "
#else
(void)printf("sig: kevent flags: 0x%x, data: %" PRId64 " (# "
#endif
"times signal posted)\n", event[0].flags, event[0].data);
}

View File

@ -65,6 +65,8 @@ __sym_compat(statfs, freebsd11_statfs, FBSD_1.0);
__sym_compat(mknod, freebsd11_mknod, FBSD_1.0);
__sym_compat(mknodat, freebsd11_mknodat, FBSD_1.1);
__sym_compat(kevent, freebsd11_kevent, FBSD_1.0);
#undef __sym_compat
#define __weak_reference(sym,alias) \

View File

@ -121,7 +121,6 @@ FBSD_1.0 {
jail;
jail_attach;
kenv;
kevent;
kill;
kldfind;
kldfirstmod;
@ -393,6 +392,7 @@ FBSD_1.5 {
getdents;
getdirentries;
getfsstat;
kevent;
lstat;
mknod;
mknodat;

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd April 18, 2017
.Dd June 17, 2017
.Dt KQUEUE 2
.Os
.Sh NAME
@ -148,12 +148,13 @@ The
structure is defined as:
.Bd -literal
struct kevent {
uintptr_t ident; /* identifier for this event */
uintptr_t ident; /* identifier for this event */
short filter; /* filter for event */
u_short flags; /* action flags for kqueue */
u_int fflags; /* filter flag value */
intptr_t data; /* filter data value */
int64_t data; /* filter data value */
void *udata; /* opaque user data identifier */
uint64_t ext[4]; /* extentions */
};
.Ed
.Pp
@ -177,6 +178,20 @@ Filter-specific flags.
Filter-specific data value.
.It Fa udata
Opaque user-defined value passed through the kernel unchanged.
.It Fa ext
Extended data passed to and from kernel.
The
.Fa ext[0]
and
.Fa ext[1]
members use is defined by the filter.
If the filter does not use them, the members are copied unchanged.
The
.Fa ext[2]
and
.Fa ext[3]
members are always passed throught the kernel as-is,
making additional context available to application.
.El
.Pp
The
@ -515,16 +530,26 @@ Establishes an arbitrary timer identified by
.Va ident .
When adding a timer,
.Va data
specifies the timeout period.
specifies the moment to fire the timer (for
.Dv NOTE_ABSTIME )
or the timeout period.
The timer will be periodic unless
.Dv EV_ONESHOT
or
.Dv NOTE_ABSTIME
is specified.
On return,
.Va data
contains the number of times the timeout has expired since the last call to
.Fn kevent .
This filter automatically sets the EV_CLEAR flag internally.
.Bl -tag -width "Dv NOTE_USECONDS"
For non-monotonic timers, this filter automatically sets the
.Dv EV_CLEAR
flag internally.
.Pp
The filter accepts the following flags in the
.Va fflags
argument:
.Bl -tag -width "Dv NOTE_MSECONDS"
.It Dv NOTE_SECONDS
.Va data
is in seconds.
@ -537,6 +562,8 @@ is in microseconds.
.It Dv NOTE_NSECONDS
.Va data
is in nanoseconds.
.It Dv NOTE_ABSTIME
The specified expiration time is absolute.
.El
.Pp
If

View File

@ -137,12 +137,13 @@ struct statfs32 {
};
struct kevent32 {
u_int32_t ident; /* identifier for this event */
uint32_t ident; /* identifier for this event */
short filter; /* filter for event */
u_short flags;
u_int fflags;
int32_t data;
u_int32_t udata; /* opaque user data identifier */
int32_t data1, data2;
uint32_t udata; /* opaque user data identifier */
uint32_t ext64[8];
};
struct iovec32 {

View File

@ -119,7 +119,7 @@ CTASSERT(sizeof(struct statfs32) == 256);
CTASSERT(sizeof(struct rusage32) == 72);
#endif
CTASSERT(sizeof(struct sigaltstack32) == 12);
CTASSERT(sizeof(struct kevent32) == 20);
CTASSERT(sizeof(struct kevent32) == 56);
CTASSERT(sizeof(struct iovec32) == 8);
CTASSERT(sizeof(struct msghdr32) == 28);
#ifdef __amd64__
@ -622,11 +622,131 @@ freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count)
{
struct freebsd32_kevent_args *uap;
struct kevent32 ks32[KQ_NEVENTS];
int i, error = 0;
uint64_t e;
int i, j, error;
KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
uap = (struct freebsd32_kevent_args *)arg;
for (i = 0; i < count; i++) {
CP(kevp[i], ks32[i], ident);
CP(kevp[i], ks32[i], filter);
CP(kevp[i], ks32[i], flags);
CP(kevp[i], ks32[i], fflags);
#if BYTE_ORDER == LITTLE_ENDIAN
ks32[i].data1 = kevp[i].data;
ks32[i].data2 = kevp[i].data >> 32;
#else
ks32[i].data1 = kevp[i].data >> 32;
ks32[i].data2 = kevp[i].data;
#endif
PTROUT_CP(kevp[i], ks32[i], udata);
for (j = 0; j < nitems(kevp->ext); j++) {
e = kevp[i].ext[j];
#if BYTE_ORDER == LITTLE_ENDIAN
ks32[i].ext64[2 * j] = e;
ks32[i].ext64[2 * j + 1] = e >> 32;
#else
ks32[i].ext64[2 * j] = e >> 32;
ks32[i].ext64[2 * j + 1] = e;
#endif
}
}
error = copyout(ks32, uap->eventlist, count * sizeof *ks32);
if (error == 0)
uap->eventlist += count;
return (error);
}
/*
* Copy 'count' items from the list pointed to by uap->changelist.
*/
static int
freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count)
{
struct freebsd32_kevent_args *uap;
struct kevent32 ks32[KQ_NEVENTS];
uint64_t e;
int i, j, error;
KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
uap = (struct freebsd32_kevent_args *)arg;
error = copyin(uap->changelist, ks32, count * sizeof *ks32);
if (error)
goto done;
uap->changelist += count;
for (i = 0; i < count; i++) {
CP(ks32[i], kevp[i], ident);
CP(ks32[i], kevp[i], filter);
CP(ks32[i], kevp[i], flags);
CP(ks32[i], kevp[i], fflags);
kevp[i].data = PAIR32TO64(uint64_t, ks32[i].data);
PTRIN_CP(ks32[i], kevp[i], udata);
for (j = 0; j < nitems(kevp->ext); j++) {
#if BYTE_ORDER == LITTLE_ENDIAN
e = ks32[i].ext64[2 * j + 1];
e <<= 32;
e += ks32[i].ext64[2 * j];
#else
e = ks32[i].ext64[2 * j];
e <<= 32;
e += ks32[i].ext64[2 * j + 1];
#endif
kevp[i].ext[j] = e;
}
}
done:
return (error);
}
int
freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
{
struct timespec32 ts32;
struct timespec ts, *tsp;
struct kevent_copyops k_ops = {
.arg = uap,
.k_copyout = freebsd32_kevent_copyout,
.k_copyin = freebsd32_kevent_copyin,
};
int error;
if (uap->timeout) {
error = copyin(uap->timeout, &ts32, sizeof(ts32));
if (error)
return (error);
CP(ts32, ts, tv_sec);
CP(ts32, ts, tv_nsec);
tsp = &ts;
} else
tsp = NULL;
error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents,
&k_ops, tsp);
return (error);
}
#ifdef COMPAT_FREEBSD11
struct kevent32_freebsd11 {
u_int32_t ident; /* identifier for this event */
short filter; /* filter for event */
u_short flags;
u_int fflags;
int32_t data;
u_int32_t udata; /* opaque user data identifier */
};
static int
freebsd32_kevent11_copyout(void *arg, struct kevent *kevp, int count)
{
struct freebsd11_freebsd32_kevent_args *uap;
struct kevent32_freebsd11 ks32[KQ_NEVENTS];
int i, error;
KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
uap = (struct freebsd11_freebsd32_kevent_args *)arg;
for (i = 0; i < count; i++) {
CP(kevp[i], ks32[i], ident);
CP(kevp[i], ks32[i], filter);
@ -645,14 +765,14 @@ freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count)
* Copy 'count' items from the list pointed to by uap->changelist.
*/
static int
freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count)
freebsd32_kevent11_copyin(void *arg, struct kevent *kevp, int count)
{
struct freebsd32_kevent_args *uap;
struct kevent32 ks32[KQ_NEVENTS];
int i, error = 0;
struct freebsd11_freebsd32_kevent_args *uap;
struct kevent32_freebsd11 ks32[KQ_NEVENTS];
int i, j, error;
KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
uap = (struct freebsd32_kevent_args *)arg;
uap = (struct freebsd11_freebsd32_kevent_args *)arg;
error = copyin(uap->changelist, ks32, count * sizeof *ks32);
if (error)
@ -666,24 +786,26 @@ freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count)
CP(ks32[i], kevp[i], fflags);
CP(ks32[i], kevp[i], data);
PTRIN_CP(ks32[i], kevp[i], udata);
for (j = 0; j < nitems(kevp->ext); j++)
kevp[i].ext[j] = 0;
}
done:
return (error);
}
int
freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
freebsd11_freebsd32_kevent(struct thread *td,
struct freebsd11_freebsd32_kevent_args *uap)
{
struct timespec32 ts32;
struct timespec ts, *tsp;
struct kevent_copyops k_ops = {
.arg = uap,
.k_copyout = freebsd32_kevent_copyout,
.k_copyin = freebsd32_kevent_copyin,
.k_copyout = freebsd32_kevent11_copyout,
.k_copyin = freebsd32_kevent11_copyin,
};
int error;
if (uap->timeout) {
error = copyin(uap->timeout, &ts32, sizeof(ts32));
if (error)
@ -697,6 +819,7 @@ freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
&k_ops, tsp);
return (error);
}
#endif
int
freebsd32_gettimeofday(struct thread *td,

View File

@ -667,10 +667,12 @@
361 AUE_GETRESGID NOPROTO { int getresgid(gid_t *rgid, gid_t *egid, \
gid_t *sgid); }
362 AUE_KQUEUE NOPROTO { int kqueue(void); }
363 AUE_KEVENT STD { int freebsd32_kevent(int fd, \
const struct kevent32 *changelist, \
363 AUE_KEVENT COMPAT11 { int freebsd32_kevent(int fd, \
const struct kevent32_freebsd11 * \
changelist, \
int nchanges, \
struct kevent32 *eventlist, int nevents, \
struct kevent32_freebsd11 *eventlist, \
int nevents, \
const struct timespec32 *timeout); }
364 AUE_NULL UNIMPL __cap_get_proc
365 AUE_NULL UNIMPL __cap_set_proc
@ -1111,3 +1113,9 @@
struct statfs32 *buf); }
559 AUE_MKNODAT NOPROTO { int mknodat(int fd, char *path, mode_t mode, \
dev_t dev); }
560 AUE_KEVENT STD { int freebsd32_kevent(int fd, \
const struct kevent32 *changelist, \
int nchanges, \
struct kevent32 *eventlist, \
int nevents, \
const struct timespec32 *timeout); }

View File

@ -29,6 +29,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_ktrace.h"
#include "opt_kqueue.h"
@ -111,6 +112,10 @@ static int kqueue_scan(struct kqueue *kq, int maxevents,
static void kqueue_wakeup(struct kqueue *kq);
static struct filterops *kqueue_fo_find(int filt);
static void kqueue_fo_release(int filt);
struct g_kevent_args;
static int kern_kevent_generic(struct thread *td,
struct g_kevent_args *uap,
struct kevent_copyops *k_ops);
static fo_ioctl_t kqueue_ioctl;
static fo_poll_t kqueue_poll;
@ -663,7 +668,7 @@ timer2sbintime(intptr_t data, int flags)
struct kq_timer_cb_data {
struct callout c;
sbintime_t next; /* next timer event fires at */
sbintime_t to; /* precalculated timer period */
sbintime_t to; /* precalculated timer period, 0 for abs */
};
static void
@ -678,8 +683,9 @@ filt_timerexpire(void *knx)
if ((kn->kn_flags & EV_ONESHOT) != 0)
return;
kc = kn->kn_ptr.p_v;
if (kc->to == 0)
return;
kc->next += kc->to;
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
PCPU_GET(cpuid), C_ABSOLUTE);
@ -692,7 +698,8 @@ static int
filt_timerattach(struct knote *kn)
{
struct kq_timer_cb_data *kc;
sbintime_t to;
struct bintime bt;
sbintime_t to, sbt;
unsigned int ncallouts;
if (kn->kn_sdata < 0)
@ -700,10 +707,15 @@ filt_timerattach(struct knote *kn)
if (kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0)
kn->kn_sdata = 1;
/* Only precision unit are supported in flags so far */
if ((kn->kn_sfflags & ~NOTE_TIMER_PRECMASK) != 0)
if ((kn->kn_sfflags & ~(NOTE_TIMER_PRECMASK | NOTE_ABSTIME)) != 0)
return (EINVAL);
to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags);
if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
getboottimebin(&bt);
sbt = bttosbt(bt);
to -= sbt;
}
if (to < 0)
return (EINVAL);
@ -713,12 +725,18 @@ filt_timerattach(struct knote *kn)
return (ENOMEM);
} while (!atomic_cmpset_int(&kq_ncallouts, ncallouts, ncallouts + 1));
kn->kn_flags |= EV_CLEAR; /* automatically set */
if ((kn->kn_sfflags & NOTE_ABSTIME) == 0)
kn->kn_flags |= EV_CLEAR; /* automatically set */
kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */
kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
callout_init(&kc->c, 1);
kc->next = to + sbinuptime();
kc->to = to;
if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
kc->next = to;
kc->to = 0;
} else {
kc->next = to + sbinuptime();
kc->to = to;
}
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
PCPU_GET(cpuid), C_ABSOLUTE);
@ -890,34 +908,42 @@ kern_kqueue(struct thread *td, int flags, struct filecaps *fcaps)
#ifdef KTRACE
static size_t
kev_iovlen(int n, u_int kgio)
kev_iovlen(int n, u_int kgio, size_t kevent_size)
{
if (n < 0 || n >= kgio / sizeof(struct kevent))
if (n < 0 || n >= kgio / kevent_size)
return (kgio);
return (n * sizeof(struct kevent));
return (n * kevent_size);
}
#endif
#ifndef _SYS_SYSPROTO_H_
struct kevent_args {
struct g_kevent_args {
int fd;
const struct kevent *changelist;
void *changelist;
int nchanges;
struct kevent *eventlist;
void *eventlist;
int nevents;
const struct timespec *timeout;
};
#endif
int
sys_kevent(struct thread *td, struct kevent_args *uap)
{
struct timespec ts, *tsp;
struct kevent_copyops k_ops = {
.arg = uap,
.k_copyout = kevent_copyout,
.k_copyin = kevent_copyin,
.kevent_size = sizeof(struct kevent),
};
return (kern_kevent_generic(td, (struct g_kevent_args *)uap, &k_ops));
}
static int
kern_kevent_generic(struct thread *td, struct g_kevent_args *uap,
struct kevent_copyops *k_ops)
{
struct timespec ts, *tsp;
int error;
#ifdef KTRACE
struct uio ktruio;
@ -939,26 +965,30 @@ sys_kevent(struct thread *td, struct kevent_args *uap)
if (KTRPOINT(td, KTR_GENIO)) {
kgio = ktr_geniosize;
ktriov.iov_base = uap->changelist;
ktriov.iov_len = kev_iovlen(uap->nchanges, kgio);
ktriov.iov_len = kev_iovlen(uap->nchanges, kgio,
k_ops->kevent_size);
ktruio = (struct uio){ .uio_iov = &ktriov, .uio_iovcnt = 1,
.uio_segflg = UIO_USERSPACE, .uio_rw = UIO_READ,
.uio_td = td };
ktruioin = cloneuio(&ktruio);
ktriov.iov_base = uap->eventlist;
ktriov.iov_len = kev_iovlen(uap->nevents, kgio);
ktriov.iov_len = uap->nevents * sizeof(struct kevent);
ktriov.iov_len = kev_iovlen(uap->nevents, kgio,
k_ops->kevent_size);
ktriov.iov_len = uap->nevents * k_ops->kevent_size;
ktruioout = cloneuio(&ktruio);
}
#endif
error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents,
&k_ops, tsp);
k_ops, tsp);
#ifdef KTRACE
if (ktruioin != NULL) {
ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio);
ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio,
k_ops->kevent_size);
ktrgenio(uap->fd, UIO_WRITE, ktruioin, 0);
ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio);
ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio,
k_ops->kevent_size);
ktrgenio(uap->fd, UIO_READ, ktruioout, error);
}
#endif
@ -1002,6 +1032,86 @@ kevent_copyin(void *arg, struct kevent *kevp, int count)
return (error);
}
#ifdef COMPAT_FREEBSD11
struct kevent_freebsd11 {
__uintptr_t ident; /* identifier for this event */
short filter; /* filter for event */
unsigned short flags;
unsigned int fflags;
__intptr_t data;
void *udata; /* opaque user data identifier */
};
static int
kevent11_copyout(void *arg, struct kevent *kevp, int count)
{
struct freebsd11_kevent_args *uap;
struct kevent_freebsd11 kev11;
int error, i;
KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
uap = (struct freebsd11_kevent_args *)arg;
for (i = 0; i < count; i++) {
kev11.ident = kevp->ident;
kev11.filter = kevp->filter;
kev11.flags = kevp->flags;
kev11.fflags = kevp->fflags;
kev11.data = kevp->data;
kev11.udata = kevp->udata;
error = copyout(&kev11, uap->eventlist, sizeof(kev11));
if (error != 0)
break;
uap->eventlist++;
kevp++;
}
return (error);
}
/*
* Copy 'count' items from the list pointed to by uap->changelist.
*/
static int
kevent11_copyin(void *arg, struct kevent *kevp, int count)
{
struct freebsd11_kevent_args *uap;
struct kevent_freebsd11 kev11;
int error, i;
KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
uap = (struct freebsd11_kevent_args *)arg;
for (i = 0; i < count; i++) {
error = copyin(uap->changelist, &kev11, sizeof(kev11));
if (error != 0)
break;
kevp->ident = kev11.ident;
kevp->filter = kev11.filter;
kevp->flags = kev11.flags;
kevp->fflags = kev11.fflags;
kevp->data = (uintptr_t)kev11.data;
kevp->udata = kev11.udata;
bzero(&kevp->ext, sizeof(kevp->ext));
uap->changelist++;
kevp++;
}
return (error);
}
int
freebsd11_kevent(struct thread *td, struct freebsd11_kevent_args *uap)
{
struct kevent_copyops k_ops = {
.arg = uap,
.k_copyout = kevent11_copyout,
.k_copyin = kevent11_copyin,
.kevent_size = sizeof(struct kevent_freebsd11),
};
return (kern_kevent_generic(td, (struct g_kevent_args *)uap, &k_ops));
}
#endif
int
kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout)

View File

@ -657,9 +657,11 @@
361 AUE_GETRESGID STD { int getresgid(gid_t *rgid, gid_t *egid, \
gid_t *sgid); }
362 AUE_KQUEUE STD { int kqueue(void); }
363 AUE_KEVENT STD { int kevent(int fd, \
struct kevent *changelist, int nchanges, \
struct kevent *eventlist, int nevents, \
363 AUE_KEVENT COMPAT11 { int kevent(int fd, \
struct kevent_freebsd11 *changelist, \
int nchanges, \
struct kevent_freebsd11 *eventlist, \
int nevents, \
const struct timespec *timeout); }
364 AUE_NULL UNIMPL __cap_get_proc
365 AUE_NULL UNIMPL __cap_set_proc
@ -1017,6 +1019,10 @@
struct statfs *buf); }
559 AUE_MKNODAT STD { int mknodat(int fd, char *path, mode_t mode, \
dev_t dev); }
560 AUE_KEVENT STD { int kevent(int fd, \
struct kevent *changelist, int nchanges, \
struct kevent *eventlist, int nevents, \
const struct timespec *timeout); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master

View File

@ -2491,7 +2491,9 @@ sys_aio_fsync(struct thread *td, struct aio_fsync_args *uap)
static int
filt_aioattach(struct knote *kn)
{
struct kaiocb *job = (struct kaiocb *)kn->kn_sdata;
struct kaiocb *job;
job = (struct kaiocb *)(uintptr_t)kn->kn_sdata;
/*
* The job pointer must be validated before using it, so
@ -2539,7 +2541,9 @@ filt_aio(struct knote *kn, long hint)
static int
filt_lioattach(struct knote *kn)
{
struct aioliojob * lj = (struct aioliojob *)kn->kn_sdata;
struct aioliojob *lj;
lj = (struct aioliojob *)(uintptr_t)kn->kn_sdata;
/*
* The aioliojob pointer must be validated before using it, so

View File

@ -55,6 +55,10 @@
(kevp)->fflags = (d); \
(kevp)->data = (e); \
(kevp)->udata = (f); \
(kevp)->ext[0] = 0; \
(kevp)->ext[1] = 0; \
(kevp)->ext[2] = 0; \
(kevp)->ext[3] = 0; \
} while(0)
struct kevent {
@ -62,8 +66,9 @@ struct kevent {
short filter; /* filter for event */
unsigned short flags;
unsigned int fflags;
__intptr_t data;
__int64_t data;
void *udata; /* opaque user data identifier */
__uint64_t ext[4];
};
/* actions */
@ -149,6 +154,7 @@ struct kevent {
#define NOTE_MSECONDS 0x00000002 /* data is milliseconds */
#define NOTE_USECONDS 0x00000004 /* data is microseconds */
#define NOTE_NSECONDS 0x00000008 /* data is nanoseconds */
#define NOTE_ABSTIME 0x00000010 /* timeout is absolute */
struct knote;
SLIST_HEAD(klist, knote);
@ -232,7 +238,7 @@ struct knote {
#define KN_SCAN 0x100 /* flux set in kqueue_scan() */
int kn_influx;
int kn_sfflags; /* saved filter flags */
intptr_t kn_sdata; /* saved data field */
int64_t kn_sdata; /* saved data field */
union {
struct file *p_fp; /* file data pointer */
struct proc *p_proc; /* proc pointer */
@ -253,6 +259,7 @@ struct kevent_copyops {
void *arg;
int (*k_copyout)(void *arg, struct kevent *kevp, int count);
int (*k_copyin)(void *arg, struct kevent *kevp, int count);
size_t kevent_size;
};
struct thread;

View File

@ -180,13 +180,18 @@ kevent_to_str(struct kevent *kev)
char buf[512];
snprintf(&buf[0], sizeof(buf),
"[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]",
(u_int) kev->ident,
"[ident=%ju, filter=%d, %s, %s, data=%jd, udata=%p, "
"ext=[%jx %jx %jx %jx]",
(uintmax_t) kev->ident,
kev->filter,
kevent_flags_dump(kev),
kevent_fflags_dump(kev),
(int) kev->data,
kev->udata);
(uintmax_t)kev->data,
kev->udata,
(uintmax_t)kev->ext[0],
(uintmax_t)kev->ext[1],
(uintmax_t)kev->ext[2],
(uintmax_t)kev->ext[3]);
return (strdup(buf));
}
@ -218,7 +223,11 @@ kevent_cmp(struct kevent *k1, struct kevent *k2)
if (k1->flags & EV_ADD)
k2->flags |= EV_ADD;
#endif
if (memcmp(k1, k2, sizeof(*k1)) != 0) {
if (k1->ident != k2->ident || k1->filter != k2->filter ||
k1->flags != k2->flags || k1->fflags != k2->fflags ||
k1->data != k2->data || k1->udata != k2->udata ||
k1->ext[0] != k2->ext[0] || k1->ext[1] != k2->ext[1] ||
k1->ext[0] != k2->ext[2] || k1->ext[0] != k2->ext[3]) {
printf("kevent_cmp: mismatch:\n %s !=\n %s\n",
kevent_to_str(k1), kevent_to_str(k2));
abort();

View File

@ -17,6 +17,7 @@
*/
#include "common.h"
#include <sys/time.h>
int kqfd;
@ -164,6 +165,39 @@ disable_and_enable(void)
success();
}
static void
test_abstime(void)
{
const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
struct kevent kev;
time_t when;
const int timeout = 3;
test_begin(test_id);
test_no_kevents();
when = time(NULL);
EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
NOTE_ABSTIME | NOTE_SECONDS, when + timeout, NULL);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
/* Retrieve the event */
kev.flags = EV_ADD | EV_ONESHOT;
kev.data = 1;
kev.fflags = 0;
kevent_cmp(&kev, kevent_get(kqfd));
if (time(NULL) < when + timeout)
err(1, "too early %jd %jd", time(), when + timeout);
/* Check if the event occurs again */
sleep(3);
test_no_kevents();
success();
}
void
test_evfilt_timer()
{
@ -173,6 +207,7 @@ test_evfilt_timer()
test_kevent_timer_get();
test_oneshot();
test_periodic();
test_abstime();
disable_and_enable();
close(kqfd);
}

View File

@ -1255,7 +1255,7 @@ print_kevent(FILE *fp, struct kevent *ke, int input)
default:
fprintf(fp, "%#x", ke->fflags);
}
fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
}
static void