X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=a65d62bfa9086dab4b4546483323731a5b6c0e0b;hb=59cec096169139f64a420a14049fb07e08dd0749;hp=6d6140b1f891f10c75f4cff539c0f6776b7272aa;hpb=4d0762229f4950d4ad21f6f47870d3b767dd61fa;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 6d6140b1f..a65d62bfa 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include "lttng-sessiond.h" #include "buffer-registry.h" @@ -72,12 +74,15 @@ static const char *tracing_group_name = DEFAULT_TRACING_GROUP; static const char *opt_pidfile; static int opt_sig_parent; static int opt_verbose_consumer; -static int opt_daemon; +static int opt_daemon, opt_background; static int opt_no_kernel; -static int is_root; /* Set to 1 if the daemon is running as root */ static pid_t ppid; /* Parent PID for --sig-parent option */ +static pid_t child_ppid; /* Internal parent PID use with daemonize. */ static char *rundir; +/* Set to 1 when a SIGUSR1 signal is received. */ +static int recv_child_signal; + /* * Consumer daemon specific control data. Every value not initialized here is * set to 0 by the static definition. @@ -238,6 +243,41 @@ struct health_app *health_sessiond; /* JUL TCP port for registration. Used by the JUL thread. */ unsigned int jul_tcp_port = DEFAULT_JUL_TCP_PORT; +/* Am I root or not. */ +int is_root; /* Set to 1 if the daemon is running as root */ + +/* + * 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 || opt_background) { + kill(child_ppid, SIGUSR1); + } + } +} + static void setup_consumerd_path(void) { @@ -455,6 +495,11 @@ static void cleanup(void) DBG("Removing %s", path); (void) unlink(path); + snprintf(path, PATH_MAX, "%s/%s", rundir, + DEFAULT_LTTNG_SESSIOND_JULPORT_FILE); + DBG("Removing %s", path); + (void) unlink(path); + /* kconsumerd */ snprintf(path, PATH_MAX, DEFAULT_KCONSUMERD_ERR_SOCK_PATH, @@ -494,6 +539,12 @@ static void cleanup(void) DBG("Removing directory %s", path); (void) rmdir(path); + /* + * We do NOT rmdir rundir because there are other processes + * using it, for instance lttng-relayd, which can start in + * parallel with this teardown. + */ + free(rundir); DBG("Cleaning up all sessions"); @@ -785,13 +836,13 @@ static void *thread_manage_kernel(void *data) */ 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; } @@ -860,9 +911,8 @@ static void *thread_manage_kernel(void *data) /* Check for data on kernel pipe */ if (pollfd == kernel_poll_pipe[0] && (revents & LPOLLIN)) { - do { - ret = read(kernel_poll_pipe[0], &tmp, 1); - } while (ret < 0 && errno == EINTR); + (void) lttng_read(kernel_poll_pipe[0], + &tmp, 1); /* * Ret value is useless here, if this pipe gets any actions an * update is required anyway. @@ -972,7 +1022,7 @@ static void *thread_manage_consumer(void *data) restart: health_poll_entry(); - if (testpoint(thread_manage_consumer)) { + if (testpoint(sessiond_thread_manage_consumer)) { goto error; } @@ -1036,7 +1086,6 @@ restart: } health_code_update(); - if (code == LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) { /* Connect both socket, command and metadata. */ consumer_data->cmd_sock = @@ -1193,13 +1242,13 @@ error: } consumer_data->cmd_sock = -1; } - if (*consumer_data->metadata_sock.fd_ptr >= 0) { + if (consumer_data->metadata_sock.fd_ptr && + *consumer_data->metadata_sock.fd_ptr >= 0) { ret = close(*consumer_data->metadata_sock.fd_ptr); if (ret) { PERROR("close"); } } - if (sock >= 0) { ret = close(sock); if (ret) { @@ -1213,9 +1262,10 @@ error: pthread_mutex_unlock(&consumer_data->lock); /* Cleanup metadata socket mutex. */ - pthread_mutex_destroy(consumer_data->metadata_sock.lock); - free(consumer_data->metadata_sock.lock); - + if (consumer_data->metadata_sock.lock) { + pthread_mutex_destroy(consumer_data->metadata_sock.lock); + free(consumer_data->metadata_sock.lock); + } lttng_poll_clean(&events); error_poll: if (err) { @@ -1234,6 +1284,7 @@ error_poll: static void *thread_manage_apps(void *data) { int i, ret, pollfd, err = -1; + ssize_t size_ret; uint32_t revents, nb_fd; struct lttng_poll_event events; @@ -1244,7 +1295,7 @@ static void *thread_manage_apps(void *data) health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_MANAGE); - if (testpoint(thread_manage_apps)) { + if (testpoint(sessiond_thread_manage_apps)) { goto error_testpoint; } @@ -1260,7 +1311,7 @@ static void *thread_manage_apps(void *data) goto error; } - if (testpoint(thread_manage_apps_before_loop)) { + if (testpoint(sessiond_thread_manage_apps_before_loop)) { goto error; } @@ -1309,10 +1360,8 @@ static void *thread_manage_apps(void *data) int sock; /* Empty pipe */ - do { - ret = read(apps_cmd_pipe[0], &sock, sizeof(sock)); - } while (ret < 0 && errno == EINTR); - if (ret < 0 || ret < sizeof(sock)) { + size_ret = lttng_read(apps_cmd_pipe[0], &sock, sizeof(sock)); + if (size_ret < sizeof(sock)) { PERROR("read apps cmd pipe"); goto error; } @@ -1331,10 +1380,6 @@ static void *thread_manage_apps(void *data) } DBG("Apps with sock %d added to poll set", sock); - - health_code_update(); - - break; } } else { /* @@ -1350,7 +1395,6 @@ static void *thread_manage_apps(void *data) /* Socket closed on remote end. */ ust_app_unregister(pollfd); - break; } } @@ -1395,7 +1439,7 @@ error_testpoint: */ static int send_socket_to_thread(int fd, int sock) { - int ret; + ssize_t ret; /* * It's possible that the FD is set as invalid with -1 concurrently just @@ -1406,10 +1450,8 @@ static int send_socket_to_thread(int fd, int sock) goto error; } - do { - ret = write(fd, &sock, sizeof(sock)); - } while (ret < 0 && errno == EINTR); - if (ret < 0 || ret != sizeof(sock)) { + ret = lttng_write(fd, &sock, sizeof(sock)); + if (ret < sizeof(sock)) { PERROR("write apps pipe %d", fd); if (ret < 0) { ret = -errno; @@ -1420,7 +1462,7 @@ static int send_socket_to_thread(int fd, int sock) /* All good. Don't send back the write positive ret value. */ ret = 0; error: - return ret; + return (int) ret; } /* @@ -1524,6 +1566,10 @@ static void *thread_dispatch_ust_registration(void *data) health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH); + if (testpoint(sessiond_thread_app_reg_dispatch)) { + goto error_testpoint; + } + health_code_update(); CDS_INIT_LIST_HEAD(&wait_queue.head); @@ -1573,7 +1619,7 @@ static void *thread_dispatch_ust_registration(void *data) if (ret < 0) { PERROR("close ust sock dispatch %d", ust_cmd->sock); } - lttng_fd_put(1, LTTNG_FD_APPS); + lttng_fd_put(LTTNG_FD_APPS, 1); free(ust_cmd); goto error; } @@ -1587,7 +1633,7 @@ static void *thread_dispatch_ust_registration(void *data) if (ret < 0) { PERROR("close ust sock dispatch %d", ust_cmd->sock); } - lttng_fd_put(1, LTTNG_FD_APPS); + lttng_fd_put(LTTNG_FD_APPS, 1); free(wait_node); free(ust_cmd); continue; @@ -1635,7 +1681,7 @@ static void *thread_dispatch_ust_registration(void *data) if (ret < 0) { PERROR("close ust sock dispatch %d", ust_cmd->sock); } - lttng_fd_put(1, LTTNG_FD_APPS); + lttng_fd_put(LTTNG_FD_APPS, 1); } free(ust_cmd); } @@ -1728,6 +1774,7 @@ error: free(wait_node); } +error_testpoint: DBG("Dispatch thread dying"); if (err) { health_error(); @@ -1755,7 +1802,7 @@ static void *thread_registration_apps(void *data) health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG); - if (testpoint(thread_registration_apps)) { + if (testpoint(sessiond_thread_registration_apps)) { goto error_testpoint; } @@ -1916,11 +1963,6 @@ static void *thread_registration_apps(void *data) exit: error: - if (err) { - health_error(); - ERR("Health error occurred in %s", __func__); - } - /* Notify that the registration thread is gone */ notify_ust_apps(0); @@ -1945,6 +1987,10 @@ error_listen: error_create_poll: error_testpoint: DBG("UST Registration thread cleanup complete"); + if (err) { + health_error(); + ERR("Health error occurred in %s", __func__); + } health_unregister(health_sessiond); return NULL; @@ -2041,19 +2087,23 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) if (ret != 0) { errno = ret; if (ret == ETIMEDOUT) { + int pth_ret; + /* * Call has timed out so we kill the kconsumerd_thread and return * an error. */ ERR("Condition timed out. The consumer thread was never ready." " Killing it"); - ret = pthread_cancel(consumer_data->thread); - if (ret < 0) { + pth_ret = pthread_cancel(consumer_data->thread); + if (pth_ret < 0) { PERROR("pthread_cancel consumer thread"); } } else { PERROR("pthread_cond_wait failed consumer thread"); } + /* Caller is expecting a negative value on failure. */ + ret = -1; goto error; } @@ -2139,10 +2189,11 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) consumer_to_use = consumerd32_bin; } else { DBG("Could not find any valid consumerd executable"); + ret = -EINVAL; break; } DBG("Using kernel consumer at: %s", consumer_to_use); - execl(consumer_to_use, + ret = execl(consumer_to_use, "lttng-consumerd", verbosity, "-k", "--consumerd-cmd-sock", consumer_data->cmd_unix_sock_path, "--consumerd-err-sock", consumer_data->err_unix_sock_path, @@ -2190,9 +2241,6 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) if (consumerd64_libdir[0] != '\0') { free(tmpnew); } - if (ret) { - goto error; - } break; } case LTTNG_CONSUMER32_UST: @@ -2236,9 +2284,6 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) if (consumerd32_libdir[0] != '\0') { free(tmpnew); } - if (ret) { - goto error; - } break; } default: @@ -2246,8 +2291,9 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) exit(EXIT_FAILURE); } if (errno != 0) { - PERROR("kernel start consumer exec"); + PERROR("Consumer execl()"); } + /* Reaching this point, we got a failure on our execl(). */ exit(EXIT_FAILURE); } else if (pid > 0) { ret = pid; @@ -2415,6 +2461,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session) consumer = session->kernel_session->consumer; dir_name = DEFAULT_KERNEL_TRACE_DIR; break; + case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_UST: DBG3("Copying tracing session consumer output in UST session"); if (session->ust_session->consumer) { @@ -2458,6 +2505,7 @@ static int create_ust_session(struct ltt_session *session, assert(session->consumer); switch (domain->type) { + case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_UST: break; default: @@ -2750,10 +2798,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, break; case LTTNG_DOMAIN_JUL: - { - ret = LTTNG_ERR_UNKNOWN_DOMAIN; - goto error; - } case LTTNG_DOMAIN_UST: { if (!ust_app_supported()) { @@ -2927,9 +2971,74 @@ skip_domain: } case LTTNG_ENABLE_EVENT: { + struct lttng_event_exclusion *exclusion = NULL; + struct lttng_filter_bytecode *bytecode = NULL; + + /* Handle exclusion events and receive it from the client. */ + if (cmd_ctx->lsm->u.enable.exclusion_count > 0) { + size_t count = cmd_ctx->lsm->u.enable.exclusion_count; + + exclusion = zmalloc(sizeof(struct lttng_event_exclusion) + + (count * LTTNG_SYMBOL_NAME_LEN)); + if (!exclusion) { + ret = LTTNG_ERR_EXCLUSION_NOMEM; + goto error; + } + + DBG("Receiving var len exclusion event list from client ..."); + exclusion->count = count; + ret = lttcomm_recv_unix_sock(sock, exclusion->names, + count * LTTNG_SYMBOL_NAME_LEN); + if (ret <= 0) { + DBG("Nothing recv() from client var len data... continuing"); + *sock_error = 1; + free(exclusion); + ret = LTTNG_ERR_EXCLUSION_INVAL; + goto error; + } + } + + /* Handle filter and get bytecode from client. */ + if (cmd_ctx->lsm->u.enable.bytecode_len > 0) { + size_t bytecode_len = cmd_ctx->lsm->u.enable.bytecode_len; + + if (bytecode_len > LTTNG_FILTER_MAX_LEN) { + ret = LTTNG_ERR_FILTER_INVAL; + free(exclusion); + goto error; + } + + bytecode = zmalloc(bytecode_len); + if (!bytecode) { + free(exclusion); + ret = LTTNG_ERR_FILTER_NOMEM; + goto error; + } + + /* Receive var. len. data */ + DBG("Receiving var len filter's bytecode from client ..."); + ret = lttcomm_recv_unix_sock(sock, bytecode, bytecode_len); + if (ret <= 0) { + DBG("Nothing recv() from client car len data... continuing"); + *sock_error = 1; + free(bytecode); + free(exclusion); + ret = LTTNG_ERR_FILTER_INVAL; + goto error; + } + + if ((bytecode->len + sizeof(*bytecode)) != bytecode_len) { + free(bytecode); + free(exclusion); + ret = LTTNG_ERR_FILTER_INVAL; + goto error; + } + } + ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, NULL, kernel_poll_pipe[1]); + &cmd_ctx->lsm->u.enable.event, bytecode, exclusion, + kernel_poll_pipe[1]); break; } case LTTNG_ENABLE_ALL_EVENT: @@ -3253,46 +3362,6 @@ skip_domain: cmd_ctx->lsm->u.reg.path, cdata); break; } - case LTTNG_ENABLE_EVENT_WITH_FILTER: - { - struct lttng_filter_bytecode *bytecode; - - if (cmd_ctx->lsm->u.enable.bytecode_len > LTTNG_FILTER_MAX_LEN) { - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - if (cmd_ctx->lsm->u.enable.bytecode_len == 0) { - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - bytecode = zmalloc(cmd_ctx->lsm->u.enable.bytecode_len); - if (!bytecode) { - ret = LTTNG_ERR_FILTER_NOMEM; - goto error; - } - /* Receive var. len. data */ - DBG("Receiving var len data from client ..."); - ret = lttcomm_recv_unix_sock(sock, bytecode, - cmd_ctx->lsm->u.enable.bytecode_len); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - if (bytecode->len + sizeof(*bytecode) - != cmd_ctx->lsm->u.enable.bytecode_len) { - free(bytecode); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, - cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, bytecode, kernel_poll_pipe[1]); - break; - } case LTTNG_DATA_PENDING: { ret = cmd_data_pending(cmd_ctx->session); @@ -3535,6 +3604,8 @@ static void *thread_manage_health(void *data) goto error; } + lttng_sessiond_notify_ready(); + while (1) { DBG("Health check ready"); @@ -3599,7 +3670,7 @@ restart: rcu_thread_online(); - reply.ret_code = 0; + memset(&reply, 0, sizeof(reply)); for (i = 0; i < NR_HEALTH_SESSIOND_TYPES; i++) { /* * health_check_state returns 0 if health is @@ -3663,10 +3734,6 @@ static void *thread_manage_clients(void *data) 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); @@ -3689,14 +3756,14 @@ static void *thread_manage_clients(void *data) goto error; } - /* - * Notify parent pid that we are ready to accept command for client side. - */ - if (opt_sig_parent) { - kill(ppid, SIGUSR1); + lttng_sessiond_notify_ready(); + + /* 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; } @@ -3871,7 +3938,6 @@ error: error_listen: error_create_poll: -error_testpoint: unlink(client_unix_sock_path); if (client_sock >= 0) { ret = close(client_sock); @@ -3914,9 +3980,10 @@ static void usage(void) fprintf(stderr, " --consumerd64-path PATH Specify path for the 64-bit UST consumer daemon binary\n"); fprintf(stderr, " --consumerd64-libdir PATH Specify path for the 64-bit UST consumer daemon libraries\n"); fprintf(stderr, " -d, --daemonize Start as a daemon.\n"); + fprintf(stderr, " -b, --background Start as a daemon, keeping console open.\n"); fprintf(stderr, " -g, --group NAME Specify the tracing group name. (default: tracing)\n"); fprintf(stderr, " -V, --version Show version number.\n"); - fprintf(stderr, " -S, --sig-parent Send SIGCHLD to parent pid to notify readiness.\n"); + fprintf(stderr, " -S, --sig-parent Send SIGUSR1 to parent pid to notify readiness.\n"); fprintf(stderr, " -q, --quiet No output at all.\n"); fprintf(stderr, " -v, --verbose Verbose mode. Activate DBG() macro.\n"); fprintf(stderr, " -p, --pidfile FILE Write a pid to FILE name overriding the default value.\n"); @@ -3956,12 +4023,13 @@ static int parse_args(int argc, char **argv) { "no-kernel", 0, 0, 'N' }, { "pidfile", 1, 0, 'p' }, { "jul-tcp-port", 1, 0, 'J' }, + { "background", 0, 0, 'b' }, { NULL, 0, 0, 0 } }; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:J:", + c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:J:b", long_options, &option_index); if (c == -1) { break; @@ -3983,6 +4051,9 @@ static int parse_args(int argc, char **argv) case 'd': opt_daemon = 1; break; + case 'b': + opt_background = 1; + break; case 'g': tracing_group_name = optarg; break; @@ -4337,6 +4408,9 @@ static void sighandler(int sig) DBG("SIGTERM caught"); stop_threads(); break; + case SIGUSR1: + CMM_STORE_SHARED(recv_child_signal, 1); + break; default: break; } @@ -4375,7 +4449,12 @@ static int set_signal_handler(void) return ret; } - DBG("Signal handler set for SIGTERM, SIGPIPE and SIGINT"); + if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { + PERROR("sigaction"); + return ret; + } + + DBG("Signal handler set for SIGTERM, SIGUSR1, SIGPIPE and SIGINT"); return ret; } @@ -4431,6 +4510,34 @@ error: return; } +/* + * Write JUL TCP port using the rundir. + */ +static void write_julport(void) +{ + int ret; + char path[PATH_MAX]; + + assert(rundir); + + ret = snprintf(path, sizeof(path), "%s/" + DEFAULT_LTTNG_SESSIOND_JULPORT_FILE, rundir); + if (ret < 0) { + PERROR("snprintf julport path"); + goto error; + } + + /* + * Create TCP JUL port file in rundir. Return value is of no importance. + * The execution will continue even though we are not able to write the + * file. + */ + (void) utils_create_pid_file(jul_tcp_port, path); + +error: + return; +} + /* * main */ @@ -4444,6 +4551,10 @@ int main(int argc, char **argv) rcu_register_thread(); + if ((ret = set_signal_handler()) < 0) { + goto error; + } + setup_consumerd_path(); page_size = sysconf(_SC_PAGESIZE); @@ -4460,23 +4571,19 @@ int main(int argc, char **argv) } /* Daemonize */ - if (opt_daemon) { + if (opt_daemon || opt_background) { int i; - /* - * fork - * child: setsid, close FD 0, 1, 2, chdir / - * parent: exit (if fork is successful) - */ - ret = daemon(0, 0); + ret = lttng_daemonize(&child_ppid, &recv_child_signal, + !opt_background); if (ret < 0) { - PERROR("daemon"); goto error; } + /* - * We are in the child. Make sure all other file - * descriptors are closed, in case we are called with - * more opened file descriptors than the standard ones. + * We are in the child. Make sure all other file descriptors are + * closed, in case we are called with more opened file descriptors than + * the standard ones. */ for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { (void) close(i); @@ -4628,6 +4735,12 @@ int main(int argc, char **argv) */ ust_app_ht_alloc(); + /* Initialize JUL domain subsystem. */ + if ((ret = jul_init()) < 0) { + /* ENOMEM at this point. */ + goto error; + } + /* After this point, we can safely call cleanup() with "goto exit" */ /* @@ -4663,10 +4776,6 @@ int main(int argc, char **argv) goto exit; } - if ((ret = set_signal_handler()) < 0) { - goto exit; - } - /* Setup the needed unix socket */ if ((ret = init_daemon_socket()) < 0) { goto exit; @@ -4731,6 +4840,7 @@ int main(int argc, char **argv) } write_pidfile(); + write_julport(); /* Initialize communication library */ lttcomm_init(); @@ -4747,7 +4857,7 @@ int main(int argc, char **argv) goto exit_health_sessiond_cleanup; } - /* Create thread to manage the client socket */ + /* Create thread to clean up RCU hash tables */ ret = pthread_create(&ht_cleanup_thread, NULL, thread_ht_cleanup, (void *) NULL); if (ret != 0) { @@ -4755,7 +4865,7 @@ int main(int argc, char **argv) goto exit_ht_cleanup; } - /* Create thread to manage the client socket */ + /* Create health-check thread */ ret = pthread_create(&health_thread, NULL, thread_manage_health, (void *) NULL); if (ret != 0) {