mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
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. Security: FreeBSD-26:06.timerfd Approved by: so Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D55790 MFC after: 2 weeks (cherry picked from commit 85c0f1a87da1fd1eb3e646e86f70e630c48da91a) (cherry picked from commit 3c00f603a2801fd780666f9e94a26f264a887c90)
This commit is contained in:
parent
74e09b2d0d
commit
6ffe3a31b8
1 changed files with 13 additions and 11 deletions
|
|
@ -394,23 +394,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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue