df98bb
From 73bf41a783edbff1b367e645956ed602de1889e2 Mon Sep 17 00:00:00 2001
df98bb
From: Insun <iplayinsun@gmail.com>
df98bb
Date: Sun, 28 Oct 2018 21:26:13 +0900
df98bb
Subject: [PATCH] core: don't drop timer expired but not yet processed when
df98bb
 system date is changed
df98bb
df98bb
There is difference between time set by the user and real elapsed time because of accuracy feature.
df98bb
If you change the system date(or time) between these times, the timer drops.
df98bb
df98bb
You can easily reproduce it with the following command.
df98bb
-----------------------------------------------------------
df98bb
$ systemd-run --on-active=3s ls; sleep 3; date -s "`date`"
df98bb
-----------------------------------------------------------
df98bb
df98bb
In the following command, the problem is rarely reproduced. But it exists.
df98bb
---------------------------------------------------------------------------------------------
df98bb
$ systemd-run --on-active=3s --timer-property=AccuracySec=1us ls ; sleep 1; date -s "`date`"
df98bb
---------------------------------------------------------------------------------------------
df98bb
df98bb
Note : Global AccuracySec value.
df98bb
----------------------------------------------------------------------
df98bb
$ cat /etc/systemd/system.conf
df98bb
DefaultTimerAccuracySec=1min
df98bb
----------------------------------------------------------------------
df98bb
df98bb
(cherry picked from commit fee04d7f3ab810e99b97535ca5fda2f9517acda9)
df98bb
df98bb
Related: #1899402
df98bb
---
df98bb
 src/core/timer.c | 18 +++++++++---------
df98bb
 1 file changed, 9 insertions(+), 9 deletions(-)
df98bb
df98bb
diff --git a/src/core/timer.c b/src/core/timer.c
df98bb
index 281ac7f97f..ef240a6f19 100644
df98bb
--- a/src/core/timer.c
df98bb
+++ b/src/core/timer.c
df98bb
@@ -262,7 +262,7 @@ static void timer_set_state(Timer *t, TimerState state) {
df98bb
         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
df98bb
 }
df98bb
 
df98bb
-static void timer_enter_waiting(Timer *t, bool initial);
df98bb
+static void timer_enter_waiting(Timer *t, bool initial, bool time_change);
df98bb
 
df98bb
 static int timer_coldplug(Unit *u) {
df98bb
         Timer *t = TIMER(u);
df98bb
@@ -274,7 +274,7 @@ static int timer_coldplug(Unit *u) {
df98bb
                 return 0;
df98bb
 
df98bb
         if (t->deserialized_state == TIMER_WAITING)
df98bb
-                timer_enter_waiting(t, false);
df98bb
+                timer_enter_waiting(t, false, false);
df98bb
         else
df98bb
                 timer_set_state(t, t->deserialized_state);
df98bb
 
df98bb
@@ -334,7 +334,7 @@ static void add_random(Timer *t, usec_t *v) {
df98bb
         log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
df98bb
 }
df98bb
 
df98bb
-static void timer_enter_waiting(Timer *t, bool initial) {
df98bb
+static void timer_enter_waiting(Timer *t, bool initial, bool time_change) {
df98bb
         bool found_monotonic = false, found_realtime = false;
df98bb
         bool leave_around = false;
df98bb
         triple_timestamp ts;
df98bb
@@ -444,7 +444,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
df98bb
 
df98bb
                         v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value);
df98bb
 
df98bb
-                        if (!initial &&
df98bb
+                        if (!initial && !time_change &&
df98bb
                             v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) &&
df98bb
                             IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
df98bb
                                 /* This is a one time trigger, disable it now */
df98bb
@@ -642,7 +642,7 @@ static int timer_start(Unit *u) {
df98bb
         }
df98bb
 
df98bb
         t->result = TIMER_SUCCESS;
df98bb
-        timer_enter_waiting(t, true);
df98bb
+        timer_enter_waiting(t, true, false);
df98bb
         return 1;
df98bb
 }
df98bb
 
df98bb
@@ -764,14 +764,14 @@ static void timer_trigger_notify(Unit *u, Unit *other) {
df98bb
         case TIMER_ELAPSED:
df98bb
 
df98bb
                 /* Recalculate sleep time */
df98bb
-                timer_enter_waiting(t, false);
df98bb
+                timer_enter_waiting(t, false, false);
df98bb
                 break;
df98bb
 
df98bb
         case TIMER_RUNNING:
df98bb
 
df98bb
                 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
df98bb
                         log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
df98bb
-                        timer_enter_waiting(t, false);
df98bb
+                        timer_enter_waiting(t, false, false);
df98bb
                 }
df98bb
                 break;
df98bb
 
df98bb
@@ -813,7 +813,7 @@ static void timer_time_change(Unit *u) {
df98bb
                 t->last_trigger.realtime = ts;
df98bb
 
df98bb
         log_unit_debug(u, "Time change, recalculating next elapse.");
df98bb
-        timer_enter_waiting(t, false);
df98bb
+        timer_enter_waiting(t, false, true);
df98bb
 }
df98bb
 
df98bb
 static void timer_timezone_change(Unit *u) {
df98bb
@@ -825,7 +825,7 @@ static void timer_timezone_change(Unit *u) {
df98bb
                 return;
df98bb
 
df98bb
         log_unit_debug(u, "Timezone change, recalculating next elapse.");
df98bb
-        timer_enter_waiting(t, false);
df98bb
+        timer_enter_waiting(t, false, false);
df98bb
 }
df98bb
 
df98bb
 static const char* const timer_base_table[_TIMER_BASE_MAX] = {