#include <common/futex.h>
#include <common/relayd/relayd.h>
#include <common/utils.h>
+#include <common/daemonize.h>
#include <common/config/config.h>
#include "lttng-sessiond.h"
const char * const config_section_name = "sessiond";
+/*
+ * Whether sessiond is ready for commands/health check requests.
+ * NR_LTTNG_SESSIOND_READY must match the number of calls to
+ * lttng_sessiond_notify_ready().
+ */
+#define NR_LTTNG_SESSIOND_READY 2
+int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY;
+
+/* Notify parents that we are ready for cmd and health check */
+static
+void lttng_sessiond_notify_ready(void)
+{
+ if (uatomic_sub_return(<tng_sessiond_ready, 1) == 0) {
+ /*
+ * Notify parent pid that we are ready to accept command
+ * for client side. This ppid is the one from the
+ * external process that spawned us.
+ */
+ if (opt_sig_parent) {
+ kill(ppid, SIGUSR1);
+ }
+
+ /*
+ * Notify the parent of the fork() process that we are
+ * ready.
+ */
+ if (opt_daemon) {
+ kill(child_ppid, SIGUSR1);
+ }
+ }
+}
+
static
void setup_consumerd_path(void)
{
*/
lttng_poll_init(&events);
- if (testpoint(thread_manage_kernel)) {
+ if (testpoint(sessiond_thread_manage_kernel)) {
goto error_testpoint;
}
health_code_update();
- if (testpoint(thread_manage_kernel_before_loop)) {
+ if (testpoint(sessiond_thread_manage_kernel_before_loop)) {
goto error_testpoint;
}
restart:
health_poll_entry();
- if (testpoint(thread_manage_consumer)) {
+ if (testpoint(sessiond_thread_manage_consumer)) {
goto error;
}
health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_MANAGE);
- if (testpoint(thread_manage_apps)) {
+ if (testpoint(sessiond_thread_manage_apps)) {
goto error_testpoint;
}
goto error;
}
- if (testpoint(thread_manage_apps_before_loop)) {
+ if (testpoint(sessiond_thread_manage_apps_before_loop)) {
goto error;
}
health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG);
- if (testpoint(thread_registration_apps)) {
+ if (testpoint(sessiond_thread_registration_apps)) {
goto error_testpoint;
}
goto error;
}
+ lttng_sessiond_notify_ready();
+
while (1) {
DBG("Health check ready");
health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CMD);
- if (testpoint(thread_manage_clients)) {
- goto error_testpoint;
- }
-
health_code_update();
ret = lttcomm_listen_unix_sock(client_sock);
goto error;
}
- /*
- * Notify parent pid that we are ready to accept command for client side.
- * This ppid is the one from the external process that spawned us.
- */
- if (opt_sig_parent) {
- kill(ppid, SIGUSR1);
- }
+ lttng_sessiond_notify_ready();
- /* Notify the parent of the fork() process that we are ready. */
- if (opt_daemon) {
- kill(child_ppid, SIGUSR1);
+ /* This testpoint is after we signal readiness to the parent. */
+ if (testpoint(sessiond_thread_manage_clients)) {
+ goto error;
}
- if (testpoint(thread_manage_clients_before_loop)) {
+ if (testpoint(sessiond_thread_manage_clients_before_loop)) {
goto error;
}
error_listen:
error_create_poll:
-error_testpoint:
unlink(client_unix_sock_path);
if (client_sock >= 0) {
ret = close(client_sock);
return;
}
-/*
- * Daemonize this process by forking and making the parent wait for the child
- * to signal it indicating readiness. Once received, the parent successfully
- * quits.
- *
- * The child process undergoes the same action that daemon(3) does meaning
- * setsid, chdir, and dup /dev/null into 0, 1 and 2.
- *
- * Return 0 on success else -1 on error.
- */
-static int daemonize(void)
-{
- int ret;
- pid_t pid;
-
- /* Get parent pid of this process. */
- child_ppid = getppid();
-
- pid = fork();
- if (pid < 0) {
- PERROR("fork");
- goto error;
- } else if (pid == 0) {
- int fd;
- pid_t sid;
-
- /* Child */
-
- /*
- * Get the newly created parent pid so we can signal that process when
- * we are ready to operate.
- */
- child_ppid = getppid();
-
- sid = setsid();
- if (sid < 0) {
- PERROR("setsid");
- goto error;
- }
-
- /* Try to change directory to /. If we can't well at least notify. */
- ret = chdir("/");
- if (ret < 0) {
- PERROR("chdir");
- }
-
- fd = open(_PATH_DEVNULL, O_RDWR, 0);
- if (fd < 0) {
- PERROR("open %s", _PATH_DEVNULL);
- /* Let 0, 1 and 2 open since we can't bind them to /dev/null. */
- } else {
- (void) dup2(fd, STDIN_FILENO);
- (void) dup2(fd, STDOUT_FILENO);
- (void) dup2(fd, STDERR_FILENO);
- if (fd > 2) {
- ret = close(fd);
- if (ret < 0) {
- PERROR("close");
- }
- }
- }
- goto end;
- } else {
- /* Parent */
-
- /*
- * Waiting for child to notify this parent that it can exit. Note that
- * sleep() is interrupted before the 1 second delay as soon as the
- * signal is received, so it will not cause visible delay for the
- * user.
- */
- while (!CMM_LOAD_SHARED(recv_child_signal)) {
- int status;
- pid_t ret;
-
- /*
- * Check if child exists without blocking. If so, we have to stop
- * this parent process and return an error.
- */
- ret = waitpid(pid, &status, WNOHANG);
- if (ret < 0 || (ret != 0 && WIFEXITED(status))) {
- /* The child exited somehow or was not valid. */
- goto error;
- }
- sleep(1);
- }
-
- /*
- * From this point on, the parent can exit and the child is now an
- * operationnal session daemon ready to serve clients and applications.
- */
- exit(EXIT_SUCCESS);
- }
-
-end:
- return 0;
-
-error:
- return -1;
-}
-
/*
* main
*/
if (opt_daemon) {
int i;
- ret = daemonize();
+ ret = lttng_daemonize(&child_ppid, &recv_child_signal, 1);
if (ret < 0) {
goto error;
}