Index: lib/libc/include/compat.h =================================================================== --- lib/libc/include/compat.h +++ lib/libc/include/compat.h @@ -65,6 +65,8 @@ __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) \ Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map +++ lib/libc/sys/Symbol.map @@ -121,7 +121,6 @@ jail; jail_attach; kenv; - kevent; kill; kldfind; kldfirstmod; @@ -393,6 +392,7 @@ getdents; getdirentries; getfsstat; + kevent; lstat; mknod; mknodat; Index: lib/libc/sys/kqueue.2 =================================================================== --- lib/libc/sys/kqueue.2 +++ lib/libc/sys/kqueue.2 @@ -148,12 +148,13 @@ 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 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,20 +530,26 @@ .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. -There is a system wide limit on the number of timers -which is controlled by the -.Va kern.kq_calloutmax -sysctl. -.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. @@ -541,13 +562,21 @@ .It Dv NOTE_NSECONDS .Va data is in nanoseconds. +.It Dv NOTE_ABSTIME +The specified expiration time is absolute. .El .Pp If .Va fflags -is not set, the default is milliseconds. On return, +is not set, the default is milliseconds. +On return, .Va fflags contains the events which triggered the filter. +.Pp +There is a system wide limit on the number of timers +which is controlled by the +.Va kern.kq_calloutmax +sysctl. .It Dv EVFILT_USER Establishes a user event identified by .Va ident Index: sys/compat/freebsd32/freebsd32.h =================================================================== --- sys/compat/freebsd32/freebsd32.h +++ sys/compat/freebsd32/freebsd32.h @@ -137,12 +137,13 @@ }; 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 { Index: sys/compat/freebsd32/freebsd32_misc.c =================================================================== --- sys/compat/freebsd32/freebsd32_misc.c +++ sys/compat/freebsd32/freebsd32_misc.c @@ -119,7 +119,7 @@ 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 @@ { 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,18 @@ CP(kevp[i], ks32[i], filter); CP(kevp[i], ks32[i], flags); CP(kevp[i], ks32[i], fflags); - CP(kevp[i], ks32[i], data); + bcopy(&kevp[i].data, &ks32[i].data1, sizeof(uint64_t)); 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 +660,8 @@ { 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 +676,20 @@ 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 +707,98 @@ }; 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 +813,7 @@ &k_ops, tsp); return (error); } +#endif int freebsd32_gettimeofday(struct thread *td, Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master +++ 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); } Index: sys/kern/kern_event.c =================================================================== --- sys/kern/kern_event.c +++ 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 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; @@ -601,12 +606,13 @@ * interval timer support code. */ -#define NOTE_TIMER_PRECMASK (NOTE_SECONDS|NOTE_MSECONDS|NOTE_USECONDS| \ - NOTE_NSECONDS) +#define NOTE_TIMER_PRECMASK \ + (NOTE_SECONDS | NOTE_MSECONDS | NOTE_USECONDS | NOTE_NSECONDS) static sbintime_t timer2sbintime(intptr_t data, int flags) { + int64_t secs; /* * Macros for converting to the fractional second portion of an @@ -625,27 +631,27 @@ case NOTE_MSECONDS: /* FALLTHROUGH */ case 0: if (data >= 1000) { - int64_t secs = data / 1000; + secs = data / 1000; #ifdef __LP64__ if (secs > (SBT_MAX / SBT_1S)) return (SBT_MAX); #endif return (secs << 32 | MS_TO_SBT(data % 1000)); } - return MS_TO_SBT(data); + return (MS_TO_SBT(data)); case NOTE_USECONDS: if (data >= 1000000) { - int64_t secs = data / 1000000; + secs = data / 1000000; #ifdef __LP64__ if (secs > (SBT_MAX / SBT_1S)) return (SBT_MAX); #endif return (secs << 32 | US_TO_SBT(data % 1000000)); } - return US_TO_SBT(data); + return (US_TO_SBT(data)); case NOTE_NSECONDS: if (data >= 1000000000) { - int64_t secs = data / 1000000000; + secs = data / 1000000000; #ifdef __LP64__ if (secs > (SBT_MAX / SBT_1S)) return (SBT_MAX); @@ -662,7 +668,7 @@ 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 @@ -677,8 +683,9 @@ 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); @@ -691,7 +698,8 @@ 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) @@ -699,10 +707,15 @@ 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); @@ -712,12 +725,18 @@ 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); @@ -889,34 +908,42 @@ #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; @@ -938,26 +965,30 @@ 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 @@ -1001,6 +1032,86 @@ 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) Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master +++ 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 Index: sys/sys/event.h =================================================================== --- sys/sys/event.h +++ 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 @@ 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 @@ #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 @@ #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 @@ 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; Index: tests/sys/kqueue/libkqueue/main.c =================================================================== --- tests/sys/kqueue/libkqueue/main.c +++ tests/sys/kqueue/libkqueue/main.c @@ -180,13 +180,18 @@ 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 @@ 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(); Index: tests/sys/kqueue/libkqueue/timer.c =================================================================== --- tests/sys/kqueue/libkqueue/timer.c +++ tests/sys/kqueue/libkqueue/timer.c @@ -17,6 +17,7 @@ */ #include "common.h" +#include int kqfd; @@ -164,6 +165,39 @@ success(); } +static void +test_monotonic(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_kevent_timer_get(); test_oneshot(); test_periodic(); + test_monotonic(); disable_and_enable(); close(kqfd); }