From 6546045fa0bf84737bd8b2e1e8bf7dd3941d8352 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 23 May 2023 16:24:47 +0200 Subject: [PATCH 1/2] core/timer: Always use inactive_exit_timestamp if it is set If we're doing a daemon-reload, we'll be going from TIMER_DEAD => TIMER_WAITING, so we won't use inactive_exit_timestamp because TIMER_DEAD != UNIT_ACTIVE, even though inactive_exit_timestamp is serialized/deserialized and will be valid after the daemon-reload. This issue can lead to timers never firing as we'll always calculate the next elapse based on the current realtime on daemon-reload, so if daemon-reload happens often enough, the elapse interval will be moved into the future every time, which means the timer will never trigger. To fix the issue, let's always use inactive_exit_timestamp if it is set, and only fall back to the current realtime if it is not set. --- src/core/timer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/core/timer.c b/src/core/timer.c index 419416b3255..4b8a1635121 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -401,12 +401,10 @@ static void timer_enter_waiting(Timer *t, bool time_change) { if (t->last_trigger.realtime > 0) b = t->last_trigger.realtime; - else { - if (state_translation_table[t->state] == UNIT_ACTIVE) - b = UNIT(t)->inactive_exit_timestamp.realtime; - else - b = ts.realtime; - } + else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp)) + b = UNIT(t)->inactive_exit_timestamp.realtime; + else + b = ts.realtime; r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse); if (r < 0) From e21f75afcd95a46261a36a2614712eff6bc119f4 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 24 May 2023 11:41:37 +0200 Subject: [PATCH 2/2] timer: Use dual_timestamp_is_set() in one more place --- src/core/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/timer.c b/src/core/timer.c index 4b8a1635121..aab376e5cc7 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -399,7 +399,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) { * to that. If we don't, just start from * the activation time. */ - if (t->last_trigger.realtime > 0) + if (dual_timestamp_is_set(&t->last_trigger)) b = t->last_trigger.realtime; else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp)) b = UNIT(t)->inactive_exit_timestamp.realtime;