]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/timer: Always use inactive_exit_timestamp if it is set
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 23 May 2023 14:24:47 +0000 (16:24 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 24 May 2023 08:05:08 +0000 (10:05 +0200)
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

index 419416b3255af0847cd52de6030d6e23ec204c78..4b8a1635121fcefd5cb770653364af859deaa4da 100644 (file)
@@ -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)