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,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, 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 __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 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