In Debian bug report about starting anacron on resume, there is the claim that this snippet (simplified for brevitiy) might be triggered while suspending instead of on resuming, because of the way the systemd dependencies work. I am unable to understand the race condition indicated there using the systemd documentation and the unit files shipped with systemd.
[Unit]
Description=Do something at resume
After=suspend.target
[Service]
ExecStart=/bin/do-something
[Install]
WantedBy=suspend.target
The author of this post goes on citing systemd-suspend.service
, which contains the following declarations (again trimmed down to the relevant statements)
[Unit]
After=sleep.target
Requires=sleep.target
followed by the claim that two different units, both ordering after sleep.target
are run in parallel and thus there is no ordering between those two units. I perfectly agree on that point, but there are no two units both depending on sleep.target
, as I understand it. The declaration in systemd-suspend.service
makes sure that sleep.target
is completely started before going to sleep, so all units that are depended-on by sleep.target
are started. But looking at suspend.target
(the target the original unit file really depends on), I find the following declarations:
[Unit]
BindsTo=systemd-suspend.service
After=systemd-suspend.service
I understand this file as declaring the suspend.target
is sucessfully started only after systemd-suspend.service
is sucessfully started. Now, looking into systemd-suspend.service
again, I find the following declarations in that file:
[Service]
Type=oneshot
Exec=/lib/systemd/systemd-sleep suspend
As I understand one-shot services, they do not enter the "started" state until the Exec
command finished. So anything ordering After
this service can not get started until systemd-sleep
finished. Finally, taking a look at systemd-sleep, it contains the magic write of some string to /sys/power/state
, which blocks until the system is resumed. This should ensure that everything that wants to be started after systemd-suspend.service
is indeed not started before resume.
The reason that I claim that writing to /sys/power/state
blocks is that this write is handled by the sysfs store function for that file, which calls pm_suspend
for non-hibernate modes, which in turn calls enter_state
(directly before pm_suspend
in the same source file) which obviously doesn't return before resuming.