daemon: Introduce parent_waits flag for daemonize().
authorAndre Noll <maan@systemlinux.org>
Sat, 12 Nov 2011 13:37:01 +0000 (14:37 +0100)
committerAndre Noll <maan@systemlinux.org>
Sun, 13 Nov 2011 13:32:21 +0000 (14:32 +0100)
In daemon mode, para_server should not detach from the console
until it is listening on its command socket. The previous approach
turned out to be buggy and has been reverted in the previous commit.

This second attempt tries to get it right. It adds a boolean parameter
"parent_waits" to daemonize(). After daemonize() has forked, the
parent process does not exit immediately if parent_waits is true but
waits until the child process sends SIGTERM to its parent, or exits.

para_server makes use of the new flag in server_init(). The daemon
process (child) sends SIGTERM to its parent after the command socket
has been initialized. para_audiod, on the other hand, does not need
this feature, so it calls daemonize() with parent_waits == false to
get the old behaviour.

audiod.c
daemon.c
daemon.h
server.c

index 4864c85..8008e2c 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1381,7 +1381,7 @@ int main(int argc, char *argv[])
        init_command_task(cmd_task);
 
        if (conf.daemon_given)
-               daemonize();
+               daemonize(false /* parent exits immediately */);
 
        register_task(&sig_task->task);
        register_task(&cmd_task->task);
index ffdec4e..541e44d 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -142,14 +142,25 @@ static bool daemon_test_flag(unsigned flag)
        return me->flags & flag;
 }
 
+static void dummy_sighandler(__a_unused int s)
+{
+}
+
 /**
  * Do the usual stuff to become a daemon.
  *
- * Fork, become session leader, dup fd 0, 1, 2 to /dev/null.
+ * \param parent_waits Whether the parent process should pause before exit.
  *
- * \sa fork(2), setsid(2), dup(2).
+ * Fork, become session leader, cd to /, and dup fd 0, 1, 2 to /dev/null. If \a
+ * parent_waits is false, the parent process terminates immediately.
+ * Otherwise, it calls pause() to sleep until it receives \p SIGTERM or \p
+ * SIGCHLD and exits successfully thereafter. This behaviour is useful if the
+ * daemon process should not detach from the console until the child process
+ * has completed its setup.
+ *
+ * \sa fork(2), setsid(2), dup(2), pause(2).
  */
-void daemonize(void)
+void daemonize(bool parent_waits)
 {
        pid_t pid;
        int null;
@@ -158,8 +169,14 @@ void daemonize(void)
        pid = fork();
        if (pid < 0)
                goto err;
-       if (pid)
+       if (pid) {
+               if (parent_waits) {
+                       signal(SIGTERM, dummy_sighandler);
+                       signal(SIGCHLD, dummy_sighandler);
+                       pause();
+               }
                exit(EXIT_SUCCESS); /* parent exits */
+       }
        /* become session leader */
        if (setsid() < 0)
                goto err;
index d5583f5..3fe72ea 100644 (file)
--- a/daemon.h
+++ b/daemon.h
@@ -1,7 +1,7 @@
 /** \file daemon.h exported symbols from daemon.c */
 
 
-void daemonize(void);
+void daemonize(bool parent_waits);
 void daemon_open_log_or_die(void);
 void daemon_close_log(void);
 void log_welcome(const char *whoami);
index 82f48e0..7f020c8 100644 (file)
--- a/server.c
+++ b/server.c
@@ -493,7 +493,7 @@ static void server_init(int argc, char **argv)
        init_user_list(user_list_file);
        /* become daemon */
        if (conf.daemon_given)
-               daemonize();
+               daemonize(true /* parent waits for SIGTERM */);
        PARA_NOTICE_LOG("initializing audio format handlers\n");
        afh_init();
 
@@ -519,6 +519,8 @@ static void server_init(int argc, char **argv)
        PARA_NOTICE_LOG("initializing virtual streaming system\n");
        init_vss_task(afs_socket);
        init_server_command_task(argc, argv);
+       if (conf.daemon_given)
+               kill(getppid(), SIGTERM);
        PARA_NOTICE_LOG("server init complete\n");
 }