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