diff options
author | ian <ian@FreeBSD.org> | 2014-10-04 15:59:15 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2014-10-04 15:59:15 +0000 |
commit | e35c0ad650d6714add810f7245b92c3af0f00159 (patch) | |
tree | cfe31fbad1617288c93a4ebbc3dfc895f0878078 /sys/kern | |
parent | 60bf73506ecd9b277bfeb5eaa63fa80715d98698 (diff) | |
download | FreeBSD-src-e35c0ad650d6714add810f7245b92c3af0f00159.zip FreeBSD-src-e35c0ad650d6714add810f7245b92c3af0f00159.tar.gz |
Make kevent(2) periodic timer events more reliably periodic. The event
callout is now scheduled using the C_ABSOLUTE flag, and the absolute time
of each event is calculated as the time the previous event was scheduled
for plus the interval. This ensures that latency in processing a given
event doesn't perturb the arrival time of any subsequent events.
Reviewed by: jhb
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_event.c | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 7488652..55bffe7 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -569,9 +569,10 @@ filt_timerexpire(void *knx) if ((kn->kn_flags & EV_ONESHOT) != EV_ONESHOT) { calloutp = (struct callout *)kn->kn_hook; - callout_reset_sbt_on(calloutp, - timer2sbintime(kn->kn_sdata, kn->kn_sfflags), 0, - filt_timerexpire, kn, PCPU_GET(cpuid), 0); + *kn->kn_ptr.p_nexttime += timer2sbintime(kn->kn_sdata, + kn->kn_sfflags); + callout_reset_sbt_on(calloutp, *kn->kn_ptr.p_nexttime, 0, + filt_timerexpire, kn, PCPU_GET(cpuid), C_ABSOLUTE); } } @@ -607,11 +608,13 @@ filt_timerattach(struct knote *kn) kn->kn_flags |= EV_CLEAR; /* automatically set */ kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */ + kn->kn_ptr.p_nexttime = malloc(sizeof(sbintime_t), M_KQUEUE, M_WAITOK); calloutp = malloc(sizeof(*calloutp), M_KQUEUE, M_WAITOK); callout_init(calloutp, CALLOUT_MPSAFE); kn->kn_hook = calloutp; - callout_reset_sbt_on(calloutp, to, 0, - filt_timerexpire, kn, PCPU_GET(cpuid), 0); + *kn->kn_ptr.p_nexttime = to + sbinuptime(); + callout_reset_sbt_on(calloutp, *kn->kn_ptr.p_nexttime, 0, + filt_timerexpire, kn, PCPU_GET(cpuid), C_ABSOLUTE); return (0); } @@ -625,6 +628,7 @@ filt_timerdetach(struct knote *kn) calloutp = (struct callout *)kn->kn_hook; callout_drain(calloutp); free(calloutp, M_KQUEUE); + free(kn->kn_ptr.p_nexttime, M_KQUEUE); old = atomic_fetch_sub_explicit(&kq_ncallouts, 1, memory_order_relaxed); KASSERT(old > 0, ("Number of callouts cannot become negative")); kn->kn_status |= KN_DETACHED; /* knlist_remove sets it */ |