X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=339b20d3ee433be2d17f33d3462b104ab6266448;hp=fc52d759b2130b8f1bdd2e122f24c1990f9b85d2;hb=e7fe706f887aa4d753b102a610f802f7dd816655;hpb=35df275583d85652cb5132adb9416e32175524e7 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index fc52d759b..339b20d3e 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -59,7 +59,6 @@ #include "ust-consumer.h" #include "utils.h" #include "fd-limit.h" -#include "filter.h" #include "health.h" #include "testpoint.h" @@ -73,6 +72,7 @@ const char default_global_apps_pipe[] = DEFAULT_GLOBAL_APPS_PIPE; const char *progname; const char *opt_tracing_group; +static const char *opt_pidfile; static int opt_sig_parent; static int opt_verbose_consumer; static int opt_daemon; @@ -397,7 +397,7 @@ static void stop_threads(void) static void cleanup(void) { int ret; - char *cmd; + char *cmd = NULL; struct ltt_session *sess, *stmp; DBG("Cleaning up"); @@ -405,6 +405,17 @@ static void cleanup(void) /* First thing first, stop all threads */ utils_close_pipe(thread_quit_pipe); + /* + * If opt_pidfile is undefined, the default file will be wiped when + * removing the rundir. + */ + if (opt_pidfile) { + ret = remove(opt_pidfile); + if (ret < 0) { + PERROR("remove pidfile %s", opt_pidfile); + } + } + DBG("Removing %s directory", rundir); ret = asprintf(&cmd, "rm -rf %s", rundir); if (ret < 0) { @@ -447,9 +458,6 @@ static void cleanup(void) modprobe_remove_lttng_all(); } - utils_close_pipe(kernel_poll_pipe); - utils_close_pipe(apps_cmd_pipe); - /* */ DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" "Matthew, BEET driven development works!%c[%dm", @@ -465,7 +473,7 @@ static void cleanup(void) static int send_unix_sock(int sock, void *buf, size_t len) { /* Check valid length */ - if (len <= 0) { + if (len == 0) { return -1; } @@ -630,20 +638,22 @@ static int update_kernel_stream(struct consumer_data *consumer_data, int fd) struct lttng_ht_iter iter; struct consumer_socket *socket; - + rcu_read_lock(); cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, socket, node.node) { /* Code flow error */ assert(socket->fd >= 0); pthread_mutex_lock(socket->lock); - ret = kernel_consumer_send_channel_stream(socket->fd, + ret = kernel_consumer_send_channel_stream(socket, channel, ksess); pthread_mutex_unlock(socket->lock); if (ret < 0) { + rcu_read_unlock(); goto error; } } + rcu_read_unlock(); } goto error; } @@ -693,34 +703,42 @@ static void *thread_manage_kernel(void *data) char tmp; struct lttng_poll_event events; - DBG("Thread manage kernel started"); - - testpoint(thread_manage_kernel); - - health_code_update(&health_thread_kernel); + DBG("[thread] Thread manage kernel started"); - testpoint(thread_manage_kernel_before_loop); + /* + * This first step of the while is to clean this structure which could free + * non NULL pointers so zero it before the loop. + */ + memset(&events, 0, sizeof(events)); - ret = create_thread_poll_set(&events, 2); - if (ret < 0) { - goto error_poll_create; + if (testpoint(thread_manage_kernel)) { + goto error_testpoint; } - ret = lttng_poll_add(&events, kernel_poll_pipe[0], LPOLLIN); - if (ret < 0) { - goto error; + health_code_update(&health_thread_kernel); + + if (testpoint(thread_manage_kernel_before_loop)) { + goto error_testpoint; } while (1) { health_code_update(&health_thread_kernel); if (update_poll_flag == 1) { - /* - * Reset number of fd in the poll set. Always 2 since there is the thread - * quit pipe and the kernel pipe. - */ - events.nb_fd = 2; + /* Clean events object. We are about to populate it again. */ + lttng_poll_clean(&events); + + ret = create_thread_poll_set(&events, 2); + if (ret < 0) { + goto error_poll_create; + } + + ret = lttng_poll_add(&events, kernel_poll_pipe[0], LPOLLIN); + if (ret < 0) { + goto error; + } + /* This will add the available kernel channel if any. */ ret = update_kernel_poll(&events); if (ret < 0) { goto error; @@ -728,12 +746,7 @@ static void *thread_manage_kernel(void *data) update_poll_flag = 0; } - nb_fd = LTTNG_POLL_GETNB(&events); - - DBG("Thread kernel polling on %d fds", nb_fd); - - /* Zeroed the poll events */ - lttng_poll_reset(&events); + DBG("Thread kernel polling on %d fds", LTTNG_POLL_GETNB(&events)); /* Poll infinite value of time */ restart: @@ -755,6 +768,8 @@ static void *thread_manage_kernel(void *data) continue; } + nb_fd = ret; + for (i = 0; i < nb_fd; i++) { /* Fetch once the poll data */ revents = LTTNG_POLL_GETEV(&events, i); @@ -771,7 +786,13 @@ static void *thread_manage_kernel(void *data) /* Check for data on kernel pipe */ if (pollfd == kernel_poll_pipe[0] && (revents & LPOLLIN)) { - ret = read(kernel_poll_pipe[0], &tmp, 1); + do { + ret = read(kernel_poll_pipe[0], &tmp, 1); + } while (ret < 0 && errno == EINTR); + /* + * Ret value is useless here, if this pipe gets any actions an + * update is required anyway. + */ update_poll_flag = 1; continue; } else { @@ -798,9 +819,14 @@ exit: error: lttng_poll_clean(&events); error_poll_create: +error_testpoint: + utils_close_pipe(kernel_poll_pipe); + kernel_poll_pipe[0] = kernel_poll_pipe[1] = -1; if (err) { health_error(&health_thread_kernel); ERR("Health error occurred in %s", __func__); + WARN("Kernel thread died unexpectedly. " + "Kernel tracing can continue but CPU hotplug is disabled."); } health_exit(&health_thread_kernel); DBG("Kernel thread dying"); @@ -881,15 +907,15 @@ static void *thread_manage_consumer(void *data) goto error; } - nb_fd = LTTNG_POLL_GETNB(&events); - health_code_update(&consumer_data->health); /* Inifinite blocking call, waiting for transmission */ restart: health_poll_update(&consumer_data->health); - testpoint(thread_manage_consumer); + if (testpoint(thread_manage_consumer)) { + goto error; + } ret = lttng_poll_wait(&events, -1); health_poll_update(&consumer_data->health); @@ -903,6 +929,8 @@ restart: goto error; } + nb_fd = ret; + for (i = 0; i < nb_fd; i++) { /* Fetch once the poll data */ revents = LTTNG_POLL_GETEV(&events, i); @@ -980,9 +1008,6 @@ restart: health_code_update(&consumer_data->health); - /* Update number of fd */ - nb_fd = LTTNG_POLL_GETNB(&events); - /* Inifinite blocking call, waiting for transmission */ restart_poll: health_poll_update(&consumer_data->health); @@ -998,6 +1023,8 @@ restart_poll: goto error; } + nb_fd = ret; + for (i = 0; i < nb_fd; i++) { /* Fetch once the poll data */ revents = LTTNG_POLL_GETEV(&events, i); @@ -1093,11 +1120,13 @@ static void *thread_manage_apps(void *data) DBG("[thread] Manage application started"); - testpoint(thread_manage_apps); - rcu_register_thread(); rcu_thread_online(); + if (testpoint(thread_manage_apps)) { + goto error_testpoint; + } + health_code_update(&health_thread_app_manage); ret = create_thread_poll_set(&events, 2); @@ -1110,17 +1139,14 @@ static void *thread_manage_apps(void *data) goto error; } - testpoint(thread_manage_apps_before_loop); + if (testpoint(thread_manage_apps_before_loop)) { + goto error; + } health_code_update(&health_thread_app_manage); while (1) { - /* Zeroed the events structure */ - lttng_poll_reset(&events); - - nb_fd = LTTNG_POLL_GETNB(&events); - - DBG("Apps thread polling on %d fds", nb_fd); + DBG("Apps thread polling on %d fds", LTTNG_POLL_GETNB(&events)); /* Inifinite blocking call, waiting for transmission */ restart: @@ -1137,6 +1163,8 @@ static void *thread_manage_apps(void *data) goto error; } + nb_fd = ret; + for (i = 0; i < nb_fd; i++) { /* Fetch once the poll data */ revents = LTTNG_POLL_GETEV(&events, i); @@ -1158,7 +1186,9 @@ static void *thread_manage_apps(void *data) goto error; } else if (revents & LPOLLIN) { /* Empty pipe */ - ret = read(apps_cmd_pipe[0], &ust_cmd, sizeof(ust_cmd)); + do { + ret = read(apps_cmd_pipe[0], &ust_cmd, sizeof(ust_cmd)); + } while (ret < 0 && errno == EINTR); if (ret < 0 || ret < sizeof(ust_cmd)) { PERROR("read apps cmd pipe"); goto error; @@ -1250,6 +1280,16 @@ exit: error: lttng_poll_clean(&events); error_poll_create: +error_testpoint: + utils_close_pipe(apps_cmd_pipe); + apps_cmd_pipe[0] = apps_cmd_pipe[1] = -1; + + /* + * We don't clean the UST app hash table here since already registered + * applications can still be controlled so let them be until the session + * daemon dies or the applications stop. + */ + if (err) { health_error(&health_thread_app_manage); ERR("Health error occurred in %s", __func__); @@ -1299,18 +1339,28 @@ static void *thread_dispatch_ust_registration(void *data) * call is blocking so we can be assured that the data will be read * at some point in time or wait to the end of the world :) */ - ret = write(apps_cmd_pipe[1], ust_cmd, - sizeof(struct ust_command)); - if (ret < 0) { - PERROR("write apps cmd pipe"); - if (errno == EBADF) { - /* - * We can't inform the application thread to process - * registration. We will exit or else application - * registration will not occur and tracing will never - * start. - */ - goto error; + if (apps_cmd_pipe[1] >= 0) { + do { + ret = write(apps_cmd_pipe[1], ust_cmd, + sizeof(struct ust_command)); + } while (ret < 0 && errno == EINTR); + if (ret < 0 || ret != sizeof(struct ust_command)) { + PERROR("write apps cmd pipe"); + if (errno == EBADF) { + /* + * We can't inform the application thread to process + * registration. We will exit or else application + * registration will not occur and tracing will never + * start. + */ + goto error; + } + } + } else { + /* Application manager thread is not available. */ + ret = close(ust_cmd->sock); + if (ret < 0) { + PERROR("close ust_cmd sock"); } } free(ust_cmd); @@ -1341,7 +1391,9 @@ static void *thread_registration_apps(void *data) DBG("[thread] Manage application registration started"); - testpoint(thread_registration_apps); + if (testpoint(thread_registration_apps)) { + goto error_testpoint; + } ret = lttcomm_listen_unix_sock(apps_sock); if (ret < 0) { @@ -1374,8 +1426,6 @@ static void *thread_registration_apps(void *data) while (1) { DBG("Accepting application registration"); - nb_fd = LTTNG_POLL_GETNB(&events); - /* Inifinite blocking call, waiting for transmission */ restart: health_poll_update(&health_thread_app_reg); @@ -1391,6 +1441,8 @@ static void *thread_registration_apps(void *data) goto error; } + nb_fd = ret; + for (i = 0; i < nb_fd; i++) { health_code_update(&health_thread_app_reg); @@ -1496,7 +1548,6 @@ error: health_error(&health_thread_app_reg); ERR("Health error occurred in %s", __func__); } - health_exit(&health_thread_app_reg); /* Notify that the registration thread is gone */ notify_ust_apps(0); @@ -1520,7 +1571,9 @@ error_poll_add: lttng_poll_clean(&events); error_listen: error_create_poll: +error_testpoint: DBG("UST Registration thread cleanup complete"); + health_exit(&health_thread_app_reg); return NULL; } @@ -1652,10 +1705,10 @@ error: static int join_consumer_thread(struct consumer_data *consumer_data) { void *status; - int ret; /* Consumer pid must be a real one. */ if (consumer_data->pid > 0) { + int ret; ret = kill(consumer_data->pid, SIGTERM); if (ret) { ERR("Error killing consumer daemon"); @@ -1834,7 +1887,7 @@ error: */ static int start_consumerd(struct consumer_data *consumer_data) { - int ret, err; + int ret; /* * Set the listen() state on the socket since there is a possible race @@ -1877,6 +1930,8 @@ end: error: /* Cleanup already created socket on error. */ if (consumer_data->err_sock >= 0) { + int err; + err = close(consumer_data->err_sock); if (err < 0) { PERROR("close consumer data error socket"); @@ -2444,7 +2499,6 @@ skip_domain: { ret = cmd_add_context(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.context.channel_name, - cmd_ctx->lsm->u.context.event_name, &cmd_ctx->lsm->u.context.ctx, kernel_poll_pipe[1]); break; } @@ -2508,7 +2562,7 @@ skip_domain: { ret = cmd_enable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, kernel_poll_pipe[1]); + &cmd_ctx->lsm->u.enable.event, NULL, kernel_poll_pipe[1]); break; } case LTTNG_ENABLE_ALL_EVENT: @@ -2517,7 +2571,7 @@ skip_domain: ret = cmd_enable_event_all(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.enable.channel_name, - cmd_ctx->lsm->u.enable.event.type, kernel_poll_pipe[1]); + cmd_ctx->lsm->u.enable.event.type, NULL, kernel_poll_pipe[1]); break; } case LTTNG_LIST_TRACEPOINTS: @@ -2829,15 +2883,19 @@ skip_domain: cmd_ctx->lsm->u.reg.path, cdata); break; } - case LTTNG_SET_FILTER: + case LTTNG_ENABLE_EVENT_WITH_FILTER: { struct lttng_filter_bytecode *bytecode; - if (cmd_ctx->lsm->u.filter.bytecode_len > LTTNG_FILTER_MAX_LEN) { + 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.filter.bytecode_len); + bytecode = zmalloc(cmd_ctx->lsm->u.enable.bytecode_len); if (!bytecode) { ret = LTTNG_ERR_FILTER_NOMEM; goto error; @@ -2845,7 +2903,7 @@ skip_domain: /* Receive var. len. data */ DBG("Receiving var len data from client ..."); ret = lttcomm_recv_unix_sock(sock, bytecode, - cmd_ctx->lsm->u.filter.bytecode_len); + cmd_ctx->lsm->u.enable.bytecode_len); if (ret <= 0) { DBG("Nothing recv() from client var len data... continuing"); *sock_error = 1; @@ -2854,16 +2912,15 @@ skip_domain: } if (bytecode->len + sizeof(*bytecode) - != cmd_ctx->lsm->u.filter.bytecode_len) { + != cmd_ctx->lsm->u.enable.bytecode_len) { free(bytecode); ret = LTTNG_ERR_FILTER_INVAL; goto error; } - ret = cmd_set_filter(cmd_ctx->session, cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.filter.channel_name, - cmd_ctx->lsm->u.filter.event_name, - bytecode); + ret = cmd_enable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type, + cmd_ctx->lsm->u.enable.channel_name, + &cmd_ctx->lsm->u.enable.event, bytecode, kernel_poll_pipe[1]); break; } case LTTNG_DATA_PENDING: @@ -2948,8 +3005,6 @@ static void *thread_manage_health(void *data) while (1) { DBG("Health check ready"); - nb_fd = LTTNG_POLL_GETNB(&events); - /* Inifinite blocking call, waiting for transmission */ restart: ret = lttng_poll_wait(&events, -1); @@ -2963,6 +3018,8 @@ restart: goto error; } + nb_fd = ret; + for (i = 0; i < nb_fd; i++) { /* Fetch once the poll data */ revents = LTTNG_POLL_GETEV(&events, i); @@ -3103,10 +3160,12 @@ static void *thread_manage_clients(void *data) DBG("[thread] Manage client started"); - testpoint(thread_manage_clients); - rcu_register_thread(); + if (testpoint(thread_manage_clients)) { + goto error_testpoint; + } + health_code_update(&health_thread_cmd); ret = lttcomm_listen_unix_sock(client_sock); @@ -3136,15 +3195,15 @@ static void *thread_manage_clients(void *data) kill(ppid, SIGUSR1); } - testpoint(thread_manage_clients_before_loop); + if (testpoint(thread_manage_clients_before_loop)) { + goto error; + } health_code_update(&health_thread_cmd); while (1) { DBG("Accepting client command ..."); - nb_fd = LTTNG_POLL_GETNB(&events); - /* Inifinite blocking call, waiting for transmission */ restart: health_poll_update(&health_thread_cmd); @@ -3160,6 +3219,8 @@ static void *thread_manage_clients(void *data) goto error; } + nb_fd = ret; + for (i = 0; i < nb_fd; i++) { /* Fetch once the poll data */ revents = LTTNG_POLL_GETEV(&events, i); @@ -3311,6 +3372,7 @@ error: error_listen: error_create_poll: +error_testpoint: unlink(client_unix_sock_path); if (client_sock >= 0) { ret = close(client_sock); @@ -3358,6 +3420,7 @@ static void usage(void) fprintf(stderr, " -S, --sig-parent Send SIGCHLD 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"); fprintf(stderr, " --verbose-consumer Verbose mode for consumer. Activate DBG() macro.\n"); fprintf(stderr, " --no-kernel Disable kernel tracer\n"); } @@ -3391,12 +3454,13 @@ static int parse_args(int argc, char **argv) { "verbose", 0, 0, 'v' }, { "verbose-consumer", 0, 0, 'Z' }, { "no-kernel", 0, 0, 'N' }, + { "pidfile", 1, 0, 'p' }, { 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", + c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:", long_options, &option_index); if (c == -1) { break; @@ -3473,6 +3537,9 @@ static int parse_args(int argc, char **argv) case 'T': consumerd64_libdir = optarg; break; + case 'p': + opt_pidfile = optarg; + break; default: /* Unknown option or other error. * Error is printed by getopt, just return */ @@ -3799,6 +3866,38 @@ static void set_ulimit(void) } } +/* + * Write pidfile using the rundir and opt_pidfile. + */ +static void write_pidfile(void) +{ + int ret; + char pidfile_path[PATH_MAX]; + + assert(rundir); + + if (opt_pidfile) { + strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path)); + } else { + /* Build pidfile path from rundir and opt_pidfile. */ + ret = snprintf(pidfile_path, sizeof(pidfile_path), "%s/" + DEFAULT_LTTNG_SESSIOND_PIDFILE, rundir); + if (ret < 0) { + PERROR("snprintf pidfile path"); + goto error; + } + } + + /* + * Create pid 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(getpid(), pidfile_path); + +error: + return; +} + /* * main */ @@ -3816,7 +3915,7 @@ int main(int argc, char **argv) /* Parse arguments */ progname = argv[0]; - if ((ret = parse_args(argc, argv) < 0)) { + if ((ret = parse_args(argc, argv)) < 0) { goto error; } @@ -4043,8 +4142,10 @@ int main(int argc, char **argv) } /* Setup the kernel pipe for waking up the kernel thread */ - if ((ret = utils_create_pipe_cloexec(kernel_poll_pipe)) < 0) { - goto exit; + if (is_root && !opt_no_kernel) { + if ((ret = utils_create_pipe_cloexec(kernel_poll_pipe)) < 0) { + goto exit; + } } /* Setup the thread apps communication pipe. */ @@ -4094,6 +4195,8 @@ int main(int argc, char **argv) app_socket_timeout = DEFAULT_APP_SOCKET_RW_TIMEOUT; } + write_pidfile(); + /* Create thread to manage the client socket */ ret = pthread_create(&health_thread, NULL, thread_manage_health, (void *) NULL); @@ -4134,18 +4237,21 @@ int main(int argc, char **argv) goto exit_apps; } - /* Create kernel thread to manage kernel event */ - ret = pthread_create(&kernel_thread, NULL, - thread_manage_kernel, (void *) NULL); - if (ret != 0) { - PERROR("pthread_create kernel"); - goto exit_kernel; - } + /* Don't start this thread if kernel tracing is not requested nor root */ + if (is_root && !opt_no_kernel) { + /* Create kernel thread to manage kernel event */ + ret = pthread_create(&kernel_thread, NULL, + thread_manage_kernel, (void *) NULL); + if (ret != 0) { + PERROR("pthread_create kernel"); + goto exit_kernel; + } - ret = pthread_join(kernel_thread, &status); - if (ret != 0) { - PERROR("pthread_join"); - goto error; /* join error, exit without cleanup */ + ret = pthread_join(kernel_thread, &status); + if (ret != 0) { + PERROR("pthread_join"); + goto error; /* join error, exit without cleanup */ + } } exit_kernel: