Module Name: src Committed By: thorpej Date: Thu Oct 21 01:11:21 UTC 2021
Modified Files: src/sys/kern: kern_event.c Log Message: Re-factor the code that computes the EVFILT_TIMER value into its own function. NFC. To generate a diff of this commit: cvs rdiff -u -r1.133 -r1.134 src/sys/kern/kern_event.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/kern_event.c diff -u src/sys/kern/kern_event.c:1.133 src/sys/kern/kern_event.c:1.134 --- src/sys/kern/kern_event.c:1.133 Thu Oct 21 00:54:15 2021 +++ src/sys/kern/kern_event.c Thu Oct 21 01:11:21 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_event.c,v 1.133 2021/10/21 00:54:15 thorpej Exp $ */ +/* $NetBSD: kern_event.c,v 1.134 2021/10/21 01:11:21 thorpej Exp $ */ /*- * Copyright (c) 2008, 2009, 2021 The NetBSD Foundation, Inc. @@ -63,7 +63,7 @@ #endif /* _KERNEL_OPT */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.133 2021/10/21 00:54:15 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_event.c,v 1.134 2021/10/21 01:11:21 thorpej Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1153,32 +1153,13 @@ knote_proc_exit(struct proc *p) #define FILT_TIMER_NOSCHED ((uintptr_t)-1) -static void -filt_timerexpire(void *knx) -{ - struct knote *kn = knx; - struct kqueue *kq = kn->kn_kq; - - mutex_spin_enter(&kq->kq_lock); - kn->kn_data++; - knote_activate_locked(kn); - if (kn->kn_sdata != FILT_TIMER_NOSCHED) { - KASSERT(kn->kn_sdata > 0 && kn->kn_sdata <= INT_MAX); - callout_schedule((callout_t *)kn->kn_hook, - (int)kn->kn_sdata); - } - mutex_spin_exit(&kq->kq_lock); -} - static int -filt_timerattach(struct knote *kn) +filt_timercompute(struct kevent *kev, uintptr_t *tticksp) { - callout_t *calloutp; - struct kqueue *kq; struct timespec ts; - int tticks, flags = 0; + uintptr_t tticks; - if (kn->kn_sfflags & ~(NOTE_TIMER_UNITMASK | NOTE_ABSTIME)) { + if (kev->fflags & ~(NOTE_TIMER_UNITMASK | NOTE_ABSTIME)) { return EINVAL; } @@ -1186,32 +1167,32 @@ filt_timerattach(struct knote *kn) * Convert the event 'data' to a timespec, then convert the * timespec to callout ticks. */ - switch (kn->kn_sfflags & NOTE_TIMER_UNITMASK) { + switch (kev->fflags & NOTE_TIMER_UNITMASK) { case NOTE_SECONDS: - ts.tv_sec = kn->kn_sdata; + ts.tv_sec = kev->data; ts.tv_nsec = 0; break; case NOTE_MSECONDS: /* == historical value 0 */ - ts.tv_sec = kn->kn_sdata / 1000; - ts.tv_nsec = (kn->kn_sdata % 1000) * 1000000; + ts.tv_sec = kev->data / 1000; + ts.tv_nsec = (kev->data % 1000) * 1000000; break; case NOTE_USECONDS: - ts.tv_sec = kn->kn_sdata / 1000000; - ts.tv_nsec = (kn->kn_sdata % 1000000) * 1000; + ts.tv_sec = kev->data / 1000000; + ts.tv_nsec = (kev->data % 1000000) * 1000; break; case NOTE_NSECONDS: - ts.tv_sec = kn->kn_sdata / 1000000000; - ts.tv_nsec = kn->kn_sdata % 1000000000; + ts.tv_sec = kev->data / 1000000000; + ts.tv_nsec = kev->data % 1000000000; break; default: return EINVAL; } - if (kn->kn_sfflags & NOTE_ABSTIME) { + if (kev->fflags & NOTE_ABSTIME) { struct timespec deadline = ts; /* @@ -1222,35 +1203,81 @@ filt_timerattach(struct knote *kn) */ nanotime(&ts); + /* Absolute timers do not repeat. */ + kev->data = FILT_TIMER_NOSCHED; + /* If we're past the deadline, then the event will fire. */ if (timespeccmp(&deadline, &ts, <=)) { - kn->kn_data = 1; - return 0; + tticks = FILT_TIMER_NOSCHED; + goto out; } /* Calculate how much time is left. */ timespecsub(&deadline, &ts, &ts); } else { /* EV_CLEAR automatically set for relative timers. */ - flags |= EV_CLEAR; + kev->flags |= EV_CLEAR; } tticks = tstohz(&ts); /* if the supplied value is under our resolution, use 1 tick */ if (tticks == 0) { - if (kn->kn_sdata == 0) + if (kev->data == 0) return EINVAL; tticks = 1; + } else if (tticks > INT_MAX) { + return EINVAL; } - if ((kn->kn_flags & EV_ONESHOT) != 0 || - (kn->kn_sfflags & NOTE_ABSTIME) != 0) { + if ((kev->flags & EV_ONESHOT) != 0) { /* Timer does not repeat. */ - kn->kn_sdata = FILT_TIMER_NOSCHED; + kev->data = FILT_TIMER_NOSCHED; } else { KASSERT((uintptr_t)tticks != FILT_TIMER_NOSCHED); - kn->kn_sdata = tticks; + kev->data = tticks; + } + + out: + *tticksp = tticks; + + return 0; +} + +static void +filt_timerexpire(void *knx) +{ + struct knote *kn = knx; + struct kqueue *kq = kn->kn_kq; + + mutex_spin_enter(&kq->kq_lock); + kn->kn_data++; + knote_activate_locked(kn); + if (kn->kn_sdata != FILT_TIMER_NOSCHED) { + KASSERT(kn->kn_sdata > 0 && kn->kn_sdata <= INT_MAX); + callout_schedule((callout_t *)kn->kn_hook, + (int)kn->kn_sdata); + } + mutex_spin_exit(&kq->kq_lock); +} + +static int +filt_timerattach(struct knote *kn) +{ + callout_t *calloutp; + struct kqueue *kq; + uintptr_t tticks; + int error; + + struct kevent kev = { + .flags = kn->kn_flags, + .fflags = kn->kn_sfflags, + .data = kn->kn_sdata, + }; + + error = filt_timercompute(&kev, &tticks); + if (error) { + return error; } if (atomic_inc_uint_nv(&kq_ncallouts) >= kq_calloutmax || @@ -1262,11 +1289,20 @@ filt_timerattach(struct knote *kn) kq = kn->kn_kq; mutex_spin_enter(&kq->kq_lock); - kn->kn_flags |= flags; + + kn->kn_sdata = kev.data; + kn->kn_flags = kev.flags; + KASSERT(kn->kn_sfflags == kev.fflags); kn->kn_hook = calloutp; - mutex_spin_exit(&kq->kq_lock); - callout_reset(calloutp, tticks, filt_timerexpire, kn); + if (__predict_false(tticks == FILT_TIMER_NOSCHED)) { + kn->kn_data = 1; + } else { + KASSERT(tticks <= INT_MAX); + callout_reset(calloutp, (int)tticks, filt_timerexpire, kn); + } + + mutex_spin_exit(&kq->kq_lock); return (0); }