我目前正在开发一个 systemd 守护进程。我面临的问题是守护进程在启动后 1 分 30 秒被杀死,因为未检测到分叉。
我正在使用该int daemon(int nochdir, int noclose)
函数来守护进程。
int main()
{
openlog("shutdownd", LOG_PID, LOG_DAEMON);
if(daemon(0, 0) != 0)
{
syslog(LOG_ERR, "Error daemonizing process : %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
syslog(LOG_NOTICE, "Daemon started !\n");
pthread_create(&threads[0], NULL, &alimThread, NULL);
pthread_create(&threads[1], NULL, &extinctThread, NULL);
pthread_create(&threads[2], NULL, &blinkThread, NULL);
while(1)
{
}
syslog(LOG_NOTICE, "Daemon stopped !\n");
exit(EXIT_SUCCESS);
}
这是服务文件/etc/systemd/system/shutdownd.service
[Unit]
Description=Shutdown Daemon
After=syslog.target
[Service]
Type=forking
PIDFile=/var/run/shutdownd.pid
ExecStartPre=/bin/rm -f /var/run/shutdownd.pid
ExecStartPre=/usr/bin/shutdownd-exportGpio.sh
ExecStart=/usr/bin/shutdownd
Restart=on-abort
[Install]
WantedBy=multi-user.target
守护进程函数应该分叉进程并将其与终端分离,我还关闭文件描述符并将工作目录更改为 /。
然而,systemd 似乎没有检测到分叉,因为它在 1 分 30 秒后杀死了我正在运行的守护进程。
Sep 8 13:52:50 raspberrypi systemd[1]: shutdownd.service: PID file /var/run/shutdownd.pid not readable (yet?) after start: No such file or directory
Sep 8 13:52:50 raspberrypi shutdownd[293]: Daemon started !
Sep 8 13:52:50 raspberrypi shutdownd[293]: [Extinct] Value changed to 0
Sep 8 13:52:50 raspberrypi shutdownd[293]: OFF
Sep 8 13:52:50 raspberrypi shutdownd[293]: [Alim] Value changed to 0
Sep 8 13:52:50 raspberrypi shutdownd[293]: OFF
Sep 8 13:53:46 raspberrypi shutdownd[293]: [Alim] Value changed to 1
Sep 8 13:53:46 raspberrypi shutdownd[293]: Toogle : ON
Sep 8 13:53:48 raspberrypi shutdownd[293]: Toogle : OFF
[...]
Sep 8 13:54:16 raspberrypi shutdownd[293]: [Extinct] Value changed to 1
Sep 8 13:54:16 raspberrypi shutdownd[293]: ON
Sep 8 13:54:20 raspberrypi systemd[1]: shutdownd.service: Start operation timed out. Terminating.
Sep 8 13:54:20 raspberrypi systemd[1]: shutdownd.service: Unit entered failed state.
Sep 8 13:54:20 raspberrypi systemd[1]: shutdownd.service: Failed with result 'timeout'.
有谁知道为什么 systemd 没有检测到分叉吗?
我是否必须显式调用fork()
我的代码?
在这种情况下,我必须自己编写 daemonize 函数,这并不困难,但完全无用且多余,因为 ac 函数已经存在用于此目的。
答案1
不要那样做。
完全没有。任何一个,无论是通过库函数还是滚动您自己的代码。适用于任何服务管理系统。自 20 世纪 90 年代以来,这一直是一个错误的想法。
你的守护进程是已经在服务上下文中运行,由服务管理器以这种方式调用。你的程序应该没做什么在这方面。完全停止以这种方式编写程序。
并且不要使用forking
准备协议。您的程序是多线程的,如果您尝试forking
向其中添加就绪协议,几乎肯定无法正常运行,因为正确制定协议意味着分叉后所有初始化都已完成,包括启动所有线程。几乎没有实际上forking
在野外使用准备协议。使用其他协议。
进一步阅读
- https://unix.stackexchange.com/a/200365/5132
- https://unix.stackexchange.com/a/194653/5132
- https://unix.stackexchange.com/a/211126/5132
- https://unix.stackexchange.com/a/336067/5132
- https://unix.stackexchange.com/a/283739/5132
- 乔纳森·德博因·波拉德 (2001)。 ”不要为了“将守护进程置于后台”而使用 fork()。”。 设计 Unix 守护程序时要避免的错误。经常给出的答案。
- 乔纳森·德博因·波拉德 (2015)。您确实不需要守护进程。真的。。 systemd 恐怖屋。
- 乔纳森·德博因·波拉德 (2015)。Unix 守护进程的就绪协议问题。经常给出的答案。