core/timer: Prevent timer looping when unit cannot start
When a unit job finishes early (e.g. when fork(2) fails) triggered unit goes
through states
stopped->failed (or failed->failed),
in case a ExecStart= command fails unit passes through
stopped->starting->failed.
The former transition doesn't result in unit active/inactive timestamp being
updated and timer (OnUnitActiveSec= or OnUnitInactiveSec=) would use an expired
timestamp triggering immediately again (repeatedly).
This patch exploits timer's last trigger timestamp to ensure the timer isn't
triggered more frequently than OnUnitActiveSec=/OnUnitInactiveSec= period.
Steps to reproduce:
0) Create sample units:
cat >~/.config/systemd/user/looper.service <<EOD
[Service]
ExecStart=/usr/bin/sleep 2
EOD
cat >~/.config/systemd/user/looper.timer <<EOD
[Timer]
AccuracySec=5
OnUnitActiveSec=5
EOD
1) systemctl --user daemon-reload
2) systemctl --user start looper.timer
# to have first activation timestamp/sentinel
systemctl --user start looper.service
o Observe the service is being regularly triggered.
3) systemctl set-property user@$UID.service TasksMax=2
o Observe the tight looping as long as the looper.service cannot be started.
Ref: #5969
This commit is contained in:
committed by
Lennart Poettering
parent
3e52ec4301
commit
204d140c4d
@@ -431,6 +431,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
|
||||
|
||||
if (base <= 0)
|
||||
continue;
|
||||
base = MAX(base, t->last_trigger.monotonic);
|
||||
|
||||
break;
|
||||
|
||||
@@ -443,6 +444,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
|
||||
|
||||
if (base <= 0)
|
||||
continue;
|
||||
base = MAX(base, t->last_trigger.monotonic);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user