+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ case LTTNG_DOMAIN_UST_PID:
+ break;
+ default:
+ ret = LTTCOMM_UNKNOWN_DOMAIN;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+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,
+ struct lttng_domain *domain, struct lttng_channel *attr)
+{
+ int ret;
+
+ switch (domain->type) {
+ case LTTNG_DOMAIN_KERNEL:
+ {
+ struct ltt_kernel_channel *kchan;
+
+ 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);
+ }
+
+ 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;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_DISABLE_EVENT processed by the client thread.
+ */
+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:
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ ret = LTTCOMM_KERN_CHAN_NOT_FOUND;
+ goto error;
+ }
+
+ ret = event_kernel_disable_tracepoint(session->kernel_session, kchan, event_name);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_DISABLE_ALL_EVENT processed by the client thread.
+ */
+static int cmd_disable_event_all(struct ltt_session *session, int domain,
+ char *channel_name)
+{
+ 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 = LTTCOMM_KERN_CHAN_NOT_FOUND;
+ goto error;
+ }
+
+ ret = event_kernel_disable_all(session->kernel_session, kchan);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_ADD_CONTEXT processed by the client thread.
+ */
+static int cmd_add_context(struct ltt_session *session, int domain,
+ char *channel_name, char *event_name, struct lttng_event_context *ctx)
+{
+ int ret;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ /* Add kernel context to kernel tracer */
+ ret = context_kernel_add(session->kernel_session, ctx,
+ event_name, channel_name);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_ENABLE_EVENT processed by the client thread.
+ */
+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;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ /* This call will notify the kernel thread */
+ ret = channel_kernel_create(session->kernel_session,
+ NULL, kernel_poll_pipe[1]);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
+
+ /* Get the newly created kernel channel pointer */
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ /* This sould not happen... */
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ ret = event_kernel_enable_tracepoint(session->kernel_session, kchan, event);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * 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, int event_type)
+{
+ 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) {
+ /* This call will notify the kernel thread */
+ ret = channel_kernel_create(session->kernel_session, NULL,
+ kernel_poll_pipe[1]);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
+
+ /* Get the newly created kernel channel pointer */
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ /* This sould not happen... */
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ 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;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ default:
+ /* TODO: Userspace tracing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+/*
+ * Command LTTNG_LIST_TRACEPOINTS processed by the client thread.
+ */
+static ssize_t cmd_list_tracepoints(int domain, struct lttng_event **events)
+{
+ int ret;
+ ssize_t nb_events = 0;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ nb_events = kernel_list_events(kernel_tracer_fd, events);
+ if (nb_events < 0) {
+ ret = LTTCOMM_KERN_LIST_FAIL;
+ goto error;
+ }
+ break;
+ default:
+ /* TODO: Userspace listing */
+ ret = LTTCOMM_NOT_IMPLEMENTED;
+ goto error;
+ }
+
+ return nb_events;
+
+error:
+ /* Return negative value to differentiate return code */
+ return -ret;
+}
+
+/*
+ * Command LTTNG_START_TRACE processed by the client thread.
+ */
+static int cmd_start_trace(struct ltt_session *session)
+{
+ int ret;
+ struct ltt_kernel_channel *kchan;
+ struct ltt_kernel_session *ksession;
+
+ /* Short cut */
+ ksession = session->kernel_session;
+
+ /* Kernel tracing */
+ if (ksession != NULL) {
+ /* Open kernel metadata */
+ if (ksession->metadata == NULL) {
+ ret = kernel_open_metadata(ksession, ksession->trace_path);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_META_FAIL;
+ goto error;
+ }
+ }
+
+ /* Open kernel metadata stream */
+ if (ksession->metadata_stream_fd == 0) {
+ ret = kernel_open_metadata_stream(ksession);
+ if (ret < 0) {
+ ERR("Kernel create metadata stream failed");
+ ret = LTTCOMM_KERN_STREAM_FAIL;
+ goto error;
+ }
+ }
+
+ /* For each channel */
+ cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
+ if (kchan->stream_count == 0) {
+ ret = kernel_open_channel_stream(kchan);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_STREAM_FAIL;
+ goto error;
+ }
+ /* Update the stream global counter */
+ ksession->stream_count_global += ret;
+ }
+ }
+
+ /* Setup kernel consumer socket and send fds to it */
+ ret = init_kernel_tracing(ksession);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_START_FAIL;
+ goto error;
+ }
+
+ /* This start the kernel tracing */
+ ret = kernel_start_session(ksession);
+ if (ret < 0) {
+ ret = LTTCOMM_KERN_START_FAIL;
+ goto error;
+ }
+
+ /* Quiescent wait after starting trace */
+ kernel_wait_quiescent(kernel_tracer_fd);
+ }
+
+ /* TODO: Start all UST traces */
+
+ 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;
+
+ /* 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);
+ }
+
+ /* TODO : User-space tracer */
+
+ 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++;
+ }
+
+ nb_dom += session->ust_session_list.count;
+
+ *domains = malloc(nb_dom * sizeof(struct lttng_domain));
+ if (*domains == NULL) {
+ ret = -LTTCOMM_FATAL;
+ goto error;
+ }
+
+ (*domains)[0].type = LTTNG_DOMAIN_KERNEL;
+
+ /* TODO: User-space tracer domain support */
+
+ 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);
+
+ 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. */