summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2017-06-17 00:57:26 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2017-06-17 00:57:26 +0000
commit2b34e84335149a2d464c8e4b1334fb8f65a1fa8f (patch)
treed91d2c296ad043d944aa75f9d9a8635198860982
parentf2eb97b2cded8209e6d0d35930507dcfcf5bc794 (diff)
Notes
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_proc1.c4
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_sig.c4
-rw-r--r--lib/libc/include/compat.h2
-rw-r--r--lib/libc/sys/Symbol.map2
-rw-r--r--lib/libc/sys/kqueue.239
-rw-r--r--sys/compat/freebsd32/freebsd32.h7
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c133
-rw-r--r--sys/compat/freebsd32/syscalls.master14
-rw-r--r--sys/kern/kern_event.c154
-rw-r--r--sys/kern/syscalls.master12
-rw-r--r--sys/kern/vfs_aio.c8
-rw-r--r--sys/sys/event.h11
-rw-r--r--tests/sys/kqueue/libkqueue/main.c19
-rw-r--r--tests/sys/kqueue/libkqueue/timer.c35
-rw-r--r--usr.bin/truss/syscalls.c2
15 files changed, 385 insertions, 61 deletions
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_proc1.c b/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
index 5f8c2a4948b2..947e6e317a0a 100644
--- a/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
+++ b/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
@@ -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");
}
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_sig.c b/contrib/netbsd-tests/kernel/kqueue/t_sig.c
index 12e3d6115586..ea707e9af9e2 100644
--- a/contrib/netbsd-tests/kernel/kqueue/t_sig.c
+++ b/contrib/netbsd-tests/kernel/kqueue/t_sig.c
@@ -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);
}
diff --git a/lib/libc/include/compat.h b/lib/libc/include/compat.h
index 559c8502fb93..e353b0712430 100644
--- a/lib/libc/include/compat.h
+++ b/lib/libc/include/compat.h
@@ -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) \
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index feccda6f6bf4..4411cfe968cd 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -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;
diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
index e7bca7231690..14a8eaf22989 100644
--- a/lib/libc/sys/kqueue.2
+++ b/lib/libc/sys/kqueue.2
@@ -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
diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
index 05447da3696b..86211b556a1d 100644
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -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 {
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 86b5810d2665..826b1b3e9784 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -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,7 +622,8 @@ 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;
@@ -632,8 +633,24 @@ freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count)
CP(kevp[i], ks32[i], filter);
CP(kevp[i], ks32[i], flags);
CP(kevp[i], ks32[i], fflags);
- CP(kevp[i], ks32[i], data);
+#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)
@@ -649,7 +666,8 @@ freebsd32_kevent_copyin(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;
@@ -664,8 +682,20 @@ freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count)
CP(ks32[i], kevp[i], filter);
CP(ks32[i], kevp[i], flags);
CP(ks32[i], kevp[i], fflags);
- CP(ks32[i], kevp[i], data);
+ 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);
@@ -683,6 +713,98 @@ freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
};
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);
+ CP(kevp[i], ks32[i], flags);
+ CP(kevp[i], ks32[i], fflags);
+ CP(kevp[i], ks32[i], data);
+ PTROUT_CP(kevp[i], ks32[i], udata);
+ }
+ 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_kevent11_copyin(void *arg, struct kevent *kevp, int count)
+{
+ 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 freebsd11_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);
+ 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
+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_kevent11_copyout,
+ .k_copyin = freebsd32_kevent11_copyin,
+ };
+ int error;
if (uap->timeout) {
error = copyin(uap->timeout, &ts32, sizeof(ts32));
@@ -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,
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index fce75fe3488a..41efe33a5d1e 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -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); }
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 7a6c9ab067e8..da2026d8fec8 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -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)
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index ad0fdb27545f..732b640b2b5f 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -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
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index 1e01ccdac35c..c95dc772f527 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -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
diff --git a/sys/sys/event.h b/sys/sys/event.h
index 81d4a4750dac..ce93018caded 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -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;
diff --git a/tests/sys/kqueue/libkqueue/main.c b/tests/sys/kqueue/libkqueue/main.c
index 553478a514f5..aaf88bdc9d5a 100644
--- a/tests/sys/kqueue/libkqueue/main.c
+++ b/tests/sys/kqueue/libkqueue/main.c
@@ -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();
diff --git a/tests/sys/kqueue/libkqueue/timer.c b/tests/sys/kqueue/libkqueue/timer.c
index 766125d857e8..12b324b4eef8 100644
--- a/tests/sys/kqueue/libkqueue/timer.c
+++ b/tests/sys/kqueue/libkqueue/timer.c
@@ -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);
}
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 7601476854d0..c804ba2051fc 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -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