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 4864c8550d35d66d813c9a553685f8cc761acd88..8008e2cb6459f84d3b258bd9efeb0fffc77e4016 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 ffdec4e35f3e8cdbd113a780f6d6ade7faf9fcfe..541e44defedc3d17d609dc13b09cf18a94c493e0 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 d5583f580e8ec3f2af9456b564e47c13521a4af4..3fe72ea9149a56af3a9b8fdfe9c9f5b493962f94 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 82f48e00eb8911503688fd2c9faf9a02b8909e5f..7f020c8f73f34674a0ff644aa84e73a9096962b1 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");
 }