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