X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=ltt-sessiond%2Fmain.c;h=167187e4da6801ba1b7e38ad9d21bd081b0b5730;hp=bcb43e19d423345fda151561f2a5b3353eeeef96;hb=9a745bc7cbb8247543e38420fb8ba74f1756942d;hpb=532d79a74ed67913120fc339c2bff925cc6ab2bc diff --git a/ltt-sessiond/main.c b/ltt-sessiond/main.c index bcb43e19d..167187e4d 100644 --- a/ltt-sessiond/main.c +++ b/ltt-sessiond/main.c @@ -36,10 +36,11 @@ #include #include #include +#include -#include +#include #include -#include +#include #include #include "channel.h" @@ -50,11 +51,29 @@ #include "kernel-ctl.h" #include "ltt-sessiond.h" #include "shm.h" -#include "traceable-app.h" +#include "ust-app.h" #include "ust-ctl.h" #include "utils.h" #include "ust-ctl.h" +struct consumer_data { + enum lttng_consumer_type type; + + pthread_t thread; /* Worker thread interacting with the consumer */ + sem_t sem; + + /* Mutex to control consumerd pid assignation */ + pthread_mutex_t pid_mutex; + pid_t pid; + + int err_sock; + int cmd_sock; + + /* consumer error and command Unix socket path */ + char err_unix_sock_path[PATH_MAX]; + char cmd_unix_sock_path[PATH_MAX]; +}; + /* Const values */ const char default_home_dir[] = DEFAULT_HOME_DIR; const char default_tracing_group[] = LTTNG_DEFAULT_TRACING_GROUP; @@ -63,7 +82,7 @@ const char default_global_apps_pipe[] = DEFAULT_GLOBAL_APPS_PIPE; /* Variables */ int opt_verbose; /* Not static for lttngerr.h */ -int opt_verbose_kconsumerd; /* Not static for lttngerr.h */ +int opt_verbose_consumer; /* Not static for lttngerr.h */ int opt_quiet; /* Not static for lttngerr.h */ const char *progname; @@ -72,24 +91,27 @@ static int opt_sig_parent; static int opt_daemon; 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 kconsumerd_pid; + +/* Consumer daemon specific control data */ +static struct consumer_data kconsumer_data = { + .type = LTTNG_CONSUMER_KERNEL, +}; +static struct consumer_data ustconsumer_data = { + .type = LTTNG_CONSUMER_UST, +}; + static int dispatch_thread_exit; /* Global application Unix socket path */ static char apps_unix_sock_path[PATH_MAX]; /* Global client Unix socket path */ static char client_unix_sock_path[PATH_MAX]; -/* kconsumerd error and command Unix socket path */ -static char kconsumerd_err_unix_sock_path[PATH_MAX]; -static char kconsumerd_cmd_unix_sock_path[PATH_MAX]; /* global wait shm path for UST */ static char wait_shm_path[PATH_MAX]; /* Sockets and FDs */ static int client_sock; static int apps_sock; -static int kconsumerd_err_sock; -static int kconsumerd_cmd_sock; static int kernel_tracer_fd; static int kernel_poll_pipe[2]; @@ -106,17 +128,12 @@ static int thread_quit_pipe[2]; static int apps_cmd_pipe[2]; /* Pthread, Mutexes and Semaphores */ -static pthread_t kconsumerd_thread; static pthread_t apps_thread; static pthread_t reg_apps_thread; static pthread_t client_thread; static pthread_t kernel_thread; static pthread_t dispatch_thread; -static sem_t kconsumerd_sem; - -/* Mutex to control kconsumerd pid assignation */ -static pthread_mutex_t kconsumerd_pid_mutex; /* * UST registration command queue. This queue is tied with a futex and uses a N @@ -269,7 +286,7 @@ static void teardown_kernel_session(struct ltt_session *session) * If a custom kernel consumer was registered, close the socket before * tearing down the complete kernel session structure */ - if (session->kernel_session->consumer_fd != kconsumerd_cmd_sock) { + if (session->kernel_session->consumer_fd != kconsumer_data.cmd_sock) { lttcomm_close_unix_sock(session->kernel_session->consumer_fd); } @@ -344,9 +361,9 @@ static void cleanup(void) } DBG("Closing all UST sockets"); - clean_traceable_apps_list(); + ust_app_clean_list(); - pthread_mutex_destroy(&kconsumerd_pid_mutex); + pthread_mutex_destroy(&kconsumer_data.pid_mutex); DBG("Closing kernel fd"); close(kernel_tracer_fd); @@ -396,54 +413,57 @@ static void clean_command_ctx(struct command_ctx **cmd_ctx) /* * Send all stream fds of kernel channel to the consumer. */ -static int send_kconsumerd_channel_fds(int sock, - struct ltt_kernel_channel *channel) +static int send_consumer_channel_streams(struct consumer_data *consumer_data, + int sock, struct ltt_kernel_channel *channel) { int ret; size_t nb_fd; struct ltt_kernel_stream *stream; - struct lttcomm_kconsumerd_header lkh; - struct lttcomm_kconsumerd_msg lkm; + struct lttcomm_consumer_msg lkm; - DBG("Sending fds of channel %s to kernel consumer", + DBG("Sending streams of channel %s to kernel consumer", channel->channel->name); - nb_fd = channel->stream_count; - /* Setup header */ - lkh.payload_size = nb_fd * sizeof(struct lttcomm_kconsumerd_msg); - lkh.cmd_type = ADD_STREAM; - - DBG("Sending kconsumerd header"); - - ret = lttcomm_send_unix_sock(sock, &lkh, - sizeof(struct lttcomm_kconsumerd_header)); + /* Send channel */ + lkm.cmd_type = LTTNG_CONSUMER_ADD_CHANNEL; + lkm.u.channel.channel_key = channel->fd; + lkm.u.channel.max_sb_size = channel->channel->attr.subbuf_size; + lkm.u.channel.mmap_len = 0; /* for kernel */ + DBG("Sending channel %d to consumer", lkm.u.stream.stream_key); + ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm)); if (ret < 0) { - perror("send kconsumerd header"); + perror("send consumer channel"); goto error; } + /* Send streams */ cds_list_for_each_entry(stream, &channel->stream_list.head, list) { - if (stream->fd != 0) { - lkm.fd = stream->fd; - lkm.state = stream->state; - lkm.max_sb_size = channel->channel->attr.subbuf_size; - lkm.output = channel->channel->attr.output; - strncpy(lkm.path_name, stream->pathname, PATH_MAX); - lkm.path_name[PATH_MAX - 1] = '\0'; - - DBG("Sending fd %d to kconsumerd", lkm.fd); - - ret = lttcomm_send_fds_unix_sock(sock, &lkm, - &lkm.fd, 1, sizeof(lkm)); - if (ret < 0) { - perror("send kconsumerd fd"); - goto error; - } + if (!stream->fd) { + continue; + } + lkm.cmd_type = LTTNG_CONSUMER_ADD_STREAM; + lkm.u.stream.channel_key = channel->fd; + lkm.u.stream.stream_key = stream->fd; + lkm.u.stream.state = stream->state; + lkm.u.stream.output = channel->channel->attr.output; + lkm.u.stream.mmap_len = 0; /* for kernel */ + strncpy(lkm.u.stream.path_name, stream->pathname, PATH_MAX - 1); + lkm.u.stream.path_name[PATH_MAX - 1] = '\0'; + DBG("Sending stream %d to consumer", lkm.u.stream.stream_key); + ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm)); + if (ret < 0) { + perror("send consumer stream"); + goto error; + } + ret = lttcomm_send_fds_unix_sock(sock, &stream->fd, 1); + if (ret < 0) { + perror("send consumer stream ancillary data"); + goto error; } } - DBG("Kconsumerd channel fds sent"); + DBG("consumer channel streams sent"); return 0; @@ -454,58 +474,64 @@ error: /* * Send all stream fds of the kernel session to the consumer. */ -static int send_kconsumerd_fds(struct ltt_kernel_session *session) +static int send_consumer_session_streams(struct consumer_data *consumer_data, + struct ltt_kernel_session *session) { int ret; struct ltt_kernel_channel *chan; - struct lttcomm_kconsumerd_header lkh; - struct lttcomm_kconsumerd_msg lkm; - - /* Setup header */ - lkh.payload_size = sizeof(struct lttcomm_kconsumerd_msg); - lkh.cmd_type = ADD_STREAM; - - DBG("Sending kconsumerd header for metadata"); - - ret = lttcomm_send_unix_sock(session->consumer_fd, &lkh, - sizeof(struct lttcomm_kconsumerd_header)); - if (ret < 0) { - perror("send kconsumerd header"); - goto error; - } + struct lttcomm_consumer_msg lkm; + int sock = session->consumer_fd; DBG("Sending metadata stream fd"); /* Extra protection. It's NOT suppose to be set to 0 at this point */ if (session->consumer_fd == 0) { - session->consumer_fd = kconsumerd_cmd_sock; + session->consumer_fd = consumer_data->cmd_sock; } if (session->metadata_stream_fd != 0) { - /* Send metadata stream fd first */ - lkm.fd = session->metadata_stream_fd; - lkm.state = ACTIVE_FD; - lkm.max_sb_size = session->metadata->conf->attr.subbuf_size; - lkm.output = DEFAULT_KERNEL_CHANNEL_OUTPUT; - strncpy(lkm.path_name, session->metadata->pathname, PATH_MAX); - lkm.path_name[PATH_MAX - 1] = '\0'; - - ret = lttcomm_send_fds_unix_sock(session->consumer_fd, &lkm, - &lkm.fd, 1, sizeof(lkm)); + /* Send metadata channel fd */ + lkm.cmd_type = LTTNG_CONSUMER_ADD_CHANNEL; + lkm.u.channel.channel_key = session->metadata->fd; + lkm.u.channel.max_sb_size = session->metadata->conf->attr.subbuf_size; + lkm.u.channel.mmap_len = 0; /* for kernel */ + DBG("Sending metadata channel %d to consumer", lkm.u.stream.stream_key); + ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm)); + if (ret < 0) { + perror("send consumer channel"); + goto error; + } + + /* Send metadata stream fd */ + lkm.cmd_type = LTTNG_CONSUMER_ADD_STREAM; + lkm.u.stream.channel_key = session->metadata->fd; + lkm.u.stream.stream_key = session->metadata_stream_fd; + lkm.u.stream.state = LTTNG_CONSUMER_ACTIVE_STREAM; + lkm.u.stream.output = DEFAULT_KERNEL_CHANNEL_OUTPUT; + lkm.u.stream.mmap_len = 0; /* for kernel */ + strncpy(lkm.u.stream.path_name, session->metadata->pathname, PATH_MAX - 1); + lkm.u.stream.path_name[PATH_MAX - 1] = '\0'; + DBG("Sending metadata stream %d to consumer", lkm.u.stream.stream_key); + ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm)); + if (ret < 0) { + perror("send consumer stream"); + goto error; + } + ret = lttcomm_send_fds_unix_sock(sock, &session->metadata_stream_fd, 1); if (ret < 0) { - perror("send kconsumerd fd"); + perror("send consumer stream"); goto error; } } cds_list_for_each_entry(chan, &session->channel_list.head, list) { - ret = send_kconsumerd_channel_fds(session->consumer_fd, chan); + ret = send_consumer_channel_streams(consumer_data, sock, chan); if (ret < 0) { goto error; } } - DBG("Kconsumerd fds (metadata and channel streams) sent"); + DBG("consumer fds (metadata and channel streams) sent"); return 0; @@ -618,7 +644,7 @@ error: * * Useful for CPU hotplug feature. */ -static int update_kernel_stream(int fd) +static int update_stream(struct consumer_data *consumer_data, int fd) { int ret = 0; struct ltt_session *session; @@ -636,7 +662,7 @@ static int update_kernel_stream(int fd) /* This is not suppose to be 0 but this is an extra security check */ if (session->kernel_session->consumer_fd == 0) { - session->kernel_session->consumer_fd = kconsumerd_cmd_sock; + session->kernel_session->consumer_fd = consumer_data->cmd_sock; } cds_list_for_each_entry(channel, @@ -653,8 +679,8 @@ static int update_kernel_stream(int fd) * that tracing is started so it is safe to send our updated * stream fds. */ - if (session->kernel_session->kconsumer_fds_sent == 1) { - ret = send_kconsumerd_channel_fds( + if (session->kernel_session->consumer_fds_sent == 1) { + ret = send_consumer_channel_streams(consumer_data, session->kernel_session->consumer_fd, channel); if (ret < 0) { goto error; @@ -701,6 +727,12 @@ static void *thread_manage_kernel(void *data) while (1) { 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; + ret = update_kernel_poll(&events); if (ret < 0) { goto error; @@ -748,7 +780,7 @@ static void *thread_manage_kernel(void *data) * kernel session and updating the kernel consumer */ if (revents & LPOLLIN) { - ret = update_kernel_stream(pollfd); + ret = update_stream(&kconsumer_data, pollfd); if (ret < 0) { continue; } @@ -773,18 +805,19 @@ error: } /* - * This thread manage the kconsumerd error sent back to the session daemon. + * This thread manage the consumer error sent back to the session daemon. */ -static void *thread_manage_kconsumerd(void *data) +static void *thread_manage_consumer(void *data) { int sock = 0, i, ret, pollfd; uint32_t revents, nb_fd; enum lttcomm_return_code code; struct lttng_poll_event events; + struct consumer_data *consumer_data = data; - DBG("[thread] Manage kconsumerd started"); + DBG("[thread] Manage consumer started"); - ret = lttcomm_listen_unix_sock(kconsumerd_err_sock); + ret = lttcomm_listen_unix_sock(consumer_data->err_sock); if (ret < 0) { goto error; } @@ -798,7 +831,7 @@ static void *thread_manage_kconsumerd(void *data) goto error; } - ret = lttng_poll_add(&events, kconsumerd_err_sock, LPOLLIN | LPOLLRDHUP); + ret = lttng_poll_add(&events, consumer_data->err_sock, LPOLLIN | LPOLLRDHUP); if (ret < 0) { goto error; } @@ -823,19 +856,21 @@ static void *thread_manage_kconsumerd(void *data) } /* Event on the registration socket */ - if (pollfd == kconsumerd_err_sock) { + if (pollfd == consumer_data->err_sock) { if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { - ERR("Kconsumerd err socket poll error"); + ERR("consumer err socket poll error"); goto error; } } } - sock = lttcomm_accept_unix_sock(kconsumerd_err_sock); + sock = lttcomm_accept_unix_sock(consumer_data->err_sock); if (sock < 0) { goto error; } + DBG2("Receiving code from consumer err_sock"); + /* Getting status code from kconsumerd */ ret = lttcomm_recv_unix_sock(sock, &code, sizeof(enum lttcomm_return_code)); @@ -843,25 +878,25 @@ static void *thread_manage_kconsumerd(void *data) goto error; } - if (code == KCONSUMERD_COMMAND_SOCK_READY) { - kconsumerd_cmd_sock = - lttcomm_connect_unix_sock(kconsumerd_cmd_unix_sock_path); - if (kconsumerd_cmd_sock < 0) { - sem_post(&kconsumerd_sem); - perror("kconsumerd connect"); + if (code == CONSUMERD_COMMAND_SOCK_READY) { + consumer_data->cmd_sock = + lttcomm_connect_unix_sock(consumer_data->cmd_unix_sock_path); + if (consumer_data->cmd_sock < 0) { + sem_post(&consumer_data->sem); + perror("consumer connect"); goto error; } /* Signal condition to tell that the kconsumerd is ready */ - sem_post(&kconsumerd_sem); - DBG("Kconsumerd command socket ready"); + sem_post(&consumer_data->sem); + DBG("consumer command socket ready"); } else { - DBG("Kconsumerd error when waiting for SOCK_READY : %s", + ERR("consumer error when waiting for SOCK_READY : %s", lttcomm_get_readable_code(-code)); goto error; } /* Remove the kconsumerd error sock since we've established a connexion */ - ret = lttng_poll_del(&events, kconsumerd_err_sock); + ret = lttng_poll_del(&events, consumer_data->err_sock); if (ret < 0) { goto error; } @@ -894,7 +929,7 @@ static void *thread_manage_kconsumerd(void *data) /* Event on the kconsumerd socket */ if (pollfd == sock) { if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { - ERR("Kconsumerd err socket second poll error"); + ERR("consumer err socket second poll error"); goto error; } } @@ -904,21 +939,21 @@ static void *thread_manage_kconsumerd(void *data) ret = lttcomm_recv_unix_sock(sock, &code, sizeof(enum lttcomm_return_code)); if (ret <= 0) { - ERR("Kconsumerd closed the command socket"); + ERR("consumer closed the command socket"); goto error; } - ERR("Kconsumerd return code : %s", lttcomm_get_readable_code(-code)); + ERR("consumer return code : %s", lttcomm_get_readable_code(-code)); error: - DBG("Kconsumerd thread dying"); - close(kconsumerd_err_sock); - close(kconsumerd_cmd_sock); + DBG("consumer thread dying"); + close(consumer_data->err_sock); + close(consumer_data->cmd_sock); close(sock); - unlink(kconsumerd_err_unix_sock_path); - unlink(kconsumerd_cmd_unix_sock_path); - kconsumerd_pid = 0; + unlink(consumer_data->err_unix_sock_path); + unlink(consumer_data->cmd_unix_sock_path); + consumer_data->pid = 0; lttng_poll_clean(&events); @@ -986,7 +1021,7 @@ static void *thread_manage_apps(void *data) } /* Register applicaton to the session daemon */ - ret = register_traceable_app(&ust_cmd.reg_msg, + ret = ust_app_register(&ust_cmd.reg_msg, ust_cmd.sock); if (ret < 0) { /* Only critical ENOMEM error can be returned here */ @@ -999,7 +1034,7 @@ static void *thread_manage_apps(void *data) * If the registration is not possible, we simply * unregister the apps and continue */ - unregister_traceable_app(ust_cmd.sock); + ust_app_unregister(ust_cmd.sock); } else { /* * We just need here to monitor the close of the UST @@ -1028,7 +1063,7 @@ static void *thread_manage_apps(void *data) } /* Socket closed */ - unregister_traceable_app(pollfd); + ust_app_unregister(pollfd); break; } } @@ -1065,7 +1100,7 @@ static void *thread_dispatch_ust_registration(void *data) /* Dequeue command for registration */ node = cds_wfq_dequeue_blocking(&ust_cmd_queue.queue); if (node == NULL) { - DBG("Waked up but nothing in the UST command queue"); + DBG("Woken up but nothing in the UST command queue"); /* Continue thread execution */ break; } @@ -1251,131 +1286,173 @@ error: } /* - * Start the thread_manage_kconsumerd. This must be done after a kconsumerd + * Start the thread_manage_consumer. This must be done after a lttng-consumerd * exec or it will fails. */ -static int spawn_kconsumerd_thread(void) +static int spawn_consumer_thread(struct consumer_data *consumer_data) { int ret; + struct timespec timeout; + + timeout.tv_sec = DEFAULT_SEM_WAIT_TIMEOUT; + timeout.tv_nsec = 0; /* Setup semaphore */ - sem_init(&kconsumerd_sem, 0, 0); + ret = sem_init(&consumer_data->sem, 0, 0); + if (ret < 0) { + PERROR("sem_init consumer semaphore"); + goto error; + } - ret = pthread_create(&kconsumerd_thread, NULL, - thread_manage_kconsumerd, (void *) NULL); + ret = pthread_create(&consumer_data->thread, NULL, + thread_manage_consumer, consumer_data); if (ret != 0) { - perror("pthread_create kconsumerd"); + PERROR("pthread_create consumer"); + ret = -1; goto error; } - /* Wait for the kconsumerd thread to be ready */ - sem_wait(&kconsumerd_sem); + /* Get time for sem_timedwait absolute timeout */ + ret = clock_gettime(CLOCK_REALTIME, &timeout); + if (ret < 0) { + PERROR("clock_gettime spawn consumer"); + /* Infinite wait for the kconsumerd thread to be ready */ + ret = sem_wait(&consumer_data->sem); + } else { + /* Normal timeout if the gettime was successful */ + timeout.tv_sec += DEFAULT_SEM_WAIT_TIMEOUT; + ret = sem_timedwait(&consumer_data->sem, &timeout); + } + + if (ret < 0) { + if (errno == ETIMEDOUT) { + /* + * Call has timed out so we kill the kconsumerd_thread and return + * an error. + */ + ERR("The consumer thread was never ready. Killing it"); + ret = pthread_cancel(consumer_data->thread); + if (ret < 0) { + PERROR("pthread_cancel consumer thread"); + } + } else { + PERROR("semaphore wait failed consumer thread"); + } + goto error; + } - if (kconsumerd_pid == 0) { + pthread_mutex_lock(&consumer_data->pid_mutex); + if (consumer_data->pid == 0) { ERR("Kconsumerd did not start"); + pthread_mutex_unlock(&consumer_data->pid_mutex); goto error; } + pthread_mutex_unlock(&consumer_data->pid_mutex); return 0; error: - ret = LTTCOMM_KERN_CONSUMER_FAIL; return ret; } /* - * Join kernel consumer thread + * Join consumer thread */ -static int join_kconsumerd_thread(void) +static int join_consumer_thread(struct consumer_data *consumer_data) { void *status; int ret; - if (kconsumerd_pid != 0) { - ret = kill(kconsumerd_pid, SIGTERM); + if (consumer_data->pid != 0) { + ret = kill(consumer_data->pid, SIGTERM); if (ret) { - ERR("Error killing kconsumerd"); + ERR("Error killing consumer daemon"); return ret; } - return pthread_join(kconsumerd_thread, &status); + return pthread_join(consumer_data->thread, &status); } else { return 0; } } /* - * Fork and exec a kernel consumer daemon (kconsumerd). + * Fork and exec a consumer daemon (consumerd). * * Return pid if successful else -1. */ -static pid_t spawn_kconsumerd(void) +static pid_t spawn_consumerd(struct consumer_data *consumer_data) { int ret; pid_t pid; const char *verbosity; - DBG("Spawning kconsumerd"); + DBG("Spawning consumerd"); pid = fork(); if (pid == 0) { /* - * Exec kconsumerd. + * Exec consumerd. */ - if (opt_verbose > 1 || opt_verbose_kconsumerd) { + if (opt_verbose > 1 || opt_verbose_consumer) { verbosity = "--verbose"; } else { verbosity = "--quiet"; } - execl(INSTALL_BIN_PATH "/ltt-kconsumerd", - "ltt-kconsumerd", verbosity, NULL); + switch (consumer_data->type) { + case LTTNG_CONSUMER_KERNEL: + execl(INSTALL_BIN_PATH "/lttng-consumerd", + "lttng-consumerd", verbosity, "-k", NULL); + break; + case LTTNG_CONSUMER_UST: + execl(INSTALL_BIN_PATH "/lttng-consumerd", + "lttng-consumerd", verbosity, "-u", NULL); + break; + default: + perror("unknown consumer type"); + exit(EXIT_FAILURE); + } if (errno != 0) { perror("kernel start consumer exec"); } exit(EXIT_FAILURE); } else if (pid > 0) { ret = pid; - goto error; } else { - perror("kernel start consumer fork"); + perror("start consumer fork"); ret = -errno; - goto error; } - -error: return ret; } /* - * Spawn the kconsumerd daemon and session daemon thread. + * Spawn the consumerd daemon and session daemon thread. */ -static int start_kconsumerd(void) +static int start_consumerd(struct consumer_data *consumer_data) { int ret; - pthread_mutex_lock(&kconsumerd_pid_mutex); - if (kconsumerd_pid != 0) { - pthread_mutex_unlock(&kconsumerd_pid_mutex); + pthread_mutex_lock(&consumer_data->pid_mutex); + if (consumer_data->pid != 0) { + pthread_mutex_unlock(&consumer_data->pid_mutex); goto end; } - ret = spawn_kconsumerd(); + ret = spawn_consumerd(consumer_data); if (ret < 0) { - ERR("Spawning kconsumerd failed"); - ret = LTTCOMM_KERN_CONSUMER_FAIL; - pthread_mutex_unlock(&kconsumerd_pid_mutex); + ERR("Spawning consumerd failed"); + pthread_mutex_unlock(&consumer_data->pid_mutex); goto error; } - /* Setting up the global kconsumerd_pid */ - kconsumerd_pid = ret; - pthread_mutex_unlock(&kconsumerd_pid_mutex); + /* Setting up the consumer_data pid */ + consumer_data->pid = ret; + DBG2("consumer pid %d", consumer_data->pid); + pthread_mutex_unlock(&consumer_data->pid_mutex); - DBG("Kconsumerd pid %d", ret); - - DBG("Spawning kconsumerd thread"); - ret = spawn_kconsumerd_thread(); + DBG2("Spawning consumer control thread"); + ret = spawn_consumer_thread(consumer_data); if (ret < 0) { - ERR("Fatal error spawning kconsumerd thread"); + ERR("Fatal error spawning consumer control thread"); goto error; } @@ -1432,12 +1509,13 @@ static int mount_debugfs(char *path) ret = mkdir_recursive(path, S_IRWXU | S_IRWXG, geteuid(), getegid()); if (ret < 0) { + PERROR("Cannot create debugfs path"); goto error; } ret = mount(type, path, type, 0, NULL); if (ret < 0) { - perror("mount debugfs"); + PERROR("Cannot mount debugfs"); goto error; } @@ -1487,6 +1565,7 @@ static void init_kernel_tracer(void) } ret = mount_debugfs(debugfs_path); if (ret < 0) { + perror("Cannot mount debugfs"); goto error; } } @@ -1535,23 +1614,23 @@ static int init_kernel_tracing(struct ltt_kernel_session *session) { int ret = 0; - if (session->kconsumer_fds_sent == 0) { + if (session->consumer_fds_sent == 0) { /* * Assign default kernel consumer socket if no consumer assigned to the * kernel session. At this point, it's NOT suppose to be 0 but this is * an extra security check. */ if (session->consumer_fd == 0) { - session->consumer_fd = kconsumerd_cmd_sock; + session->consumer_fd = kconsumer_data.cmd_sock; } - ret = send_kconsumerd_fds(session); + ret = send_consumer_session_streams(&kconsumer_data, session); if (ret < 0) { ret = LTTCOMM_KERN_CONSUMER_FAIL; goto error; } - session->kconsumer_fds_sent = 1; + session->consumer_fds_sent = 1; } error: @@ -1561,15 +1640,31 @@ error: /* * Create an UST session and add it to the session ust list. */ -static int create_ust_session(pid_t pid, struct ltt_session *session) +static int create_ust_session(struct ltt_session *session, + struct lttng_domain *domain) { - int ret = -1; - struct ltt_ust_session *lus; + int ret; + struct ltt_ust_session *lus = NULL; + struct ust_app *app; + + switch (domain->type) { + case LTTNG_DOMAIN_UST_PID: + app = ust_app_get_by_pid(domain->attr.pid); + if (app == NULL) { + ret = LTTCOMM_APP_NOT_FOUND; + goto error; + } + break; + default: + ret = LTTCOMM_UNKNOWN_DOMAIN; + goto error; + } DBG("Creating UST session"); - lus = trace_ust_create_session(session->path, pid); + lus = trace_ust_create_session(session->path, domain->attr.pid, domain); if (lus == NULL) { + ret = LTTCOMM_UST_SESS_FAIL; goto error; } @@ -1578,17 +1673,22 @@ static int create_ust_session(pid_t pid, struct ltt_session *session) if (ret < 0) { if (ret != -EEXIST) { ERR("Trace directory creation error"); + ret = LTTCOMM_UST_SESS_FAIL; goto error; } } /* Create session on the UST tracer */ - ret = ustctl_create_session(lus); + ret = ustctl_create_session(app->sock, lus); if (ret < 0) { + ret = LTTCOMM_UST_SESS_FAIL; goto error; } - return 0; + cds_list_add(&lus->list, &session->ust_session_list.head); + session->ust_session_list.count++; + + return LTTCOMM_OK; error: free(lus); @@ -1611,8 +1711,8 @@ static int create_kernel_session(struct ltt_session *session) } /* Set kernel consumer socket fd */ - if (kconsumerd_cmd_sock) { - session->kernel_session->consumer_fd = kconsumerd_cmd_sock; + if (kconsumer_data.cmd_sock) { + session->kernel_session->consumer_fd = kconsumer_data.cmd_sock; } ret = mkdir_recursive(session->kernel_session->trace_path, @@ -1719,6 +1819,9 @@ static void list_lttng_events(struct ltt_kernel_channel *kchan, case LTTNG_KERNEL_SYSCALL: events[i].type = LTTNG_EVENT_SYSCALL; break; + case LTTNG_KERNEL_ALL: + assert(0); + break; } i++; } @@ -1742,9 +1845,10 @@ static int cmd_disable_channel(struct ltt_session *session, kernel_wait_quiescent(kernel_tracer_fd); break; + case LTTNG_DOMAIN_UST_PID: + break; default: - /* TODO: Userspace tracing */ - ret = LTTCOMM_NOT_IMPLEMENTED; + ret = LTTCOMM_UNKNOWN_DOMAIN; goto error; } @@ -1754,36 +1858,115 @@ error: return ret; } +/* + * Copy channel from attributes and set it in the application channel list. + */ +static int copy_ust_channel_to_app(struct ltt_ust_session *usess, + struct lttng_channel *attr, struct ust_app *app) +{ + int ret; + struct ltt_ust_channel *uchan, *new_chan; + + uchan = trace_ust_get_channel_by_name(attr->name, usess); + if (uchan == NULL) { + ret = LTTCOMM_FATAL; + goto error; + } + + new_chan = trace_ust_create_channel(attr, usess->path); + if (new_chan == NULL) { + PERROR("malloc ltt_ust_channel"); + ret = LTTCOMM_FATAL; + goto error; + } + + ret = channel_ust_copy(new_chan, uchan); + if (ret < 0) { + ret = LTTCOMM_FATAL; + goto error; + } + + /* Add channel to the ust app channel list */ + cds_list_add(&new_chan->list, &app->channels.head); + app->channels.count++; + +error: + return ret; +} + /* * Command LTTNG_ENABLE_CHANNEL processed by the client thread. */ -static int cmd_enable_channel(struct ltt_session *session, int domain, - char *channel_name, struct lttng_channel *attr) +static int cmd_enable_channel(struct ltt_session *session, + struct lttng_domain *domain, struct lttng_channel *attr) { int ret; - struct ltt_kernel_channel *kchan; - switch (domain) { - case LTTNG_DOMAIN_KERNEL: - kchan = trace_kernel_get_channel_by_name(channel_name, - session->kernel_session); - if (kchan == NULL) { - ret = channel_kernel_create(session->kernel_session, - channel_name, attr, kernel_poll_pipe[1]); - } else { - ret = channel_kernel_enable(session->kernel_session, kchan); - } + switch (domain->type) { + case LTTNG_DOMAIN_KERNEL: + { + struct ltt_kernel_channel *kchan; - if (ret != LTTCOMM_OK) { - goto error; - } + kchan = trace_kernel_get_channel_by_name(attr->name, + session->kernel_session); + if (kchan == NULL) { + ret = channel_kernel_create(session->kernel_session, + attr, kernel_poll_pipe[1]); + } else { + ret = channel_kernel_enable(session->kernel_session, kchan); + } - kernel_wait_quiescent(kernel_tracer_fd); - break; - default: - /* TODO: Userspace tracing */ - ret = LTTCOMM_NOT_IMPLEMENTED; + if (ret != LTTCOMM_OK) { goto error; + } + + kernel_wait_quiescent(kernel_tracer_fd); + break; + } + case LTTNG_DOMAIN_UST_PID: + { + int sock; + struct ltt_ust_channel *uchan; + struct ltt_ust_session *usess; + struct ust_app *app; + + usess = trace_ust_get_session_by_pid(&session->ust_session_list, + domain->attr.pid); + if (usess == NULL) { + ret = LTTCOMM_UST_CHAN_NOT_FOUND; + goto error; + } + + app = ust_app_get_by_pid(domain->attr.pid); + if (app == NULL) { + ret = LTTCOMM_APP_NOT_FOUND; + goto error; + } + sock = app->sock; + + uchan = trace_ust_get_channel_by_name(attr->name, usess); + if (uchan == NULL) { + ret = channel_ust_create(usess, attr, sock); + } else { + ret = channel_ust_enable(usess, uchan, sock); + } + + if (ret != LTTCOMM_OK) { + goto error; + } + + ret = copy_ust_channel_to_app(usess, attr, app); + if (ret != LTTCOMM_OK) { + goto error; + } + + DBG("UST channel %s created for app sock %d with pid %d", + attr->name, app->sock, domain->attr.pid); + break; + } + default: + ret = LTTCOMM_UNKNOWN_DOMAIN; + goto error; } ret = LTTCOMM_OK; @@ -1810,7 +1993,7 @@ static int cmd_disable_event(struct ltt_session *session, int domain, goto error; } - ret = event_kernel_disable(session->kernel_session, kchan, event_name); + ret = event_kernel_disable_tracepoint(session->kernel_session, kchan, event_name); if (ret != LTTCOMM_OK) { goto error; } @@ -1904,15 +2087,23 @@ static int cmd_enable_event(struct ltt_session *session, int domain, { int ret; struct ltt_kernel_channel *kchan; + struct lttng_channel *attr; switch (domain) { case LTTNG_DOMAIN_KERNEL: kchan = trace_kernel_get_channel_by_name(channel_name, session->kernel_session); if (kchan == NULL) { + attr = channel_new_default_attr(domain); + if (attr == NULL) { + ret = LTTCOMM_FATAL; + goto error; + } + snprintf(attr->name, NAME_MAX, "%s", channel_name); + /* This call will notify the kernel thread */ - ret = channel_kernel_create(session->kernel_session, channel_name, - NULL, kernel_poll_pipe[1]); + ret = channel_kernel_create(session->kernel_session, + attr, kernel_poll_pipe[1]); if (ret != LTTCOMM_OK) { goto error; } @@ -1927,7 +2118,7 @@ static int cmd_enable_event(struct ltt_session *session, int domain, goto error; } - ret = event_kernel_enable(session->kernel_session, kchan, event); + ret = event_kernel_enable_tracepoint(session->kernel_session, kchan, event); if (ret != LTTCOMM_OK) { goto error; } @@ -1961,8 +2152,8 @@ static int cmd_enable_event_all(struct ltt_session *session, int domain, session->kernel_session); if (kchan == NULL) { /* This call will notify the kernel thread */ - ret = channel_kernel_create(session->kernel_session, channel_name, - NULL, kernel_poll_pipe[1]); + ret = channel_kernel_create(session->kernel_session, NULL, + kernel_poll_pipe[1]); if (ret != LTTCOMM_OK) { goto error; } @@ -1977,18 +2168,28 @@ static int cmd_enable_event_all(struct ltt_session *session, int domain, goto error; } - if (event_type == LTTNG_KERNEL_SYSCALL) { - ret = event_kernel_enable_syscalls(session->kernel_session, + switch (event_type) { + case LTTNG_KERNEL_SYSCALL: + ret = event_kernel_enable_all_syscalls(session->kernel_session, kchan, kernel_tracer_fd); - } else { + break; + case LTTNG_KERNEL_TRACEPOINT: /* - * This call enables all LTTNG_KERNEL_TRACEPOINTS and events - * already registered to the channel. + * This call enables all LTTNG_KERNEL_TRACEPOINTS and + * events already registered to the channel. */ + ret = event_kernel_enable_all_tracepoints(session->kernel_session, + kchan, kernel_tracer_fd); + break; + case LTTNG_KERNEL_ALL: + /* Enable syscalls and tracepoints */ ret = event_kernel_enable_all(session->kernel_session, kchan, kernel_tracer_fd); + break; + default: + ret = LTTCOMM_KERN_ENABLE_FAIL; + goto error; } - if (ret != LTTCOMM_OK) { goto error; } @@ -2191,7 +2392,7 @@ static int cmd_destroy_session(struct ltt_session *session, char *name) perror("write kernel poll pipe"); } - ret = session_destroy(name); + ret = session_destroy(session); return ret; } @@ -2368,13 +2569,13 @@ error: static int process_client_msg(struct command_ctx *cmd_ctx) { int ret = LTTCOMM_OK; - int need_kernel_session = 1; + int need_tracing_session = 1; DBG("Processing client command %d", cmd_ctx->lsm->cmd_type); /* * Check for command that don't needs to allocate a returned payload. We do - * this here so we don't have to make the call for no payload" at each + * this here so we don't have to make the call for no payload at each * command. */ switch(cmd_ctx->lsm->cmd_type) { @@ -2399,11 +2600,13 @@ static int process_client_msg(struct command_ctx *cmd_ctx) case LTTNG_CREATE_SESSION: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_TRACEPOINTS: - need_kernel_session = 0; + need_tracing_session = 0; break; default: DBG("Getting session %s by name", cmd_ctx->lsm->session.name); + session_lock_list(); cmd_ctx->session = session_find_by_name(cmd_ctx->lsm->session.name); + session_unlock_list(); if (cmd_ctx->session == NULL) { if (cmd_ctx->lsm->session.name != NULL) { ret = LTTCOMM_SESS_NOT_FOUND; @@ -2435,7 +2638,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } /* Need a session for kernel command */ - if (need_kernel_session) { + if (need_tracing_session) { if (cmd_ctx->session->kernel_session == NULL) { ret = create_kernel_session(cmd_ctx->session); if (ret < 0) { @@ -2445,16 +2648,37 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } /* Start the kernel consumer daemon */ - if (kconsumerd_pid == 0 && + pthread_mutex_lock(&kconsumer_data.pid_mutex); + if (kconsumer_data.pid == 0 && cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) { - ret = start_kconsumerd(); + pthread_mutex_unlock(&kconsumer_data.pid_mutex); + ret = start_consumerd(&kconsumer_data); if (ret < 0) { ret = LTTCOMM_KERN_CONSUMER_FAIL; goto error; } } + pthread_mutex_unlock(&kconsumer_data.pid_mutex); } break; + case LTTNG_DOMAIN_UST_PID: + { + struct ltt_ust_session *usess; + + if (need_tracing_session) { + usess = trace_ust_get_session_by_pid( + &cmd_ctx->session->ust_session_list, + cmd_ctx->lsm->domain.attr.pid); + if (usess == NULL) { + ret = create_ust_session(cmd_ctx->session, + &cmd_ctx->lsm->domain); + if (ret != LTTCOMM_OK) { + goto error; + } + } + } + break; + } default: /* TODO Userspace tracer */ break; @@ -2494,8 +2718,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } case LTTNG_ENABLE_CHANNEL: { - ret = cmd_enable_channel(cmd_ctx->session, cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.enable.channel_name, + ret = cmd_enable_channel(cmd_ctx->session, &cmd_ctx->lsm->domain, &cmd_ctx->lsm->u.channel.chan); break; } @@ -2834,7 +3057,7 @@ static void *thread_manage_clients(void *data) DBG("Sending response (size: %d, retcode: %s)", cmd_ctx->lttng_msg_size, - lttng_get_readable_code(-cmd_ctx->llm->ret_code)); + lttng_strerror(-cmd_ctx->llm->ret_code)); ret = send_unix_sock(sock, cmd_ctx->llm, cmd_ctx->lttng_msg_size); if (ret < 0) { ERR("Failed to send data back to client"); @@ -2869,13 +3092,15 @@ static void usage(void) fprintf(stderr, " -a, --apps-sock PATH Specify path for apps unix socket\n"); fprintf(stderr, " --kconsumerd-err-sock PATH Specify path for the kernel consumer error socket\n"); fprintf(stderr, " --kconsumerd-cmd-sock PATH Specify path for the kernel consumer command socket\n"); + fprintf(stderr, " --ustconsumerd-err-sock PATH Specify path for the UST consumer error socket\n"); + fprintf(stderr, " --ustconsumerd-cmd-sock PATH Specify path for the UST consumer command socket\n"); fprintf(stderr, " -d, --daemonize Start as a daemon.\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, " -q, --quiet No output at all.\n"); fprintf(stderr, " -v, --verbose Verbose mode. Activate DBG() macro.\n"); - fprintf(stderr, " --verbose-kconsumerd Verbose mode for kconsumerd. Activate DBG() macro.\n"); + fprintf(stderr, " --verbose-consumer Verbose mode for consumer. Activate DBG() macro.\n"); } /* @@ -2888,8 +3113,10 @@ static int parse_args(int argc, char **argv) static struct option long_options[] = { { "client-sock", 1, 0, 'c' }, { "apps-sock", 1, 0, 'a' }, - { "kconsumerd-cmd-sock", 1, 0, 0 }, - { "kconsumerd-err-sock", 1, 0, 0 }, + { "kconsumerd-cmd-sock", 1, 0, 'C' }, + { "kconsumerd-err-sock", 1, 0, 'E' }, + { "ustconsumerd-cmd-sock", 1, 0, 'D' }, + { "ustconsumerd-err-sock", 1, 0, 'F' }, { "daemonize", 0, 0, 'd' }, { "sig-parent", 0, 0, 'S' }, { "help", 0, 0, 'h' }, @@ -2897,13 +3124,13 @@ static int parse_args(int argc, char **argv) { "version", 0, 0, 'V' }, { "quiet", 0, 0, 'q' }, { "verbose", 0, 0, 'v' }, - { "verbose-kconsumerd", 0, 0, 'Z' }, + { "verbose-consumer", 0, 0, 'Z' }, { NULL, 0, 0, 0 } }; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "dhqvVS" "a:c:g:s:E:C:Z", + c = getopt_long(argc, argv, "dhqvVS" "a:c:g:s:C:E:D:F:Z", long_options, &option_index); if (c == -1) { break; @@ -2938,10 +3165,16 @@ static int parse_args(int argc, char **argv) opt_sig_parent = 1; break; case 'E': - snprintf(kconsumerd_err_unix_sock_path, PATH_MAX, "%s", optarg); + snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", optarg); break; case 'C': - snprintf(kconsumerd_cmd_unix_sock_path, PATH_MAX, "%s", optarg); + snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", optarg); + break; + case 'F': + snprintf(ustconsumer_data.err_unix_sock_path, PATH_MAX, "%s", optarg); + break; + case 'D': + snprintf(ustconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", optarg); break; case 'q': opt_quiet = 1; @@ -2951,7 +3184,7 @@ static int parse_args(int argc, char **argv) opt_verbose += 1; break; case 'Z': - opt_verbose_kconsumerd += 1; + opt_verbose_consumer += 1; break; default: /* Unknown option or other error. @@ -3069,10 +3302,17 @@ static int set_permissions(void) perror("chown"); } - /* kconsumerd error socket path */ - ret = chown(kconsumerd_err_unix_sock_path, 0, gid); + /* kconsumer error socket path */ + ret = chown(kconsumer_data.err_unix_sock_path, 0, gid); + if (ret < 0) { + ERR("Unable to set group on %s", kconsumer_data.err_unix_sock_path); + perror("chown"); + } + + /* ustconsumer error socket path */ + ret = chown(ustconsumer_data.err_unix_sock_path, 0, gid); if (ret < 0) { - ERR("Unable to set group on %s", kconsumerd_err_unix_sock_path); + ERR("Unable to set group on %s", ustconsumer_data.err_unix_sock_path); perror("chown"); } @@ -3123,43 +3363,49 @@ error: * Setup sockets and directory needed by the kconsumerd communication with the * session daemon. */ -static int set_kconsumerd_sockets(void) +static int set_consumer_sockets(struct consumer_data *consumer_data) { int ret; + const char *path = consumer_data->type == LTTNG_CONSUMER_KERNEL ? + KCONSUMERD_PATH : USTCONSUMERD_PATH; - if (strlen(kconsumerd_err_unix_sock_path) == 0) { - snprintf(kconsumerd_err_unix_sock_path, PATH_MAX, - KCONSUMERD_ERR_SOCK_PATH); + if (strlen(consumer_data->err_unix_sock_path) == 0) { + snprintf(consumer_data->err_unix_sock_path, PATH_MAX, + consumer_data->type == LTTNG_CONSUMER_KERNEL ? + KCONSUMERD_ERR_SOCK_PATH : + USTCONSUMERD_ERR_SOCK_PATH); } - if (strlen(kconsumerd_cmd_unix_sock_path) == 0) { - snprintf(kconsumerd_cmd_unix_sock_path, PATH_MAX, - KCONSUMERD_CMD_SOCK_PATH); + if (strlen(consumer_data->cmd_unix_sock_path) == 0) { + snprintf(consumer_data->cmd_unix_sock_path, PATH_MAX, + consumer_data->type == LTTNG_CONSUMER_KERNEL ? + KCONSUMERD_CMD_SOCK_PATH : + USTCONSUMERD_CMD_SOCK_PATH); } - ret = mkdir(KCONSUMERD_PATH, S_IRWXU | S_IRWXG); + ret = mkdir(path, S_IRWXU | S_IRWXG); if (ret < 0) { if (errno != EEXIST) { - ERR("Failed to create " KCONSUMERD_PATH); + ERR("Failed to create %s", path); goto error; } ret = 0; } /* Create the kconsumerd error unix socket */ - kconsumerd_err_sock = - lttcomm_create_unix_sock(kconsumerd_err_unix_sock_path); - if (kconsumerd_err_sock < 0) { - ERR("Create unix sock failed: %s", kconsumerd_err_unix_sock_path); + consumer_data->err_sock = + lttcomm_create_unix_sock(consumer_data->err_unix_sock_path); + if (consumer_data->err_sock < 0) { + ERR("Create unix sock failed: %s", consumer_data->err_unix_sock_path); ret = -1; goto error; } /* File permission MUST be 660 */ - ret = chmod(kconsumerd_err_unix_sock_path, + ret = chmod(consumer_data->err_unix_sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (ret < 0) { - ERR("Set file permissions failed: %s", kconsumerd_err_unix_sock_path); + ERR("Set file permissions failed: %s", consumer_data->err_unix_sock_path); perror("chmod"); goto error; } @@ -3354,11 +3600,14 @@ int main(int argc, char **argv) * kernel tracer. */ if (is_root) { - ret = set_kconsumerd_sockets(); + ret = set_consumer_sockets(&kconsumer_data); + if (ret < 0) { + goto exit; + } + ret = set_consumer_sockets(&ustconsumer_data); if (ret < 0) { goto exit; } - /* Setup kernel tracer */ init_kernel_tracer(); @@ -3481,9 +3730,9 @@ exit_dispatch: goto error; /* join error, exit without cleanup */ } - ret = join_kconsumerd_thread(); + ret = join_consumer_thread(&kconsumer_data); if (ret != 0) { - perror("join_kconsumerd"); + perror("join_consumer"); goto error; /* join error, exit without cleanup */ }