systemd 如何處理託管流程子程序的死亡?

systemd 如何處理託管流程子程序的死亡?

如何systemd處理託管進程的子進程的死亡?

假設systemd啟動守護進程foo,然後守護程式啟動其他三個守護程式:bar1bar2bar3。如果意外終止,會systemd採取什麼措施嗎?根據我的理解,如果您沒有透過更改屬性來告知,Solaris 上的服務管理工具 (SMF)將被終止或重新啟動。行為有什麼不同嗎?foobar2foostartdignore_errorsystemd

編輯#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.targetsudo systemctl stop mother_daemon.target孩子。

我認為這回答了我的問題。

答案1

事實並非如此。

主進程以正常方式處理其子進程的死亡。

這就是 POSIX 世界。如果進程A分叉了B,且進程B分叉了C、D和E;那麼進程 B 會看到C、D 和 E 終止後的狀態SIGCHLDwait()

為了讓 A 知道 C、D 和 E 終止,必須發生兩件事。

kevent()(人們可以在 BSD 上變得聰明。但這是一個 Linux 問題。)

答案2

systemd有主進程的概念。在 systemd 文件中,這被稱為“主服務進程”或簡稱為“主進程”。

範例 4 中systemd.service 文檔描述了計算時的主要流程Type=forking

Restart=systemd.service 文檔中的文檔描述與主程序相關的服務啟動時的不同可能性。

以下是上面連結的「範例 4」中的關鍵文字:

systemd 會認為服務正在初始化,而原始程式仍在運行。一旦成功退出並且至少有一個進程保留(並且RemainAfterExit = no),則服務被視為已啟動。

通常,傳統守護程序僅包含一個程序。因此,如果原進程終止後只剩下一個進程,systemd 就會認為該進程是服務的主進程。在這種情況下,$MAINPID 變數將在 ExecReload=、ExecStop= 等中可用。

如果存在多個進程,systemd 將無法確定主進程,因此它不會假設存在一個進程。在這種情況下,$MAINPID 將不會擴展為任何內容。然而,如果進程決定寫入傳統的 PID 文件,systemd 將能夠從那裡讀取主 PID。請相應地設定 PIDFile=。

相關內容