diff --git sys/kern/kern_event.c sys/kern/kern_event.c index 72386e0..cd6076e 100644 --- sys/kern/kern_event.c +++ sys/kern/kern_event.c @@ -529,14 +529,24 @@ knote_fork(struct knlist *list, int pid) * interval timer support code. */ static __inline sbintime_t -timer2sbintime(intptr_t data) +timer2sbintime(intptr_t data, int flags) { + sbintime_t modifier; + + modifier = SBT_1MS; + + if (flags & NOTE_SECONDS) + modifier = SBT_1S; + else if (flags & NOTE_USECONDS) + modifier = SBT_1US; + else if (flags & NOTE_NSECONDS) + modifier = SBT_1NS; #ifdef __LP64__ - if (data > INT64_MAX / SBT_1MS) + if (data > INT64_MAX / modifier) return INT64_MAX; #endif - return (SBT_1MS * data); + return (modifier * data); } static void @@ -544,16 +554,20 @@ filt_timerexpire(void *knx) { struct callout *calloutp; struct knote *kn; + int flag; kn = knx; kn->kn_data++; KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */ + flag = 0; if ((kn->kn_flags & EV_ONESHOT) != EV_ONESHOT) { calloutp = (struct callout *)kn->kn_hook; + if ((kn->kn_sfflags & NOTE_MONOTONIC) == NOTE_MONOTONIC) + flag = C_ABSOLUTE; callout_reset_sbt_on(calloutp, - timer2sbintime(kn->kn_sdata), 0 /* 1ms? */, - filt_timerexpire, kn, PCPU_GET(cpuid), 0); + timer2sbintime(kn->kn_sdata, kn->kn_sfflags), 0 /* 1ms? */, + filt_timerexpire, kn, PCPU_GET(cpuid), flag); } } @@ -564,17 +578,32 @@ static int filt_timerattach(struct knote *kn) { struct callout *calloutp; + struct timespec ts; sbintime_t to; + int64_t now; + int flag; unsigned int ncallouts; if ((intptr_t)kn->kn_sdata < 0) return (EINVAL); if ((intptr_t)kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0) kn->kn_sdata = 1; - to = timer2sbintime(kn->kn_sdata); + to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags); if (to < 0) return (EINVAL); + if ((kn->kn_sfflags & NOTE_MONOTONIC) == NOTE_MONOTONIC) { + if ((kn->kn_flags & EV_ONESHOT) == 0) + return (EINVAL); + nanouptime(&ts); + now = ((ts.tv_sec * 1000000000) + ts.tv_nsec); + if (to <= timer2sbintime(now, NOTE_NSECONDS)) { + kn->kn_data++; + KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */ + return(0); + } + } + ncallouts = atomic_load_explicit(&kq_ncallouts, memory_order_relaxed); do { if (ncallouts >= kq_calloutmax) @@ -588,8 +617,11 @@ filt_timerattach(struct knote *kn) calloutp = malloc(sizeof(*calloutp), M_KQUEUE, M_WAITOK); callout_init(calloutp, CALLOUT_MPSAFE); kn->kn_hook = calloutp; + flag = 0; + if ((kn->kn_sfflags & NOTE_MONOTONIC) == NOTE_MONOTONIC) + flag = C_ABSOLUTE; callout_reset_sbt_on(calloutp, to, 0 /* 1ms? */, - filt_timerexpire, kn, PCPU_GET(cpuid), 0); + filt_timerexpire, kn, PCPU_GET(cpuid), flag); return (0); } diff --git sys/sys/event.h sys/sys/event.h index bad8c9e..28ed84a 100644 --- sys/sys/event.h +++ sys/sys/event.h @@ -133,6 +133,12 @@ struct kevent { #define NOTE_TRACKERR 0x00000002 /* could not track child */ #define NOTE_CHILD 0x00000004 /* am a child process */ +/* additional flags for EVFILT_TIMER */ +#define NOTE_SECONDS 0x00000001 /* data is seconds */ +#define NOTE_USECONDS 0x00000002 /* data is microseconds */ +#define NOTE_NSECONDS 0x00000004 /* data is nanoseconds */ +#define NOTE_MONOTONIC 0x00000008 /* absolute time since boot */ + struct knote; SLIST_HEAD(klist, knote); struct kqueue;