aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-04-28 16:28:49 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-05-03 16:49:54 +0000
commit7cb40543e96451092d5bc6bb3d96ebee364327e0 (patch)
treeea681a4ed4c9fc4b9908b9a7295cd75a1c28e941
parentb87a5b266d88b658ac0afa10f5f82adc21f4382a (diff)
downloadsrc-7cb40543e96451092d5bc6bb3d96ebee364327e0.tar.gz
src-7cb40543e96451092d5bc6bb3d96ebee364327e0.zip
filt_timerexpire: do not iterate over the interval
User-supplied data might make this loop too time-consuming. Divide directly, and handle both the possibility that we were woken up earlier, and arithmetic overflows/underflows from the calculation. Reported and tested by: pho (previous version) Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D30069
-rw-r--r--sys/kern/kern_event.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 33a6cdcda486..1067e7f128b7 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -718,6 +718,7 @@ filt_timerexpire_l(struct knote *kn, bool proc_locked)
{
struct kq_timer_cb_data *kc;
struct proc *p;
+ uint64_t delta;
sbintime_t now;
kc = kn->kn_ptr.p_v;
@@ -728,9 +729,17 @@ filt_timerexpire_l(struct knote *kn, bool proc_locked)
return;
}
- for (now = sbinuptime(); kc->next <= now; kc->next += kc->to)
- kn->kn_data++;
- KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */
+ now = sbinuptime();
+ if (now >= kc->next) {
+ delta = (now - kc->next) / kc->to;
+ if (delta == 0)
+ delta = 1;
+ kn->kn_data += delta;
+ kc->next += (delta + 1) * kc->to;
+ if (now >= kc->next) /* overflow */
+ kc->next = now + kc->to;
+ KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */
+ }
/*
* Initial check for stopped kc->p is racy. It is fine to