+ /* Quiescent wait after starting trace */
+ kernel_wait_quiescent(kernel_tracer_fd);
+ }
+
+ /* 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;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_STOP_TRACE processed by the client thread.
+ */
+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;
+
+ /* Kernel tracer */
+ if (ksession != NULL) {
+ DBG("Stop kernel tracing");
+
+ /* Flush all buffers before stopping */
+ ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd);
+ if (ret < 0) {
+ ERR("Kernel metadata flush failed");
+ }
+
+ cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
+ ret = kernel_flush_buffer(kchan);
+ if (ret < 0) {
+ ERR("Kernel flush buffer error");
+ }
+ }
+
+ ret = kernel_stop_session(ksession);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_STOP_FAIL;
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ }
+
+ /* 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;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_CREATE_SESSION processed by the client thread.
+ */
+static int cmd_create_session(char *name, char *path)
+{
+ int ret;
+
+ ret = session_create(name, path);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_DESTROY_SESSION processed by the client thread.
+ */
+static int cmd_destroy_session(struct ltt_session *session, char *name)
+{
+ int ret;
+
+ /* Clean kernel session teardown */
+ teardown_kernel_session(session);
+
+ /*
+ * Must notify the kernel thread here to update it's poll setin order
+ * to remove the channel(s)' fd just destroyed.
+ */
+ ret = notify_thread_pipe(kernel_poll_pipe[1]);
+ if (ret < 0) {
+ perror("write kernel poll pipe");
+ }
+
+ ret = session_destroy(session);
+
+ return ret;
+}
+
+/*
+ * Command LTTNG_CALIBRATE processed by the client thread.
+ */
+static int cmd_calibrate(int domain, struct lttng_calibrate *calibrate)
+{
+ int ret;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ {
+ struct lttng_kernel_calibrate kcalibrate;
+
+ kcalibrate.type = calibrate->type;
+ ret = kernel_calibrate(kernel_tracer_fd, &kcalibrate);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_ENABLE_FAIL;
+ goto error;
+ }
+ break;
+ }
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_REGISTER_CONSUMER processed by the client thread.
+ */
+static int cmd_register_consumer(struct ltt_session *session, int domain,
+ char *sock_path)
+{
+ int ret, sock;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ /* Can't register a consumer if there is already one */
+ if (session->kernel_session->consumer_fd != 0) {
+ ret = LTTCOMM_KERN_CONSUMER_FAIL;
+ goto error;
+ }
+
+ sock = lttcomm_connect_unix_sock(sock_path);
+ if (sock < 0) {
+ ret = LTTCOMM_CONNECT_FAIL;
+ goto error;
+ }
+
+ session->kernel_session->consumer_fd = sock;
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_DOMAINS processed by the client thread.
+ */
+static ssize_t cmd_list_domains(struct ltt_session *session,
+ struct lttng_domain **domains)
+{
+ int ret;
+ ssize_t nb_dom = 0;
+
+ if (session->kernel_session != NULL) {
+ nb_dom++;
+ }
+
+ /* TODO: User-space tracer domain support */
+
+ *domains = malloc(nb_dom * sizeof(struct lttng_domain));
+ if (*domains == NULL) {
+ ret = -LTTCOMM_FATAL;
+ goto error;
+ }
+
+ (*domains)[0].type = LTTNG_DOMAIN_KERNEL;
+
+ return nb_dom;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_CHANNELS processed by the client thread.
+ */
+static ssize_t cmd_list_channels(struct ltt_session *session,
+ struct lttng_channel **channels)
+{
+ int ret;
+ ssize_t nb_chan = 0;
+
+ if (session->kernel_session != NULL) {
+ nb_chan += session->kernel_session->channel_count;
+ }
+
+ *channels = malloc(nb_chan * sizeof(struct lttng_channel));
+ if (*channels == NULL) {
+ ret = -LTTCOMM_FATAL;
+ goto error;
+ }
+
+ list_lttng_channels(session, *channels);
+
+ /* TODO UST support */
+
+ return nb_chan;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_EVENTS processed by the client thread.
+ */
+static ssize_t cmd_list_events(struct ltt_session *session,
+ char *channel_name, struct lttng_event **events)
+{
+ int ret;
+ ssize_t nb_event = 0;
+ struct ltt_kernel_channel *kchan = NULL;
+
+ if (session->kernel_session != NULL) {
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ ret = -LTTCOMM_KERN_CHAN_NOT_FOUND;
+ goto error;
+ }
+ nb_event += kchan->event_count;
+ }
+
+ *events = malloc(nb_event * sizeof(struct lttng_event));
+ if (*events == NULL) {
+ ret = -LTTCOMM_FATAL;
+ goto error;
+ }
+
+ list_lttng_events(kchan, *events);
+
+ /* TODO: User-space tracer support */
+
+ return nb_event;
+
+error:
+ return ret;
+}
+
+/*
+ * Process the command requested by the lttng client within the command
+ * context structure. This function make sure that the return structure (llm)
+ * is set and ready for transmission before returning.
+ *
+ * Return any error encountered or 0 for success.
+ */
+static int process_client_msg(struct command_ctx *cmd_ctx)
+{
+ int ret = LTTCOMM_OK;
+ 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
+ * command.
+ */
+ switch(cmd_ctx->lsm->cmd_type) {
+ case LTTNG_LIST_SESSIONS:
+ case LTTNG_LIST_TRACEPOINTS:
+ case LTTNG_LIST_DOMAINS:
+ case LTTNG_LIST_CHANNELS:
+ case LTTNG_LIST_EVENTS:
+ break;
+ default:
+ /* Setup lttng message with no payload */
+ ret = setup_lttng_msg(cmd_ctx, 0);
+ if (ret < 0) {
+ /* This label does not try to unlock the session */
+ goto init_setup_error;
+ }
+ }
+
+ /* Commands that DO NOT need a session. */
+ switch (cmd_ctx->lsm->cmd_type) {
+ case LTTNG_CALIBRATE:
+ case LTTNG_CREATE_SESSION:
+ case LTTNG_LIST_SESSIONS:
+ case LTTNG_LIST_TRACEPOINTS:
+ 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;
+ } else {
+ /* If no session name specified */
+ ret = LTTCOMM_SELECT_SESS;
+ }
+ goto error;
+ } else {
+ /* Acquire lock for the session */
+ session_lock(cmd_ctx->session);
+ }
+ break;
+ }
+
+ /*
+ * Check domain type for specific "pre-action".
+ */
+ switch (cmd_ctx->lsm->domain.type) {
+ case LTTNG_DOMAIN_KERNEL:
+ /* Kernel tracer check */
+ if (kernel_tracer_fd == 0) {
+ /* Basically, load kernel tracer modules */
+ init_kernel_tracer();
+ if (kernel_tracer_fd == 0) {
+ ret = LTTCOMM_KERN_NA;
+ goto error;
+ }
+ }
+
+ /* Need a session for kernel command */
+ if (need_tracing_session) {
+ if (cmd_ctx->session->kernel_session == NULL) {
+ ret = create_kernel_session(cmd_ctx->session);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_SESS_FAIL;
+ goto error;
+ }
+ }
+
+ /* Start the kernel consumer daemon */
+ pthread_mutex_lock(&kconsumer_data.pid_mutex);
+ if (kconsumer_data.pid == 0 &&
+ cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
+ 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) {
+ if (cmd_ctx->session->ust_session == 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:
+ break;
+ }
+
+ /* Process by command type */
+ switch (cmd_ctx->lsm->cmd_type) {
+ case LTTNG_ADD_CONTEXT:
+ {
+ ret = cmd_add_context(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+ cmd_ctx->lsm->u.context.channel_name,
+ cmd_ctx->lsm->u.context.event_name,
+ &cmd_ctx->lsm->u.context.ctx);
+ break;
+ }
+ case LTTNG_DISABLE_CHANNEL:
+ {
+ ret = cmd_disable_channel(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+ cmd_ctx->lsm->u.disable.channel_name);
+ break;
+ }
+ case LTTNG_DISABLE_EVENT:
+ {
+ ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+ cmd_ctx->lsm->u.disable.channel_name,
+ cmd_ctx->lsm->u.disable.name);
+ ret = LTTCOMM_OK;
+ break;
+ }
+ case LTTNG_DISABLE_ALL_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);
+ break;
+ }
+ case LTTNG_ENABLE_CHANNEL:
+ {
+ ret = cmd_enable_channel(cmd_ctx->session, &cmd_ctx->lsm->domain,
+ &cmd_ctx->lsm->u.channel.chan);
+ break;
+ }
+ case LTTNG_ENABLE_EVENT:
+ {
+ ret = cmd_enable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+ cmd_ctx->lsm->u.enable.channel_name,
+ &cmd_ctx->lsm->u.enable.event);
+ break;
+ }
+ case LTTNG_ENABLE_ALL_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.event.type);