6

How does systemd handle the death of the children of managed processes?

Suppose that systemd launches the daemon foo, which then launches three other daemons: bar1, bar2, and bar3. Will systemd do anything to foo if bar2 terminates unexpectedly? From my understanding, under Service Management Facility (SMF) on Solaris foo would be killed or restarted if you didn't tell startd otherwise by changing the property ignore_error. Does systemd behave differently?

Edit #1:

I've written a test daemon to test systemd's behavior. The daemon is called mother_daemon because it spawns children.

#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>

using namespace std;

int main(int argc, char* argv[])
{
  cout << "Hi! I'm going to fork and make 5 child processes!" << endl;

  for (int i = 0; i < 5; i++)
    {
    pid_t pid = fork();

    if (pid > 0)
      {
    cout << "I'm the parent process, and i = " << i << endl;
      }
    if (pid == 0)
      {
      // The following four lines rename the process to make it easier to keep track of with ps
    int argv0size = strlen(argv[0]);
    string childThreadName = "mother_daemon child thread PID: ";
    childThreadName.append( to_string(::getpid()) );
    strncpy(argv[0],childThreadName.c_str(),argv0size + 25);

    cout << "I'm a child process, and i = " << i << endl;
    pause();
    // I don't want each child process spawning its own process
    break;
      }
    }
  pause();
  return 0;
  }

This is controlled with a systemd unit called mother_daemon.service:

[Unit]
Description=Testing how systemd handles the death of the children of a managed process
StopWhenUnneeded=true

[Service]
ExecStart=/home/my_user/test_program/mother_daemon
Restart=always

The mother_daemon.service unit is controlled by the mother_daemon.target:

[Unit]
Description=A target that wants mother_daemon.service
Wants=mother_daemon.service

When I run sudo systemctl start mother_daemon.target (after sudo systemctl daemon-reload) I can see the parent daemon and the five children daemons.

Killing one of the children has no effect on the parent, but killing the parent (and thus triggering a restart) does restart the children.

Stopping mother_daemon.target with sudo systemctl stop mother_daemon.target ends the children as well.

I think that this answers my question.

  • What happens when you test this situation with example services? – Mark Stosberg Sep 26 '16 at 18:54
4

It doesn't.

The main process handles the death of its children, in the normal way.

This is the POSIX world. If process A has forked B, and process B has forked C, D, and E; then process B is what sees the SIGCHLD and wait() status from the termination of C, D, and E. Process A is unaware of what happens to C, D, and E, and this is irrespective of systemd.

For A to be aware of C, D, and E terminating, two things have to happen.

(One can get clever with kevent() on the BSDs. But this is a Linux question.)

| improve this answer | |
3

systemd has the concept of a main process. In the systemd documentation this is referred to as the "main service process" or simply the "main process".

Example 4 in the systemd.service documentation describes have the main process is calculated when Type=forking.

The documentation for Restart= in the systemd.service docs describe the different possibilities for when a service is started in relation to the main process.

Here's the key text from "example 4" linked above:

systemd will consider the service to be in the process of initialization while the original program is still running. Once it exits successfully and at least a process remains (and RemainAfterExit=no), the service is considered started.

Often, a traditional daemon only consists of one process. Therefore, if only one process is left after the original process terminates, systemd will consider that process the main process of the service. In that case, the $MAINPID variable will be available in ExecReload=, ExecStop=, etc.

In case more than one process remains, systemd will be unable to determine the main process, so it will not assume there is one. In that case, $MAINPID will not expand to anything. However, if the process decides to write a traditional PID file, systemd will be able to read the main PID from there. Please set PIDFile= accordingly.

| improve this answer | |
  • Is there an advantage in using Type=forking if the original daemon does not die? I understand the advantage if the original daemon forks and then dies, but my daemon forks and stays alive to keep forking at a later time. Note: I know that this isn't the "systemd way". Ideally systemd would manage all the processes, but in my particular case that's not possible. – Dennis Dragonbain Sep 28 '16 at 16:08
  • 1
    That's a separate question. :) – Mark Stosberg Sep 28 '16 at 16:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.