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.
init_command_task(cmd_task);
if (conf.daemon_given)
init_command_task(cmd_task);
if (conf.daemon_given)
+ daemonize(false /* parent exits immediately */);
register_task(&sig_task->task);
register_task(&cmd_task->task);
register_task(&sig_task->task);
register_task(&cmd_task->task);
return me->flags & flag;
}
return me->flags & flag;
}
+static void dummy_sighandler(__a_unused int s)
+{
+}
+
/**
* Do the usual stuff to become a daemon.
*
/**
* 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(bool parent_waits)
pid = fork();
if (pid < 0)
goto err;
pid = fork();
if (pid < 0)
goto err;
+ if (pid) {
+ if (parent_waits) {
+ signal(SIGTERM, dummy_sighandler);
+ signal(SIGCHLD, dummy_sighandler);
+ pause();
+ }
exit(EXIT_SUCCESS); /* parent exits */
exit(EXIT_SUCCESS); /* parent exits */
/* become session leader */
if (setsid() < 0)
goto err;
/* become session leader */
if (setsid() < 0)
goto err;
/** \file daemon.h exported symbols from daemon.c */
/** \file daemon.h exported symbols from daemon.c */
+void daemonize(bool parent_waits);
void daemon_open_log_or_die(void);
void daemon_close_log(void);
void log_welcome(const char *whoami);
void daemon_open_log_or_die(void);
void daemon_close_log(void);
void log_welcome(const char *whoami);
init_user_list(user_list_file);
/* become daemon */
if (conf.daemon_given)
init_user_list(user_list_file);
/* become daemon */
if (conf.daemon_given)
+ daemonize(true /* parent waits for SIGTERM */);
PARA_NOTICE_LOG("initializing audio format handlers\n");
afh_init();
PARA_NOTICE_LOG("initializing audio format handlers\n");
afh_init();
PARA_NOTICE_LOG("initializing virtual streaming system\n");
init_vss_task(afs_socket);
init_server_command_task(argc, 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");
}
PARA_NOTICE_LOG("server init complete\n");
}