Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Apr 2026 15:44:25 +0000
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Cc:        Jake Freeland <jfree@FreeBSD.org>
Subject:   git: b0be1af0c48b - releng/15.0 - timerfd: Fix interval callout scheduling
Message-ID:  <69e79b59.360c8.1c6f6aa0@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch releng/15.0 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=b0be1af0c48b3c326d56fbcb15f57554bf537f53

commit b0be1af0c48b3c326d56fbcb15f57554bf537f53
Author:     Jake Freeland <jfree@FreeBSD.org>
AuthorDate: 2026-03-20 06:33:03 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-04-15 19:02:35 +0000

    timerfd: Fix interval callout scheduling
    
    When a timerfd interval callout misses its scheduled activation time, a
    differential is calculated based on the actual activation time and the
    scheduled activation time. This differential is divided by the timerfd's
    interval time and the quotient is added to the timerfd's counter.
    
    Before this change, the next callout was scheduled to activate at:
    scheduled activation time + timerfd interval.
    
    This change fixes the scheduling of the next callout to activate at:
    actual activation time + timerfd interval - remainder.
    
    Approved by:            so
    Security:               FreeBSD-EN-26:06.timerfd
    Reviewed by:            markj
    Differential Revision:  https://reviews.freebsd.org/D55790
    MFC after:              2 weeks
    
    (cherry picked from commit 85c0f1a87da1fd1eb3e646e86f70e630c48da91a)
    (cherry picked from commit 9b785380f307e772eae0df017c982acd81d5879e)
---
 sys/kern/sys_timerfd.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/sys/kern/sys_timerfd.c b/sys/kern/sys_timerfd.c
index 565ab3ad6ee6..236dfe8bb96a 100644
--- a/sys/kern/sys_timerfd.c
+++ b/sys/kern/sys_timerfd.c
@@ -393,23 +393,25 @@ static void
 timerfd_expire(void *arg)
 {
 	struct timerfd *tfd = (struct timerfd *)arg;
-	struct timespec uptime;
+	sbintime_t exp, interval, now, next, diff;
 
 	++tfd->tfd_count;
 	tfd->tfd_expired = true;
 	if (timespecisset(&tfd->tfd_time.it_interval)) {
+		exp = tstosbt(tfd->tfd_time.it_value);
+		interval = tstosbt(tfd->tfd_time.it_interval);
+		now = sbinuptime();
+		next = now + interval;
+
 		/* Count missed events. */
-		nanouptime(&uptime);
-		if (timespeccmp(&uptime, &tfd->tfd_time.it_value, >)) {
-			timespecsub(&uptime, &tfd->tfd_time.it_value, &uptime);
-			tfd->tfd_count += tstosbt(uptime) /
-			    tstosbt(tfd->tfd_time.it_interval);
+		if (now > exp) {
+			diff = now - exp;
+			tfd->tfd_count += diff / interval;
+			next -= diff % interval;
 		}
-		timespecadd(&tfd->tfd_time.it_value,
-		    &tfd->tfd_time.it_interval, &tfd->tfd_time.it_value);
-		callout_schedule_sbt(&tfd->tfd_callout,
-		    tstosbt(tfd->tfd_time.it_value),
-		    0, C_ABSOLUTE);
+
+		callout_schedule_sbt(&tfd->tfd_callout, next, 0, C_ABSOLUTE);
+		tfd->tfd_time.it_value = sbttots(next);
 	} else {
 		/* Single shot timer. */
 		callout_deactivate(&tfd->tfd_callout);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69e79b59.360c8.1c6f6aa0>