X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=ltt-sessiond%2Fmain.c;h=c288afbb049f4a078f049756fce9c20094f1d705;hp=867ba4188e37419c2f419429248126c97143bae8;hb=9674ce7a9c5218066b395d1f6d1f19f277849f95;hpb=684d34d2e47cf8ad4039fa9b3170a122b6dd9faa diff --git a/ltt-sessiond/main.c b/ltt-sessiond/main.c index 867ba4188..c288afbb0 100644 --- a/ltt-sessiond/main.c +++ b/ltt-sessiond/main.c @@ -36,10 +36,19 @@ #include #include #include +#include -#include +#include #include -#include +#include + +#ifdef CONFIG_LTTNG_TOOLS_HAVE_UST +#include +#else +#include "lttng-ust-ctl.h" +#endif + + #include #include "channel.h" @@ -50,11 +59,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 +90,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 +99,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 +136,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 +294,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 +369,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 +421,129 @@ 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_kconsumer_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; + /* 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.channel.channel_key); + ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm)); + if (ret < 0) { + perror("send consumer channel"); + goto error; + } + + /* Send streams */ + cds_list_for_each_entry(stream, &channel->stream_list.head, list) { + 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("consumer channel streams sent"); + + return 0; + +error: + return ret; +} - /* Setup header */ - lkh.payload_size = nb_fd * sizeof(struct lttcomm_kconsumerd_msg); - lkh.cmd_type = ADD_STREAM; +/* + * Send all stream fds of UST channel to the consumer. + */ +static int send_ustconsumer_channel_streams(struct consumer_data *consumer_data, + int sock, struct ltt_ust_channel *channel) +{ + int ret, fds[2]; + struct ltt_ust_stream *stream; + struct lttcomm_consumer_msg lum; - DBG("Sending kconsumerd header"); + DBG("Sending streams of channel %s to UST consumer", + channel->name); - ret = lttcomm_send_unix_sock(sock, &lkh, - sizeof(struct lttcomm_kconsumerd_header)); + /* Send channel */ + lum.cmd_type = LTTNG_CONSUMER_ADD_CHANNEL; + /* + * We need to keep shm_fd open to make sure this key stays + * unique within the session daemon. + */ + lum.u.channel.channel_key = channel->obj->shm_fd; + lum.u.channel.max_sb_size = channel->attr.subbuf_size; + lum.u.channel.mmap_len = channel->obj->memory_map_size; + DBG("Sending channel %d to consumer", lum.u.channel.channel_key); + ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum)); + if (ret < 0) { + perror("send consumer channel"); + goto error; + } + fds[0] = channel->obj->shm_fd; + fds[1] = channel->obj->wait_fd; + ret = lttcomm_send_fds_unix_sock(sock, fds, 2); if (ret < 0) { - perror("send kconsumerd header"); + perror("send consumer channel ancillary data"); 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; - } + int fds[2]; + + if (!stream->obj->shm_fd) { + continue; + } + lum.cmd_type = LTTNG_CONSUMER_ADD_STREAM; + lum.u.stream.channel_key = channel->obj->shm_fd; + lum.u.stream.stream_key = stream->obj->shm_fd; + lum.u.stream.state = LTTNG_CONSUMER_ACTIVE_STREAM; + lum.u.stream.output = channel->attr.output; + lum.u.stream.mmap_len = stream->obj->memory_map_size; + strncpy(lum.u.stream.path_name, stream->pathname, PATH_MAX - 1); + lum.u.stream.path_name[PATH_MAX - 1] = '\0'; + DBG("Sending stream %d to consumer", lum.u.stream.stream_key); + ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum)); + if (ret < 0) { + perror("send consumer stream"); + goto error; + } + fds[0] = stream->obj->shm_fd; + fds[1] = stream->obj->wait_fd; + ret = lttcomm_send_fds_unix_sock(sock, fds, 2); + 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 +554,143 @@ 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_kconsumer_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; + struct lttcomm_consumer_msg lkm; + int sock = session->consumer_fd; - /* Setup header */ - lkh.payload_size = sizeof(struct lttcomm_kconsumerd_msg); - lkh.cmd_type = ADD_STREAM; + DBG("Sending metadata stream fd"); - DBG("Sending kconsumerd header for metadata"); + /* Extra protection. It's NOT supposed to be set to 0 at this point */ + if (session->consumer_fd == 0) { + session->consumer_fd = consumer_data->cmd_sock; + } - ret = lttcomm_send_unix_sock(session->consumer_fd, &lkh, - sizeof(struct lttcomm_kconsumerd_header)); - if (ret < 0) { - perror("send kconsumerd header"); - goto error; + if (session->metadata_stream_fd != 0) { + /* 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 consumer stream"); + goto error; + } } + cds_list_for_each_entry(chan, &session->channel_list.head, list) { + ret = send_kconsumer_channel_streams(consumer_data, sock, chan); + if (ret < 0) { + goto error; + } + } + + DBG("consumer fds (metadata and channel streams) sent"); + + return 0; + +error: + return ret; +} + +/* + * Send all stream fds of the UST session to the consumer. + */ +static int send_ustconsumer_session_streams(struct consumer_data *consumer_data, + struct ltt_ust_session *session) +{ + int ret; + struct ltt_ust_channel *chan; + struct lttcomm_consumer_msg lum; + int sock = session->consumer_fd; + DBG("Sending metadata stream fd"); - /* Extra protection. It's NOT suppose to be set to 0 at this point */ + /* Extra protection. It's NOT supposed 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)); + if (session->metadata->obj->shm_fd != 0) { + int fds[2]; + + /* Send metadata channel fd */ + lum.cmd_type = LTTNG_CONSUMER_ADD_CHANNEL; + lum.u.channel.channel_key = session->metadata->obj->shm_fd; + lum.u.channel.max_sb_size = session->metadata->attr.subbuf_size; + lum.u.channel.mmap_len = 0; /* for kernel */ + DBG("Sending metadata channel %d to consumer", lum.u.stream.stream_key); + ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum)); + if (ret < 0) { + perror("send consumer channel"); + goto error; + } + fds[0] = session->metadata->obj->shm_fd; + fds[1] = session->metadata->obj->wait_fd; + ret = lttcomm_send_fds_unix_sock(sock, fds, 2); + if (ret < 0) { + perror("send consumer metadata channel"); + goto error; + } + + /* Send metadata stream fd */ + lum.cmd_type = LTTNG_CONSUMER_ADD_STREAM; + lum.u.stream.channel_key = session->metadata->obj->shm_fd; + lum.u.stream.stream_key = session->metadata->stream_obj->shm_fd; + lum.u.stream.state = LTTNG_CONSUMER_ACTIVE_STREAM; + lum.u.stream.output = DEFAULT_UST_CHANNEL_OUTPUT; + lum.u.stream.mmap_len = session->metadata->stream_obj->memory_map_size; + strncpy(lum.u.stream.path_name, session->metadata->pathname, PATH_MAX - 1); + lum.u.stream.path_name[PATH_MAX - 1] = '\0'; + DBG("Sending metadata stream %d to consumer", lum.u.stream.stream_key); + ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum)); if (ret < 0) { - perror("send kconsumerd fd"); + perror("send consumer metadata stream"); + goto error; + } + fds[0] = session->metadata->stream_obj->shm_fd; + fds[1] = session->metadata->stream_obj->wait_fd; + ret = lttcomm_send_fds_unix_sock(sock, fds, 2); + if (ret < 0) { + 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); + cds_list_for_each_entry(chan, &session->channels.head, list) { + ret = send_ustconsumer_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 +803,7 @@ error: * * Useful for CPU hotplug feature. */ -static int update_kernel_stream(int fd) +static int update_kernel_stream(struct consumer_data *consumer_data, int fd) { int ret = 0; struct ltt_session *session; @@ -636,7 +821,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 +838,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_kconsumer_channel_streams(consumer_data, session->kernel_session->consumer_fd, channel); if (ret < 0) { goto error; @@ -701,6 +886,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 +939,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_kernel_stream(&kconsumer_data, pollfd); if (ret < 0) { continue; } @@ -773,18 +964,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 +990,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 +1015,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 +1037,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 +1088,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 +1098,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 +1180,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 +1193,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 +1222,7 @@ static void *thread_manage_apps(void *data) } /* Socket closed */ - unregister_traceable_app(pollfd); + ust_app_unregister(pollfd); break; } } @@ -1065,7 +1259,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 +1445,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 (kconsumerd_pid == 0) { + 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; + } + + 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); - - DBG("Kconsumerd pid %d", ret); + /* 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("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 +1668,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 +1724,7 @@ static void init_kernel_tracer(void) } ret = mount_debugfs(debugfs_path); if (ret < 0) { + perror("Cannot mount debugfs"); goto error; } } @@ -1535,23 +1773,53 @@ 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_kconsumer_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: + return ret; +} + +/* + * Init tracing by creating trace directory and sending fds ust consumer. + */ +static int init_ust_tracing(struct ltt_ust_session *session) +{ + int ret = 0; + + if (session->consumer_fds_sent == 0) { + /* + * Assign default ust consumer socket if no consumer assigned to the + * ust 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 = ustconsumer_data.cmd_sock; + } + + ret = send_ustconsumer_session_streams(&ustconsumer_data, session); + if (ret < 0) { + ret = LTTCOMM_UST_CONSUMER_FAIL; + goto error; + } + + session->consumer_fds_sent = 1; } error: @@ -1561,15 +1829,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 +1862,24 @@ 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); if (ret < 0) { + ret = LTTCOMM_UST_SESS_FAIL; goto error; } + lus->handle = ret; + lus->sock = app->sock; - 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 +1902,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 +2010,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 +2036,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 +2049,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; @@ -1799,10 +2173,12 @@ static int cmd_disable_event(struct ltt_session *session, int domain, char *channel_name, char *event_name) { int ret; - struct ltt_kernel_channel *kchan; switch (domain) { case LTTNG_DOMAIN_KERNEL: + { + struct ltt_kernel_channel *kchan; + kchan = trace_kernel_get_channel_by_name(channel_name, session->kernel_session); if (kchan == NULL) { @@ -1810,15 +2186,41 @@ 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; } kernel_wait_quiescent(kernel_tracer_fd); break; + } + case LTTNG_DOMAIN_UST: + { + struct ltt_ust_session *ustsession; + + cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) { + struct ltt_ust_channel *ustchan; + + ustchan = trace_ust_get_channel_by_name(channel_name, + ustsession); + if (ustchan == NULL) { + ret = LTTCOMM_KERN_CHAN_NOT_FOUND; + goto error; + } + ret = event_ust_disable_tracepoint(ustsession, ustchan, event_name); + if (ret != LTTCOMM_OK) { + goto error; + } + + ustctl_wait_quiescent(ustsession->sock); + } + break; + } + case LTTNG_DOMAIN_UST_EXEC_NAME: + case LTTNG_DOMAIN_UST_PID: + case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: default: - /* TODO: Userspace tracing */ + /* TODO: Other UST domains */ ret = LTTCOMM_NOT_IMPLEMENTED; goto error; } @@ -1882,10 +2284,23 @@ static int cmd_add_context(struct ltt_session *session, int domain, if (ret != LTTCOMM_OK) { goto error; } + break; + case LTTNG_DOMAIN_UST: + { + struct ltt_ust_session *ustsession; + cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) { + /* Add UST context to UST tracer */ + ret = context_ust_add(ustsession, ctx, + event_name, channel_name); + if (ret != LTTCOMM_OK) { + goto error; + } + } break; + } default: - /* TODO: Userspace tracing */ + /* TODO: UST other domains */ ret = LTTCOMM_NOT_IMPLEMENTED; goto error; } @@ -1903,16 +2318,26 @@ static int cmd_enable_event(struct ltt_session *session, int domain, char *channel_name, struct lttng_event *event) { int ret; - struct ltt_kernel_channel *kchan; + struct lttng_channel *attr; switch (domain) { case LTTNG_DOMAIN_KERNEL: + { + struct ltt_kernel_channel *kchan; + 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,15 +2352,61 @@ 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; } kernel_wait_quiescent(kernel_tracer_fd); break; + } + case LTTNG_DOMAIN_UST: + { + struct ltt_ust_session *ustsession; + + cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) { + struct ltt_ust_channel *ustchan; + + ustchan = trace_ust_get_channel_by_name(channel_name, + ustsession); + if (ustchan == NULL) { + attr = channel_new_default_attr(domain); + if (attr == NULL) { + ret = LTTCOMM_FATAL; + goto error; + } + snprintf(attr->name, NAME_MAX, "%s", channel_name); + + ret = channel_ust_create(ustsession, + attr, ustsession->sock); + if (ret != LTTCOMM_OK) { + goto error; + } + } + + /* Get the newly created ust channel pointer */ + ustchan = trace_ust_get_channel_by_name(channel_name, + ustsession); + if (ustchan == NULL) { + /* This sould not happen... */ + ret = LTTCOMM_FATAL; + goto error; + } + + ret = event_ust_enable_tracepoint(ustsession, ustchan, event); + if (ret != LTTCOMM_OK) { + goto error; + } + + ustctl_wait_quiescent(ustsession->sock); + } + break; + } + case LTTNG_DOMAIN_UST_EXEC_NAME: + case LTTNG_DOMAIN_UST_PID: + case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: default: - /* TODO: Userspace tracing */ + /* TODO: UST other domains */ ret = LTTCOMM_NOT_IMPLEMENTED; goto error; } @@ -1950,7 +2421,7 @@ error: * Command LTTNG_ENABLE_ALL_EVENT processed by the client thread. */ static int cmd_enable_event_all(struct ltt_session *session, int domain, - char *channel_name) + char *channel_name, int event_type) { int ret; struct ltt_kernel_channel *kchan; @@ -1961,8 +2432,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,8 +2448,28 @@ static int cmd_enable_event_all(struct ltt_session *session, int domain, goto error; } - ret = event_kernel_enable_all(session->kernel_session, - kchan, kernel_tracer_fd); + switch (event_type) { + case LTTNG_KERNEL_SYSCALL: + ret = event_kernel_enable_all_syscalls(session->kernel_session, + kchan, kernel_tracer_fd); + break; + case LTTNG_KERNEL_TRACEPOINT: + /* + * 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; } @@ -2032,14 +2523,16 @@ error: static int cmd_start_trace(struct ltt_session *session) { int ret; - struct ltt_kernel_channel *kchan; struct ltt_kernel_session *ksession; + struct ltt_ust_session *ustsession; /* Short cut */ ksession = session->kernel_session; /* Kernel tracing */ if (ksession != NULL) { + struct ltt_kernel_channel *kchan; + /* Open kernel metadata */ if (ksession->metadata == NULL) { ret = kernel_open_metadata(ksession, ksession->trace_path); @@ -2090,7 +2583,101 @@ static int cmd_start_trace(struct ltt_session *session) kernel_wait_quiescent(kernel_tracer_fd); } - /* TODO: Start all UST traces */ + /* Start all UST traces */ + cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) { + struct ltt_ust_channel *ustchan; + + /* Open kernel metadata */ + if (ustsession->metadata == NULL) { + struct lttng_ust_channel_attr ustattr; + + /* Allocate UST metadata */ + ustsession->metadata = trace_ust_create_metadata(ustsession->path); + if (ustsession->metadata == NULL) { + ret = LTTCOMM_UST_META_FAIL; + goto error; + } + + ustattr.overwrite = ustsession->metadata->attr.overwrite; + ustattr.subbuf_size = ustsession->metadata->attr.subbuf_size; + ustattr.num_subbuf = ustsession->metadata->attr.num_subbuf; + ustattr.switch_timer_interval = ustsession->metadata->attr.switch_timer_interval; + ustattr.read_timer_interval = ustsession->metadata->attr.read_timer_interval; + ustattr.output = ustsession->metadata->attr.output; + + /* UST tracer metadata creation */ + ret = ustctl_open_metadata(ustsession->sock, + ustsession->handle, &ustattr, + &ustsession->metadata->obj); + if (ret < 0) { + ret = LTTCOMM_UST_META_FAIL; + goto error; + } + } + + /* Open UST metadata stream */ + if (ustsession->metadata->stream_obj == NULL) { + ret = ustctl_create_stream(ustsession->sock, + ustsession->metadata->obj, + &ustsession->metadata->stream_obj); + if (ret < 0) { + ERR("UST create metadata stream failed"); + ret = LTTCOMM_UST_STREAM_FAIL; + goto error; + } + ret = asprintf(&ustsession->metadata->pathname, "%s/%s", + ustsession->path, "metadata"); + if (ret < 0) { + perror("asprintf UST create stream"); + goto error; + } + } + + /* For each channel */ + cds_list_for_each_entry(ustchan, &ustsession->channels.head, list) { + if (ustchan->stream_count == 0) { + struct ltt_ust_stream *ustream; + + ustream = zmalloc(sizeof(*ustream)); + if (!ustream) { + ret = LTTCOMM_UST_STREAM_FAIL; + goto error; + } + ret = ustctl_create_stream(ustsession->sock, + ustchan->obj, &ustream->obj); + if (ret < 0) { + ret = LTTCOMM_UST_STREAM_FAIL; + goto error; + } + ret = asprintf(&ustream->pathname, "%s/%s_%d", + ustchan->trace_path, ustchan->name, + ustchan->stream_count); + if (ret < 0) { + perror("asprintf UST create stream"); + goto error; + } + cds_list_add(&ustream->list, &ustchan->stream_list.head); + ustchan->stream_count++; + } + } + + /* Setup UST consumer socket and send fds to it */ + ret = init_ust_tracing(ustsession); + if (ret < 0) { + ret = LTTCOMM_UST_START_FAIL; + goto error; + } + + /* This start the UST tracing */ + ret = ustctl_start_session(ustsession->sock, ustsession->handle); + if (ret < 0) { + ret = LTTCOMM_UST_START_FAIL; + goto error; + } + + /* Quiescent wait after starting trace */ + ustctl_wait_quiescent(ustsession->sock); + } ret = LTTCOMM_OK; @@ -2106,6 +2693,8 @@ static int cmd_stop_trace(struct ltt_session *session) int ret; struct ltt_kernel_channel *kchan; struct ltt_kernel_session *ksession; + struct ltt_ust_session *ustsession; + struct ltt_ust_channel *ustchan; /* Short cut */ ksession = session->kernel_session; @@ -2136,7 +2725,30 @@ static int cmd_stop_trace(struct ltt_session *session) kernel_wait_quiescent(kernel_tracer_fd); } - /* TODO : User-space tracer */ + /* Stop each UST session */ + DBG("Stop UST tracing"); + cds_list_for_each_entry(ustsession, &session->ust_session_list.head, list) { + /* Flush all buffers before stopping */ + ret = ustctl_flush_buffer(ustsession->sock, ustsession->metadata->obj); + if (ret < 0) { + ERR("UST metadata flush failed"); + } + + cds_list_for_each_entry(ustchan, &ustsession->channels.head, list) { + ret = ustctl_flush_buffer(ustsession->sock, ustchan->obj); + if (ret < 0) { + ERR("UST flush buffer error"); + } + } + + ret = ustctl_stop_session(ustsession->sock, ustsession->handle); + if (ret < 0) { + ret = LTTCOMM_KERN_STOP_FAIL; + goto error; + } + + ustctl_wait_quiescent(ustsession->sock); + } ret = LTTCOMM_OK; @@ -2181,7 +2793,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; } @@ -2306,6 +2918,8 @@ static ssize_t cmd_list_channels(struct ltt_session *session, list_lttng_channels(session, *channels); + /* TODO UST support */ + return nb_chan; error: @@ -2358,13 +2972,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) { @@ -2389,11 +3003,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; @@ -2425,7 +3041,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) { @@ -2435,18 +3051,53 @@ 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: + case LTTNG_DOMAIN_UST_EXEC_NAME: + case LTTNG_DOMAIN_UST_PID: + case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: + { + 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; + } + } + /* Start the kernel consumer daemon */ + pthread_mutex_lock(&ustconsumer_data.pid_mutex); + if (ustconsumer_data.pid == 0 && + cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) { + pthread_mutex_unlock(&ustconsumer_data.pid_mutex); + ret = start_consumerd(&ustconsumer_data); + if (ret < 0) { + ret = LTTCOMM_KERN_CONSUMER_FAIL; + goto error; + } + } + pthread_mutex_unlock(&ustconsumer_data.pid_mutex); + } + break; + } default: - /* TODO Userspace tracer */ break; } @@ -2476,7 +3127,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } case LTTNG_DISABLE_ALL_EVENT: { - DBG("Disabling all kernel event"); + DBG("Disabling all events"); ret = cmd_disable_event_all(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.disable.channel_name); @@ -2484,8 +3135,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; } @@ -2498,10 +3148,11 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } case LTTNG_ENABLE_ALL_EVENT: { - DBG("Enabling all kernel event"); + DBG("Enabling all events"); 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.channel_name, + cmd_ctx->lsm->u.enable.event.type); break; } case LTTNG_LIST_TRACEPOINTS: @@ -2823,7 +3474,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"); @@ -2858,13 +3509,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"); } /* @@ -2877,8 +3530,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' }, @@ -2886,13 +3541,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; @@ -2927,10 +3582,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; @@ -2940,7 +3601,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. @@ -3058,10 +3719,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", kconsumerd_err_unix_sock_path); + 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", ustconsumer_data.err_unix_sock_path); perror("chown"); } @@ -3112,43 +3780,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; } @@ -3343,11 +4017,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(); @@ -3470,9 +4147,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 */ }