Как systemd обрабатывает завершение дочернего процесса управляемого процесса?

Как systemd обрабатывает завершение дочернего процесса управляемого процесса?

Как systemdобрабатывается смерть потомков управляемых процессов?

Предположим, что systemdзапускается демон foo, который затем запускает три других демона: bar1, bar2, и bar3. Будет ли systemdчто-либо делать, fooесли bar2неожиданно завершится? Насколько я понимаю, в Service Management Facility (SMF) на Solaris fooбудет завершен или перезапущен, если вы не укажете startdиное, изменив свойство ignore_error. Ведет ли systemdсебя по-другому?

Редактирование №1:

Я написал тестовый демон для проверки systemdповедения . Демон вызывается, mother_daemonпотому что он порождает потомков.

#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;
  }

Это контролируется с помощью systemdустройства, называемого 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

Устройство mother_daemon.serviceуправляется mother_daemon.target:

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

Когда я запускаю sudo systemctl start mother_daemon.target(после sudo systemctl daemon-reload), я вижу родительский демон и пять дочерних демонов.

Уничтожение одного из дочерних процессов не оказывает никакого влияния на родительский процесс, но уничтожение родительского процесса (и, следовательно, запуск перезапуска) приводит к перезапуску дочерних процессов.

Остановка mother_daemon.targetзаканчивается sudo systemctl stop mother_daemon.targetи у детей.

Думаю, это ответ на мой вопрос.

решение1

Это не так.

Основной процесс обрабатывает смерть своих дочерних процессов обычным образом.

Это мир POSIX. Если процесс A разветвил B, а процесс B разветвил C, D и E; тогда процесс B — это то, что видит SIGCHLDи wait()статус завершения C, D и E. Процесс A не знает, что происходит с C, D и E, и это не зависит от systemd.

Для того чтобы А узнал о завершении C, D и E, должны произойти две вещи.

(С BSD можно помудрить kevent(). Но это вопрос Linux.)

решение2

systemdимеет концепцию основного процесса. В документации systemd это называется "основной процесс службы" или просто "основной процесс".

Пример 4 вsystemd.service документацияописывает основной процесс, который рассчитывается, когда Type=forking.

Документация Restart=в systemd.service docsописать различные возможности запуска службы по отношению к основному процессу.

Вот ключевой текст из «примера 4», ссылка на который приведена выше:

systemd будет считать, что служба находится в процессе инициализации, пока исходная программа все еще работает. После успешного завершения и при этом остается хотя бы один процесс (и RemainAfterExit=no), служба считается запущенной.

Часто традиционный демон состоит только из одного процесса. Поэтому, если после завершения исходного процесса остается только один процесс, systemd будет считать этот процесс основным процессом службы. В этом случае переменная $MAINPID будет доступна в ExecReload=, ExecStop= и т. д.

Если останется более одного процесса, systemd не сможет определить основной процесс, поэтому не будет предполагать, что он есть. В этом случае $MAINPID не будет расширяться ни во что. Однако, если процесс решит записать традиционный PID-файл, systemd сможет прочитать основной PID оттуда. Пожалуйста, установите PIDFile= соответствующим образом.

Связанный контент