Is there a way I can do what I want to do with boost::process? Or how can I do it?
If you have the child process killing the parent, there's always going to be a race condition by definition.
The quick hack is to put a sleep statement at the start of the installer script, but the correct solution is to explicitly synchronize with the child:
- have the installer script detect whether it's running interactively (ie, being run manually from a terminal instead of by your service)
- if it is non-interactive (your use case), have it wait for some input in stdin
- connect the stdin pipe when you create the child
- detach the child and then write something to tell the child it's safe
Other synchronization mechanisms are available, you could use a lockfile or a signal - you just need to make sure the child doesn't do anything until after the parent has detached it.
I turns out (from this question, which leads to the excellent-but-unfindable systemd.kill
manpage) that systemd
has four different ways of stopping a unit, controlled by the KillMode
variable in your unit configuration:
control-group
will send SIGTERM
(by default, overridable with KillSignal
) to every process in the unit's cgroup. That means both parent and child.
mixed
will send SIGTERM
(or KillSignal
) to your main process and SIGKILL
to the child.
process
will kill only the main process and leave the child alone
none
is not recommended, it will just run your ExecStop
procedure
You can probably just set KillMode=process
, but note that if SendSIGKill
or SendSIGUP
are true, those signals will still be delivered to your child after TimeoutStopSec
.
It seems like it might be simpler to restart your service and have a launch script that can update it at startup, or to perform the update in your ExecStop
procedure, than to persuade systemd
to leave the child alone until the update is complete, without the risk of a hung child updater hanging around forever.
Either way, your remaining problems are exclusively with systemd
rather than with boost.Process
.