Page MenuHomePhabricator

More correctly daemonize under unix
Needs RevisionPublic

Authored by eadler on Apr 28 2016, 5:50 AM.

Details

Reviewers
epriestley
Group Reviewers
Blessed Reviewers
Summary

Missing the setsid step causes child processes to set a SIGHUP when the session is exited.

Daemonization is weird and complicated under unix. To correctly daemonize the following steps should be taken in order

  1. explicitly set umask since the inherited umask is unknown
  2. call fork() and exit in the parent. This forces the child to have a process group ID which is not the same as the process id (thus ensuring we're not the process group leader).
  3. calls setsid() (this is now safe since we're not the process group leader). This forces us to become the PGL of a new session, and ensures we have no controlling terminal.
  4. At this point in highly portable programs it is typical to fork() yet again to prevent the child from being a session leader. This is known as the 'double fork daemonize' method.
  5. change the cwd to / to ensure that if the working directory is removed from underneath it the daemons continue to work. This also allows for the filesystem to unmounted.
  6. close open file descriptors (and possibly reopen 0,1,2).

In C without error checking this looks like

umask(0);
int pid = fork();
if (pid != 0)
	exit(0);
setsid();
int pid = fork();
if (pid != 0)
	exit(0);
chdir("/");
closefrom(0);
open("/dev/null", O_RDWR);
dup(0);
dup(0);
Test Plan

ran the daemons

note well: I wrote this all after 1:00am so something is probably wrong.

also note: I suspect the 'TODO' to learn how to unix works is hard

Diff Detail

Repository
rPHU libphutil
Branch
eax/betterdaemon (branched from master)
Lint
Lint Passed
Unit
Tests Skipped
Build Status
Buildable 11965
Build 15046: Run Core Tests
Build 15045: arc lint + arc unit

Event Timeline

eadler retitled this revision from to More correctly daemonize under unix.
eadler updated this object.
eadler edited the test plan for this revision. (Show Details)
eadler added a reviewer: epriestley.
eadler edited edge metadata.
src/daemon/PhutilDaemonOverseer.php
136

I suspect this TODO is hard.

How can I reproduce the actual problem this causes? Something like this?

  • Add a horrible fatal to didReceiveReloadSignal().
  • Launch daemons.
  • Close terminal.
  • Observe daemons die, since they unnecessarily received and processed a SIGHUP which they should not have received?

We also fork in PhabricatorAphlictManagementWorkflow in a similar way and probably want to use similar logic there, although that process doesn't do anything special with SIGHUP.

epriestley edited edge metadata.

(See comment above.)

This revision now requires changes to proceed.Jun 5 2016, 10:16 PM