Systemd timeout because it doesn't detect daemon forking
Do not do that.
At all. Any of it, either through a library function or rolling your own code. For any service management system. It has been a wrongheaded idea since the 1990s.
Your dæmon is already running in a service context, invoked that way by a service manager. Your program should do nothing in this respect. Stop writing your program that way at all.
And do not use the forking
readiness protocol. Your program is multithreaded and will almost certainly not function correctly if you try to add the forking
readiness protocol to it, as enacting the protocol correctly means forking after all initialization has been done, including starting up all of the threads. Almost nothing actually uses the forking
readiness protocol in the wild. Use another protocol.
Further reading
- 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
- Jonathan de Boyne Pollard (2001). "Don't fork() in order to 'put the dæmon into the background'.". Mistakes to avoid when designing Unix dæmon programs. Frequently Given Answers.
- Jonathan de Boyne Pollard (2015). You really don't need to daemonize. Really.. The systemd House of Horror.
- Jonathan de Boyne Pollard (2015). Readiness protocol problems with Unix dæmons. Frequently Given Answers.
Related videos on Youtube
Arkaik
Updated on September 18, 2022Comments
-
Arkaik over 1 year
I'm currently developping a systemd daemon. The problem I'm facing is that the daemon is killed 1m30s after beeing launched because the forking is not detected.
I'm using the
int daemon(int nochdir, int noclose)
function to daemonize the process.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); }
Here is the service file
/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
The daemon function is supposed to fork the process and detach it from the terminal, I also close file desciptors and change the working directory to /.
However systemd seems to don't detect the forking as it kill my running daemon after 1m30s.
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'.
Does anyone as a clue about why systemd doesn't detect the forking ?
Do I have to explicitly call
fork()
in my code?
In this case I'll have to code the daemonize function by myself which is not so difficult but totally useless and redundant since a c function already exists for that purpose. -
Johan Myréen over 6 years
Type=forking
is used to tell systemd that the daemon is an old school forking daemon.Type=forking
should be used ifdaemon()
is called; it should not be used if the service executable does not fork. But I fully agree with JdeBP that you should leave it to systemd to daemonize the process, and useType=forking
only for legacy daemons. Returning to your original problem: I think systemd is detecting that the program forked and the parent exited, but I suspect systemd is still waiting for the PIDFile to appear. Systemd does not write this file, the daemon should write it.