diff --git a/src/core/timer.c b/src/core/timer.c index 7f779fb936b..75f1dc1f8be 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -346,6 +346,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) { bool found_monotonic = false, found_realtime = false; bool leave_around = false; triple_timestamp ts; + dual_timestamp dts; TimerValue *v; Unit *trigger; int r; @@ -389,10 +390,10 @@ static void timer_enter_waiting(Timer *t, bool time_change) { /* To make the delay due to RandomizedDelaySec= work even at boot, * if the scheduled time has already passed, set the time when systemd - * first started as the scheduled time. - * Also, we don't have to check t->persistent since the logic implicitly express true. */ - if (v->next_elapse < UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime) - v->next_elapse = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime; + * first started as the scheduled time. */ + dual_timestamp_from_monotonic(&dts, UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic); + if (v->next_elapse < dts.realtime) + v->next_elapse = dts.realtime; if (!found_realtime) t->next_elapse_realtime = v->next_elapse; diff --git a/test/TEST-53-ISSUE-16347/Makefile b/test/TEST-53-ISSUE-16347/Makefile new file mode 120000 index 00000000000..e9f93b1104c --- /dev/null +++ b/test/TEST-53-ISSUE-16347/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-53-ISSUE-16347/test.sh b/test/TEST-53-ISSUE-16347/test.sh new file mode 100755 index 00000000000..089768e8ddb --- /dev/null +++ b/test/TEST-53-ISSUE-16347/test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -e + +TEST_DESCRIPTION="test timer units when initial clock is ahead" +TEST_NO_NSPAWN=1 + +future_date=$(date -u +%Y-%m-%dT%H:%M:%S -d '+3 days') +QEMU_OPTIONS="-rtc base=${future_date}" +. $TEST_BASE_DIR/test-functions + +do_test "$@" 53 diff --git a/test/units/testsuite-53.service b/test/units/testsuite-53.service new file mode 100644 index 00000000000..d4dd8cc72f8 --- /dev/null +++ b/test/units/testsuite-53.service @@ -0,0 +1,7 @@ +[Unit] +Description=TEST-53-ISSUE-16347 + +[Service] +ExecStartPre=rm -f /failed /testok +ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +Type=oneshot diff --git a/test/units/testsuite-53.sh b/test/units/testsuite-53.sh new file mode 100755 index 00000000000..3536c242712 --- /dev/null +++ b/test/units/testsuite-53.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -ex +set -o pipefail + +>/failed + +# Reset host date to current time, 3 days in the past. +date -s "-3 days" + +# Run a timer for every 15 minutes. +systemd-run --unit test-timer --on-calendar "*:0/15:0" true + +next_elapsed=$(systemctl show test-timer.timer -p NextElapseUSecRealtime --value) +next_elapsed=$(date -d "${next_elapsed}" +%s) +now=$(date +%s) +time_delta=$((next_elapsed - now)) + +# Check that the timer will elapse in less than 20 minutes. +((0 < time_delta && time_delta < 1200)) || { + echo 'Timer elapse outside of the expected 20 minute window.' + echo " next_elapsed=${next_elapsed}" + echo " now=${now}" + echo " time_delta=${time_delta}" + echo '' +} >>/failed + +if test ! -s /failed ; then + rm -f /failed + touch /testok +fi