X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=ucw%2Fdoc%2Fdaemon.txt;h=58d550f2d4b7130f732106738565519c70050182;hb=ec6703bb4d58e504fde8ea8429f9b26ab6632696;hp=100621005f554bfc81e6d68fe47d5806cfabd6d8;hpb=c7df2496065f71bd427cdc646b3dbb8990a394f4;p=libucw.git diff --git a/ucw/doc/daemon.txt b/ucw/doc/daemon.txt index 10062100..58d550f2 100644 --- a/ucw/doc/daemon.txt +++ b/ucw/doc/daemon.txt @@ -1,5 +1,8 @@ -Daemonization helper -==================== +Daemon helpers +============== + +Daemonization +------------- When programs run as daemons, they frequently forget to detach themselves from the parent environment. LibUCW therefore offers a simple daemonization @@ -17,4 +20,74 @@ helper which performs the necessary actions. Namely: * Writing a PID file. While the daemon is running, the PID file is kept locked by `flock()`, so we can easily detect stale PID files. +Example +------- + + #include + #include + + void daemon_body(struct daemon_params *dp) + { + // ... daemon's code ... + // When we are done, release the PID file and exit: + daemon_exit(dp); + } + + int main(int argc, char **argv) + { + struct daemon_params dp = { .pid_file = "/var/run/example.pid" }; + // ... parse arguments ... + daemon_init(&dp); + // ... initialize everything ... + // Let us fork off the daemon: + daemon_run(daemon_body); + // Here continues the parent process + return 0; + } + +Daemon control +-------------- + +Daemons using the LibUCW helpers can be controlled by traditional mechanisms present +in most UNIX-like operating systems. These are usually based on PID files, but they +are inherently racy, since they do not perform any locking. For example, attempts to +start the daemon, while another process is trying to stop it often lead to undefined +states. Also, detection of running daemons fails when the daemon dies and its PID +is recycled. Checking of process name and similar tricks do not avoid the problem, +since there can be multiple instances of the daemon running simultaneously. + +We therefore recommend the following daemon control protocol, which prevents all such +race conditions. Its implementation is available in form of the @daemon_control() library +function or the `ucw-daemon-control` stand-alone utility. + +* There exist two files: +** PID file (usually `/var/run/daemon.pid`), which contains the PID of the daemon + process and when the daemon runs, it keeps the file locked by `flock()`. +** Guard file (usually `/var/run/daemon.lock`), which is locked (again by `flock()`) + whenever we want to perform an action on the daemon. +* When we want to start the daemon: +** Lock the guard file, creating it if it did not exist. +** Try to lock the PID file. If it fails, the daemon is already running, so we are done. +** Unlock the PID file. +** Run the daemon. The daemon locks the PID file and when it has everything initialized, + it forks and the parent process writes the child's PID and exits. +** Unlock the guard file. +* When we want to stop it: +** Lock the guard file, creating it if it did not exist. +** Try to lock the PID file. If it succeeds, the daemon is not running, so we are done. +** Read the PID from the PID file. +** Send a signal to the process. [This is the only place when we can race. The daemon could + have exited in the meantime and its PID could have been recycled. Hopefully, the time window + between checking the lock and sending the signal will be short enough. Using 32-bit PIDs + is advisable anyway.] +** Lock the PID file. This will wait until the daemon finishes and releases the lock. +** Unlock the guard file. +* When we want to query the daemon's status: +** Lock the guard file, creating it if it did not exist. +** Try to lock the PID file. If it succeeds, the daemon was not running. +** Unlock everything. + +ucw/daemon.h +------------ + !!ucw/daemon.h