X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fclient.c;h=d6de4bfbd2fbe202ce119b553041a7056255a1f9;hb=b583ad836a07eb17b3abebc9354e49a9ce415492;hp=ea8ffd45fc066c3cfa16b4ac8017400361888e8d;hpb=4ec029ed8d032ac98d8dc158a751841b7c150639;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/client.c b/src/bin/lttng-sessiond/client.c index ea8ffd45f..d6de4bfbd 100644 --- a/src/bin/lttng-sessiond/client.c +++ b/src/bin/lttng-sessiond/client.c @@ -1,31 +1,30 @@ /* - * Copyright (C) 2011 - David Goulet - * Mathieu Desnoyers - * 2013 - Jérémie Galarneau + * Copyright (C) 2011 EfficiOS Inc. + * Copyright (C) 2011 Mathieu Desnoyers + * Copyright (C) 2013 Jérémie Galarneau * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2 only, - * as published by the Free Software Foundation. + * SPDX-License-Identifier: GPL-2.0-only * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include -#include -#include +#include "common/buffer-view.h" +#include "common/dynamic-buffer.h" +#include "common/sessiond-comm/sessiond-comm.h" +#include "lttng/lttng-error.h" +#include "lttng/tracker.h" #include +#include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include "client.h" #include "lttng-sessiond.h" @@ -36,35 +35,34 @@ #include "testpoint.h" #include "utils.h" #include "manage-consumer.h" +#include "clear.h" static bool is_root; static struct thread_state { - pthread_cond_t cond; - pthread_mutex_t lock; - bool is_running; -} thread_state = { - .cond = PTHREAD_COND_INITIALIZER, - .lock = PTHREAD_MUTEX_INITIALIZER, - .is_running = false -}; - -void set_thread_state_running(void) + sem_t ready; + bool running; + int client_sock; +} thread_state; + +static void set_thread_status(bool running) { - pthread_mutex_lock(&thread_state.lock); - thread_state.is_running = true; - pthread_cond_broadcast(&thread_state.cond); - pthread_mutex_unlock(&thread_state.lock); + DBG("Marking client thread's state as %s", running ? "running" : "error"); + thread_state.running = running; + sem_post(&thread_state.ready); } -static void wait_thread_state_running(void) +static bool wait_thread_status(void) { - pthread_mutex_lock(&thread_state.lock); - while (!thread_state.is_running) { - pthread_cond_wait(&thread_state.cond, - &thread_state.lock); + DBG("Waiting for client thread to be ready"); + sem_wait(&thread_state.ready); + if (thread_state.running) { + DBG("Client thread is ready"); + } else { + ERR("Initialization of client thread failed"); } - pthread_mutex_unlock(&thread_state.lock); + + return thread_state.running; } /* @@ -84,6 +82,7 @@ static int setup_lttng_msg(struct command_ctx *cmd_ctx, const size_t payload_offset = cmd_header_offset + cmd_header_len; const size_t total_msg_size = header_len + cmd_header_len + payload_len; + free(cmd_ctx->llm); cmd_ctx->llm = zmalloc(total_msg_size); if (cmd_ctx->llm == NULL) { @@ -189,7 +188,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) case LTTNG_CONSUMER64_UST: { if (config.consumerd64_lib_dir.value) { - char *tmp; + const char *tmp; size_t tmplen; char *tmpnew; @@ -226,7 +225,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) case LTTNG_CONSUMER32_UST: { if (config.consumerd32_lib_dir.value) { - char *tmp; + const char *tmp; size_t tmplen; char *tmpnew; @@ -391,10 +390,13 @@ static int copy_session_consumer(int domain, struct ltt_session *session) } /* Append correct directory to subdir */ - strncat(consumer->subdir, dir_name, - sizeof(consumer->subdir) - strlen(consumer->subdir) - 1); - DBG3("Copy session consumer subdir %s", consumer->subdir); - + ret = lttng_strncpy(consumer->domain_subdir, dir_name, + sizeof(consumer->domain_subdir)); + if (ret) { + ret = LTTNG_ERR_UNK; + goto error; + } + DBG3("Copy session consumer subdir %s", consumer->domain_subdir); ret = LTTNG_OK; error: @@ -407,7 +409,7 @@ error: * Should *NOT* be called with RCU read-side lock held. */ static int create_ust_session(struct ltt_session *session, - struct lttng_domain *domain) + const struct lttng_domain *domain) { int ret; struct ltt_ust_session *lus = NULL; @@ -475,10 +477,10 @@ static int create_kernel_session(struct ltt_session *session) DBG("Creating kernel session"); - ret = kernel_create_session(session, kernel_tracer_fd); + ret = kernel_create_session(session); if (ret < 0) { ret = LTTNG_ERR_KERN_SESS_FAIL; - goto error; + goto error_create; } /* Code flow safety */ @@ -494,12 +496,14 @@ static int create_kernel_session(struct ltt_session *session) session->kernel_session->gid = session->gid; session->kernel_session->output_traces = session->output_traces; session->kernel_session->snapshot_mode = session->snapshot_mode; + session->kernel_session->is_live_session = session->live_timer != 0; return LTTNG_OK; error: trace_kernel_destroy_session(session->kernel_session); session->kernel_session = NULL; +error_create: return ret; } @@ -530,112 +534,6 @@ static unsigned int lttng_sessions_count(uid_t uid, gid_t gid) return i; } -static int receive_userspace_probe(struct command_ctx *cmd_ctx, int sock, - int *sock_error, struct lttng_event *event) -{ - int fd, ret; - struct lttng_userspace_probe_location *probe_location; - const struct lttng_userspace_probe_location_lookup_method *lookup = NULL; - struct lttng_dynamic_buffer probe_location_buffer; - struct lttng_buffer_view buffer_view; - - /* - * Create a buffer to store the serialized version of the probe - * location. - */ - lttng_dynamic_buffer_init(&probe_location_buffer); - ret = lttng_dynamic_buffer_set_size(&probe_location_buffer, - cmd_ctx->lsm->u.enable.userspace_probe_location_len); - if (ret) { - ret = LTTNG_ERR_NOMEM; - goto error; - } - - /* - * Receive the probe location. - */ - ret = lttcomm_recv_unix_sock(sock, probe_location_buffer.data, - probe_location_buffer.size); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - lttng_dynamic_buffer_reset(&probe_location_buffer); - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - buffer_view = lttng_buffer_view_from_dynamic_buffer( - &probe_location_buffer, 0, probe_location_buffer.size); - - /* - * Extract the probe location from the serialized version. - */ - ret = lttng_userspace_probe_location_create_from_buffer( - &buffer_view, &probe_location); - if (ret < 0) { - WARN("Failed to create a userspace probe location from the received buffer"); - lttng_dynamic_buffer_reset( &probe_location_buffer); - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - /* - * Receive the file descriptor to the target binary from the client. - */ - DBG("Receiving userspace probe target FD from client ..."); - ret = lttcomm_recv_fds_unix_sock(sock, &fd, 1); - if (ret <= 0) { - DBG("Nothing recv() from client userspace probe fd... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - /* - * Set the file descriptor received from the client through the unix - * socket in the probe location. - */ - lookup = lttng_userspace_probe_location_get_lookup_method(probe_location); - if (!lookup) { - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - /* - * From the kernel tracer's perspective, all userspace probe event types - * are all the same: a file and an offset. - */ - switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) { - case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: - ret = lttng_userspace_probe_location_function_set_binary_fd( - probe_location, fd); - break; - case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: - ret = lttng_userspace_probe_location_tracepoint_set_binary_fd( - probe_location, fd); - break; - default: - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - if (ret) { - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - /* Attach the probe location to the event. */ - ret = lttng_event_set_userspace_probe_location(event, probe_location); - if (ret) { - ret = LTTNG_ERR_PROBE_LOCATION_INVAL; - goto error; - } - - lttng_dynamic_buffer_reset(&probe_location_buffer); -error: - return ret; -} - /* * Version of setup_lttng_msg() without command header. */ @@ -702,15 +600,20 @@ static int send_unix_sock(int sock, void *buf, size_t len) * Return any error encountered or 0 for success. * * "sock" is only used for special-case var. len data. + * A command may assume the ownership of the socket, in which case its value + * should be set to -1. * * Should *NOT* be called with RCU read-side lock held. */ -static int process_client_msg(struct command_ctx *cmd_ctx, int sock, +static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, int *sock_error) { int ret = LTTNG_OK; int need_tracing_session = 1; int need_domain; + struct lttng_dynamic_buffer payload; + + lttng_dynamic_buffer_init(&payload); DBG("Processing client command %d", cmd_ctx->lsm->cmd_type); @@ -719,9 +622,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, *sock_error = 0; switch (cmd_ctx->lsm->cmd_type) { - case LTTNG_CREATE_SESSION: - case LTTNG_CREATE_SESSION_SNAPSHOT: - case LTTNG_CREATE_SESSION_LIVE: + case LTTNG_CREATE_SESSION_EXT: case LTTNG_DESTROY_SESSION: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_DOMAINS: @@ -742,6 +643,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_ROTATION_GET_INFO: case LTTNG_ROTATION_SET_SCHEDULE: case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: + case LTTNG_CLEAR_SESSION: need_domain = 0; break; default: @@ -782,11 +684,12 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_CHANNELS: case LTTNG_LIST_EVENTS: case LTTNG_LIST_SYSCALLS: - case LTTNG_LIST_TRACKER_PIDS: + case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: + case LTTNG_PROCESS_ATTR_TRACKER_GET_POLICY: + case LTTNG_PROCESS_ATTR_TRACKER_GET_INCLUSION_SET: case LTTNG_DATA_PENDING: case LTTNG_ROTATE_SESSION: case LTTNG_ROTATION_GET_INFO: - case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: break; default: /* Setup lttng message with no payload */ @@ -799,9 +702,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, /* Commands that DO NOT need a session. */ switch (cmd_ctx->lsm->cmd_type) { - case LTTNG_CREATE_SESSION: - case LTTNG_CREATE_SESSION_SNAPSHOT: - case LTTNG_CREATE_SESSION_LIVE: + case LTTNG_CREATE_SESSION_EXT: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_TRACEPOINTS: case LTTNG_LIST_SYSCALLS: @@ -877,6 +778,15 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, goto error; } + /* Kernel tracer check */ + if (!kernel_tracer_is_initialized()) { + /* Basically, load kernel tracer modules */ + ret = init_kernel_tracer(); + if (ret != 0) { + goto error; + } + } + /* Consumer is in an ERROR state. Report back to client */ if (uatomic_read(&kernel_consumerd_state) == CONSUMER_ERROR) { ret = LTTNG_ERR_NO_KERNCONSUMERD; @@ -887,7 +797,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, if (need_tracing_session) { if (cmd_ctx->session->kernel_session == NULL) { ret = create_kernel_session(cmd_ctx->session); - if (ret < 0) { + if (ret != LTTNG_OK) { ret = LTTNG_ERR_KERN_SESS_FAIL; goto error; } @@ -939,7 +849,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, /* Create UST session if none exist. */ if (cmd_ctx->session->ust_session == NULL) { ret = create_ust_session(cmd_ctx->session, - &cmd_ctx->lsm->domain); + ALIGNED_CONST_PTR(cmd_ctx->lsm->domain)); if (ret != LTTNG_OK) { goto error; } @@ -1071,74 +981,7 @@ skip_domain: switch (cmd_ctx->lsm->cmd_type) { case LTTNG_ADD_CONTEXT: { - /* - * An LTTNG_ADD_CONTEXT command might have a supplementary - * payload if the context being added is an application context. - */ - if (cmd_ctx->lsm->u.context.ctx.ctx == - LTTNG_EVENT_CONTEXT_APP_CONTEXT) { - char *provider_name = NULL, *context_name = NULL; - size_t provider_name_len = - cmd_ctx->lsm->u.context.provider_name_len; - size_t context_name_len = - cmd_ctx->lsm->u.context.context_name_len; - - if (provider_name_len == 0 || context_name_len == 0) { - /* - * Application provider and context names MUST - * be provided. - */ - ret = -LTTNG_ERR_INVALID; - goto error; - } - - provider_name = zmalloc(provider_name_len + 1); - if (!provider_name) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } - cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name = - provider_name; - - context_name = zmalloc(context_name_len + 1); - if (!context_name) { - ret = -LTTNG_ERR_NOMEM; - goto error_add_context; - } - cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name = - context_name; - - ret = lttcomm_recv_unix_sock(sock, provider_name, - provider_name_len); - if (ret < 0) { - goto error_add_context; - } - - ret = lttcomm_recv_unix_sock(sock, context_name, - context_name_len); - if (ret < 0) { - goto error_add_context; - } - } - - /* - * cmd_add_context assumes ownership of the provider and context - * names. - */ - ret = cmd_add_context(cmd_ctx->session, - cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.context.channel_name, - &cmd_ctx->lsm->u.context.ctx, - kernel_poll_pipe[1]); - - cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name = NULL; - cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name = NULL; -error_add_context: - free(cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name); - free(cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name); - if (ret < 0) { - goto error; - } + ret = cmd_add_context(cmd_ctx, *sock, kernel_poll_pipe[1]); break; } case LTTNG_DISABLE_CHANNEL: @@ -1149,219 +992,227 @@ error_add_context: } case LTTNG_DISABLE_EVENT: { - - /* - * FIXME: handle filter; for now we just receive the filter's - * bytecode along with the filter expression which are sent by - * liblttng-ctl and discard them. - * - * This fixes an issue where the client may block while sending - * the filter payload and encounter an error because the session - * daemon closes the socket without ever handling this data. - */ - size_t count = cmd_ctx->lsm->u.disable.expression_len + - cmd_ctx->lsm->u.disable.bytecode_len; - - if (count) { - char data[LTTNG_FILTER_MAX_LEN]; - - DBG("Discarding disable event command payload of size %zu", count); - while (count) { - ret = lttcomm_recv_unix_sock(sock, data, - count > sizeof(data) ? sizeof(data) : count); - if (ret < 0) { - goto error; - } - - count -= (size_t) ret; - } - } - /* FIXME: passing packed structure to non-packed pointer */ - ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.disable.channel_name, - &cmd_ctx->lsm->u.disable.event); + ret = cmd_disable_event(cmd_ctx, *sock); break; } case LTTNG_ENABLE_CHANNEL: { - cmd_ctx->lsm->u.channel.chan.attr.extended.ptr = - (struct lttng_channel_extended *) &cmd_ctx->lsm->u.channel.extended; - ret = cmd_enable_channel(cmd_ctx->session, &cmd_ctx->lsm->domain, - &cmd_ctx->lsm->u.channel.chan, - kernel_poll_pipe[1]); + ret = cmd_enable_channel(cmd_ctx, *sock, kernel_poll_pipe[1]); break; } - case LTTNG_TRACK_PID: - { - ret = cmd_track_pid(cmd_ctx->session, - cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.pid_tracker.pid); - break; - } - case LTTNG_UNTRACK_PID: - { - ret = cmd_untrack_pid(cmd_ctx->session, - cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.pid_tracker.pid); - break; - } - case LTTNG_ENABLE_EVENT: + case LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE: + case LTTNG_PROCESS_ATTR_TRACKER_REMOVE_INCLUDE_VALUE: { - struct lttng_event *ev = NULL; - struct lttng_event_exclusion *exclusion = NULL; - struct lttng_filter_bytecode *bytecode = NULL; - char *filter_expression = NULL; - - /* Handle exclusion events and receive it from the client. */ - if (cmd_ctx->lsm->u.enable.exclusion_count > 0) { - size_t count = cmd_ctx->lsm->u.enable.exclusion_count; - - exclusion = zmalloc(sizeof(struct lttng_event_exclusion) + - (count * LTTNG_SYMBOL_NAME_LEN)); - if (!exclusion) { - ret = LTTNG_ERR_EXCLUSION_NOMEM; - goto error; - } - - DBG("Receiving var len exclusion event list from client ..."); - exclusion->count = count; - ret = lttcomm_recv_unix_sock(sock, exclusion->names, - count * LTTNG_SYMBOL_NAME_LEN); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - free(exclusion); - ret = LTTNG_ERR_EXCLUSION_INVAL; - goto error; - } + struct lttng_dynamic_buffer payload; + struct lttng_buffer_view payload_view; + const bool add_value = + cmd_ctx->lsm->cmd_type == + LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE; + const size_t name_len = + cmd_ctx->lsm->u.process_attr_tracker_add_remove_include_value + .name_len; + const enum lttng_domain_type domain_type = + (enum lttng_domain_type) + cmd_ctx->lsm->domain.type; + const enum lttng_process_attr process_attr = + (enum lttng_process_attr) cmd_ctx->lsm->u + .process_attr_tracker_add_remove_include_value + .process_attr; + const enum lttng_process_attr_value_type value_type = + (enum lttng_process_attr_value_type) cmd_ctx + ->lsm->u + .process_attr_tracker_add_remove_include_value + .value_type; + struct process_attr_value *value; + enum lttng_error_code ret_code; + + /* Receive remaining variable length payload if applicable. */ + if (name_len > LOGIN_NAME_MAX) { + /* + * POSIX mandates user and group names that are at least + * 8 characters long. Note that although shadow-utils + * (useradd, groupaadd, etc.) use 32 chars as their + * limit (from bits/utmp.h, UT_NAMESIZE), + * LOGIN_NAME_MAX is defined to 256. + */ + ERR("Rejecting process attribute tracker value %s as the provided exceeds the maximal allowed length: argument length = %zu, maximal length = %d", + add_value ? "addition" : "removal", + name_len, LOGIN_NAME_MAX); + ret = LTTNG_ERR_INVALID; + goto error; } - /* Get filter expression from client. */ - if (cmd_ctx->lsm->u.enable.expression_len > 0) { - size_t expression_len = - cmd_ctx->lsm->u.enable.expression_len; - - if (expression_len > LTTNG_FILTER_MAX_LEN) { - ret = LTTNG_ERR_FILTER_INVAL; - free(exclusion); - goto error; - } - - filter_expression = zmalloc(expression_len); - if (!filter_expression) { - free(exclusion); - ret = LTTNG_ERR_FILTER_NOMEM; - goto error; + lttng_dynamic_buffer_init(&payload); + if (name_len != 0) { + /* + * Receive variable payload for user/group name + * arguments. + */ + ret = lttng_dynamic_buffer_set_size(&payload, name_len); + if (ret) { + ERR("Failed to allocate buffer to receive payload of %s process attribute tracker value argument", + add_value ? "add" : "remove"); + ret = LTTNG_ERR_NOMEM; + goto error_add_remove_tracker_value; } - /* Receive var. len. data */ - DBG("Receiving var len filter's expression from client ..."); - ret = lttcomm_recv_unix_sock(sock, filter_expression, - expression_len); + ret = lttcomm_recv_unix_sock( + *sock, payload.data, name_len); if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); + ERR("Failed to receive payload of %s process attribute tracker value argument", + add_value ? "add" : "remove"); *sock_error = 1; - free(filter_expression); - free(exclusion); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; + ret = LTTNG_ERR_INVALID_PROTOCOL; + goto error_add_remove_tracker_value; } } - /* Handle filter and get bytecode from client. */ - if (cmd_ctx->lsm->u.enable.bytecode_len > 0) { - size_t bytecode_len = cmd_ctx->lsm->u.enable.bytecode_len; - - if (bytecode_len > LTTNG_FILTER_MAX_LEN) { - ret = LTTNG_ERR_FILTER_INVAL; - free(filter_expression); - free(exclusion); - goto error; - } - - bytecode = zmalloc(bytecode_len); - if (!bytecode) { - free(filter_expression); - free(exclusion); - ret = LTTNG_ERR_FILTER_NOMEM; - goto error; - } - - /* Receive var. len. data */ - DBG("Receiving var len filter's bytecode from client ..."); - ret = lttcomm_recv_unix_sock(sock, bytecode, bytecode_len); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - free(filter_expression); - free(bytecode); - free(exclusion); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - if ((bytecode->len + sizeof(*bytecode)) != bytecode_len) { - free(filter_expression); - free(bytecode); - free(exclusion); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } + payload_view = lttng_buffer_view_from_dynamic_buffer( + &payload, 0, name_len); + /* + * Validate the value type and domains are legal for the process + * attribute tracker that is specified and convert the value to + * add/remove to the internal sessiond representation. + */ + ret_code = process_attr_value_from_comm(domain_type, + process_attr, value_type, + &cmd_ctx->lsm->u.process_attr_tracker_add_remove_include_value + .integral_value, + &payload_view, &value); + if (ret_code != LTTNG_OK) { + ret = ret_code; + goto error_add_remove_tracker_value; + } + + if (add_value) { + ret = cmd_process_attr_tracker_inclusion_set_add_value( + cmd_ctx->session, domain_type, + process_attr, value); + } else { + ret = cmd_process_attr_tracker_inclusion_set_remove_value( + cmd_ctx->session, domain_type, + process_attr, value); + } + process_attr_value_destroy(value); + error_add_remove_tracker_value: + lttng_dynamic_buffer_reset(&payload); + break; + } + case LTTNG_PROCESS_ATTR_TRACKER_GET_POLICY: + { + enum lttng_tracking_policy tracking_policy; + const enum lttng_domain_type domain_type = + (enum lttng_domain_type) + cmd_ctx->lsm->domain.type; + const enum lttng_process_attr process_attr = + (enum lttng_process_attr) cmd_ctx->lsm->u + .process_attr_tracker_get_tracking_policy + .process_attr; + + ret = cmd_process_attr_tracker_get_tracking_policy( + cmd_ctx->session, domain_type, process_attr, + &tracking_policy); + if (ret != LTTNG_OK) { + goto error; } - ev = lttng_event_copy(&cmd_ctx->lsm->u.enable.event); - if (!ev) { - DBG("Failed to copy event: %s", - cmd_ctx->lsm->u.enable.event.name); - free(filter_expression); - free(bytecode); - free(exclusion); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, + &(uint32_t){tracking_policy}, sizeof(uint32_t)); + if (ret < 0) { ret = LTTNG_ERR_NOMEM; goto error; } + ret = LTTNG_OK; + break; + } + case LTTNG_PROCESS_ATTR_TRACKER_SET_POLICY: + { + const enum lttng_tracking_policy tracking_policy = + (enum lttng_tracking_policy) cmd_ctx->lsm->u + .process_attr_tracker_set_tracking_policy + .tracking_policy; + const enum lttng_domain_type domain_type = + (enum lttng_domain_type) + cmd_ctx->lsm->domain.type; + const enum lttng_process_attr process_attr = + (enum lttng_process_attr) cmd_ctx->lsm->u + .process_attr_tracker_set_tracking_policy + .process_attr; + + ret = cmd_process_attr_tracker_set_tracking_policy( + cmd_ctx->session, domain_type, process_attr, + tracking_policy); + if (ret != LTTNG_OK) { + goto error; + } + break; + } + case LTTNG_PROCESS_ATTR_TRACKER_GET_INCLUSION_SET: + { + struct lttng_process_attr_values *values; + struct lttng_dynamic_buffer reply; + const enum lttng_domain_type domain_type = + (enum lttng_domain_type) + cmd_ctx->lsm->domain.type; + const enum lttng_process_attr process_attr = + (enum lttng_process_attr) cmd_ctx->lsm->u + .process_attr_tracker_get_inclusion_set + .process_attr; + + ret = cmd_process_attr_tracker_get_inclusion_set( + cmd_ctx->session, domain_type, process_attr, + &values); + if (ret != LTTNG_OK) { + goto error; + } + lttng_dynamic_buffer_init(&reply); + ret = lttng_process_attr_values_serialize(values, &reply); + if (ret < 0) { + goto error_tracker_get_inclusion_set; + } - if (cmd_ctx->lsm->u.enable.userspace_probe_location_len > 0) { - /* Expect a userspace probe description. */ - ret = receive_userspace_probe(cmd_ctx, sock, sock_error, ev); - if (ret) { - free(filter_expression); - free(bytecode); - free(exclusion); - lttng_event_destroy(ev); - goto error; - } + ret = setup_lttng_msg_no_cmd_header( + cmd_ctx, reply.data, reply.size); + if (ret < 0) { + ret = LTTNG_ERR_NOMEM; + goto error_tracker_get_inclusion_set; } + ret = LTTNG_OK; - ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, - cmd_ctx->lsm->u.enable.channel_name, - ev, - filter_expression, bytecode, exclusion, - kernel_poll_pipe[1]); - lttng_event_destroy(ev); + error_tracker_get_inclusion_set: + lttng_process_attr_values_destroy(values); + lttng_dynamic_buffer_reset(&reply); + break; + } + case LTTNG_ENABLE_EVENT: + { + ret = cmd_enable_event(cmd_ctx, *sock, kernel_poll_pipe[1]); break; } case LTTNG_LIST_TRACEPOINTS: { - struct lttng_event *events; - ssize_t nb_events; + enum lttng_error_code ret_code; + unsigned int nb_events; + struct lttcomm_list_command_header cmd_header = { 0 }; session_lock_list(); - nb_events = cmd_list_tracepoints(cmd_ctx->lsm->domain.type, &events); + ret_code = cmd_list_tracepoints(cmd_ctx->lsm->domain.type, + &payload, &nb_events); session_unlock_list(); - if (nb_events < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nb_events; + if (ret_code != LTTNG_OK) { + ret = (int) ret_code; goto error; } - /* - * Setup lttng message with payload size set to the event list size in - * bytes and then copy list into the llm payload. - */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, events, - sizeof(struct lttng_event) * nb_events); - free(events); + if (nb_events > UINT32_MAX) { + ret = LTTNG_ERR_OVERFLOW; + goto error; + } + + cmd_header.count = (uint32_t) nb_events; + ret = setup_lttng_msg(cmd_ctx, payload.data, payload.size, + &cmd_header, sizeof(cmd_header)); if (ret < 0) { goto setup_error; @@ -1402,51 +1253,24 @@ error_add_context: } case LTTNG_LIST_SYSCALLS: { - struct lttng_event *events; - ssize_t nb_events; + enum lttng_error_code ret_code; + uint32_t nb_syscalls; + struct lttcomm_list_command_header cmd_header = { 0 }; - nb_events = cmd_list_syscalls(&events); - if (nb_events < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nb_events; + ret_code = cmd_list_syscalls(&payload, &nb_syscalls); + if (ret_code != LTTNG_OK) { + ret = (int) ret_code; goto error; } - /* - * Setup lttng message with payload size set to the event list size in - * bytes and then copy list into the llm payload. - */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, events, - sizeof(struct lttng_event) * nb_events); - free(events); - - if (ret < 0) { - goto setup_error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_LIST_TRACKER_PIDS: - { - int32_t *pids = NULL; - ssize_t nr_pids; - - nr_pids = cmd_list_tracker_pids(cmd_ctx->session, - cmd_ctx->lsm->domain.type, &pids); - if (nr_pids < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nr_pids; + if (nb_syscalls > UINT32_MAX) { + ret = LTTNG_ERR_OVERFLOW; goto error; } - /* - * Setup lttng message with payload size set to the event list size in - * bytes and then copy list into the llm payload. - */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, pids, - sizeof(int32_t) * nr_pids); - free(pids); + cmd_header.count = (uint32_t) nb_syscalls; + ret = setup_lttng_msg(cmd_ctx, payload.data, payload.size, + &cmd_header, sizeof(cmd_header)); if (ret < 0) { goto setup_error; @@ -1476,7 +1300,7 @@ error_add_context: /* Receive variable len data */ DBG("Receiving %zu URI(s) from client ...", nb_uri); - ret = lttcomm_recv_unix_sock(sock, uris, len); + ret = lttcomm_recv_unix_sock(*sock, uris, len); if (ret <= 0) { DBG("No URIs received from client... continuing"); *sock_error = 1; @@ -1518,51 +1342,11 @@ error_add_context: ret = cmd_stop_trace(cmd_ctx->session); break; } - case LTTNG_CREATE_SESSION: - { - size_t nb_uri, len; - struct lttng_uri *uris = NULL; - - nb_uri = cmd_ctx->lsm->u.uri.size; - len = nb_uri * sizeof(struct lttng_uri); - - if (nb_uri > 0) { - uris = zmalloc(len); - if (uris == NULL) { - ret = LTTNG_ERR_FATAL; - goto error; - } - - /* Receive variable len data */ - DBG("Waiting for %zu URIs from client ...", nb_uri); - ret = lttcomm_recv_unix_sock(sock, uris, len); - if (ret <= 0) { - DBG("No URIs received from client... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_SESSION_FAIL; - free(uris); - goto error; - } - - if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) { - DBG("Creating session with ONE network URI is a bad call"); - ret = LTTNG_ERR_SESSION_FAIL; - free(uris); - goto error; - } - } - - ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris, nb_uri, - &cmd_ctx->creds, 0); - - free(uris); - - break; - } case LTTNG_DESTROY_SESSION: { ret = cmd_destroy_session(cmd_ctx->session, - notification_thread_handle); + notification_thread_handle, + sock); break; } case LTTNG_LIST_DOMAINS: @@ -1590,20 +1374,20 @@ error_add_context: } case LTTNG_LIST_CHANNELS: { - ssize_t payload_size; - struct lttng_channel *channels = NULL; - - payload_size = cmd_list_channels(cmd_ctx->lsm->domain.type, - cmd_ctx->session, &channels); - if (payload_size < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -payload_size; + uint32_t nb_channel; + enum lttng_error_code ret_code; + struct lttcomm_list_command_header cmd_header = { 0 }; + + ret_code = cmd_list_channels(cmd_ctx->lsm->domain.type, + cmd_ctx->session, &payload, &nb_channel); + if (ret_code != LTTNG_OK) { + ret = (int) ret_code; goto error; } - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, channels, - payload_size); - free(channels); + cmd_header.count = nb_channel; + ret = setup_lttng_msg(cmd_ctx, payload.data, payload.size, + &cmd_header, sizeof(cmd_header)); if (ret < 0) { goto setup_error; @@ -1614,27 +1398,28 @@ error_add_context: } case LTTNG_LIST_EVENTS: { - ssize_t nb_event; - struct lttng_event *events = NULL; - struct lttcomm_event_command_header cmd_header; - size_t total_size; - - memset(&cmd_header, 0, sizeof(cmd_header)); - /* Extended infos are included at the end of events */ - nb_event = cmd_list_events(cmd_ctx->lsm->domain.type, - cmd_ctx->session, cmd_ctx->lsm->u.list.channel_name, - &events, &total_size); - - if (nb_event < 0) { - /* Return value is a negative lttng_error_code. */ - ret = -nb_event; + enum lttng_error_code ret_code; + unsigned int nb_events; + struct lttcomm_list_command_header cmd_header = { 0 }; + + ret_code = cmd_list_events(cmd_ctx->lsm->domain.type, + cmd_ctx->session, + cmd_ctx->lsm->u.list.channel_name, &payload, + &nb_events); + + if (ret_code != LTTNG_OK) { + ret = (int) ret_code; goto error; } - cmd_header.nb_events = nb_event; - ret = setup_lttng_msg(cmd_ctx, events, total_size, - &cmd_header, sizeof(cmd_header)); - free(events); + if (nb_events > UINT32_MAX) { + ret = LTTNG_ERR_OVERFLOW; + goto error; + } + + cmd_header.count = (uint32_t) nb_events; + ret = setup_lttng_msg(cmd_ctx, payload.data, payload.size, + &cmd_header, sizeof(cmd_header)); if (ret < 0) { goto setup_error; @@ -1653,7 +1438,9 @@ error_add_context: nr_sessions = lttng_sessions_count( LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); - payload_len = sizeof(struct lttng_session) * nr_sessions; + + payload_len = (sizeof(struct lttng_session) * nr_sessions) + + (sizeof(struct lttng_session_extended) * nr_sessions); sessions_payload = zmalloc(payload_len); if (!sessions_payload) { @@ -1662,7 +1449,7 @@ error_add_context: goto setup_error; } - cmd_list_lttng_sessions(sessions_payload, + cmd_list_lttng_sessions(sessions_payload, nr_sessions, LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds), LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds)); session_unlock_list(); @@ -1739,13 +1526,16 @@ error_add_context: } case LTTNG_SNAPSHOT_ADD_OUTPUT: { + uint32_t snapshot_id; struct lttcomm_lttng_output_id reply; ret = cmd_snapshot_add_output(cmd_ctx->session, - &cmd_ctx->lsm->u.snapshot_output.output, &reply.id); + ALIGNED_CONST_PTR(cmd_ctx->lsm->u.snapshot_output.output), + &snapshot_id); if (ret != LTTNG_OK) { goto error; } + reply.id = snapshot_id; ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &reply, sizeof(reply)); @@ -1760,7 +1550,7 @@ error_add_context: case LTTNG_SNAPSHOT_DEL_OUTPUT: { ret = cmd_snapshot_del_output(cmd_ctx->session, - &cmd_ctx->lsm->u.snapshot_output.output); + ALIGNED_CONST_PTR(cmd_ctx->lsm->u.snapshot_output.output)); break; } case LTTNG_SNAPSHOT_LIST_OUTPUT: @@ -1789,86 +1579,39 @@ error_add_context: case LTTNG_SNAPSHOT_RECORD: { ret = cmd_snapshot_record(cmd_ctx->session, - &cmd_ctx->lsm->u.snapshot_record.output, + ALIGNED_CONST_PTR(cmd_ctx->lsm->u.snapshot_record.output), cmd_ctx->lsm->u.snapshot_record.wait); break; } - case LTTNG_CREATE_SESSION_SNAPSHOT: + case LTTNG_CREATE_SESSION_EXT: { - size_t nb_uri, len; - struct lttng_uri *uris = NULL; - - nb_uri = cmd_ctx->lsm->u.uri.size; - len = nb_uri * sizeof(struct lttng_uri); - - if (nb_uri > 0) { - uris = zmalloc(len); - if (uris == NULL) { - ret = LTTNG_ERR_FATAL; - goto error; - } - - /* Receive variable len data */ - DBG("Waiting for %zu URIs from client ...", nb_uri); - ret = lttcomm_recv_unix_sock(sock, uris, len); - if (ret <= 0) { - DBG("No URIs received from client... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_SESSION_FAIL; - free(uris); - goto error; - } + struct lttng_dynamic_buffer payload; + struct lttng_session_descriptor *return_descriptor = NULL; - if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) { - DBG("Creating session with ONE network URI is a bad call"); - ret = LTTNG_ERR_SESSION_FAIL; - free(uris); - goto error; - } + lttng_dynamic_buffer_init(&payload); + ret = cmd_create_session(cmd_ctx, *sock, &return_descriptor); + if (ret != LTTNG_OK) { + goto error; } - ret = cmd_create_session_snapshot(cmd_ctx->lsm->session.name, uris, - nb_uri, &cmd_ctx->creds); - free(uris); - break; - } - case LTTNG_CREATE_SESSION_LIVE: - { - size_t nb_uri, len; - struct lttng_uri *uris = NULL; - - nb_uri = cmd_ctx->lsm->u.uri.size; - len = nb_uri * sizeof(struct lttng_uri); - - if (nb_uri > 0) { - uris = zmalloc(len); - if (uris == NULL) { - ret = LTTNG_ERR_FATAL; - goto error; - } - - /* Receive variable len data */ - DBG("Waiting for %zu URIs from client ...", nb_uri); - ret = lttcomm_recv_unix_sock(sock, uris, len); - if (ret <= 0) { - DBG("No URIs received from client... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_SESSION_FAIL; - free(uris); - goto error; - } - - if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) { - DBG("Creating session with ONE network URI is a bad call"); - ret = LTTNG_ERR_SESSION_FAIL; - free(uris); - goto error; - } + ret = lttng_session_descriptor_serialize(return_descriptor, + &payload); + if (ret) { + ERR("Failed to serialize session descriptor in reply to \"create session\" command"); + lttng_session_descriptor_destroy(return_descriptor); + ret = LTTNG_ERR_NOMEM; + goto error; } - - ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris, - nb_uri, &cmd_ctx->creds, cmd_ctx->lsm->u.session_live.timer_interval); - free(uris); + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, payload.data, + payload.size); + if (ret) { + lttng_session_descriptor_destroy(return_descriptor); + ret = LTTNG_ERR_NOMEM; + goto error; + } + lttng_dynamic_buffer_reset(&payload); + lttng_session_descriptor_destroy(return_descriptor); + ret = LTTNG_OK; break; } case LTTNG_SAVE_SESSION: @@ -1895,13 +1638,13 @@ error_add_context: } case LTTNG_REGISTER_TRIGGER: { - ret = cmd_register_trigger(cmd_ctx, sock, + ret = cmd_register_trigger(cmd_ctx, *sock, notification_thread_handle); break; } case LTTNG_UNREGISTER_TRIGGER: { - ret = cmd_unregister_trigger(cmd_ctx, sock, + ret = cmd_unregister_trigger(cmd_ctx, *sock, notification_thread_handle); break; } @@ -1918,7 +1661,9 @@ error_add_context: goto error; } - ret = cmd_rotate_session(cmd_ctx->session, &rotate_return); + ret = cmd_rotate_session(cmd_ctx->session, &rotate_return, + false, + LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED); if (ret < 0) { ret = -ret; goto error; @@ -2002,6 +1747,11 @@ error_add_context: ret = LTTNG_OK; break; } + case LTTNG_CLEAR_SESSION: + { + ret = cmd_clear_session(cmd_ctx->session, sock); + break; + } default: ret = LTTNG_ERR_UND; break; @@ -2020,12 +1770,14 @@ setup_error: if (cmd_ctx->session) { session_unlock(cmd_ctx->session); session_put(cmd_ctx->session); + cmd_ctx->session = NULL; } if (need_tracing_session) { session_unlock_list(); } init_setup_error: assert(!rcu_read_ongoing()); + lttng_dynamic_buffer_reset(&payload); return ret; } @@ -2053,8 +1805,11 @@ static int create_client_sock(void) /* File permission MUST be 660 */ ret = chmod(config.client_unix_sock_path.value, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (ret < 0) { - ERR("Set file permissions failed: %s", config.client_unix_sock_path.value); + ERR("Set file permissions failed: %s", + config.client_unix_sock_path.value); PERROR("chmod"); + (void) lttcomm_close_unix_sock(client_sock); + ret = -1; goto end; } DBG("Created client socket (fd = %i)", client_sock); @@ -2071,6 +1826,11 @@ static void cleanup_client_thread(void *data) lttng_pipe_destroy(quit_pipe); } +static void thread_init_cleanup(void *data) +{ + set_thread_status(false); +} + /* * This thread manage all clients request using the unix client socket for * communication. @@ -2082,7 +1842,7 @@ static void *thread_manage_clients(void *data) uint32_t revents, nb_fd; struct command_ctx *cmd_ctx = NULL; struct lttng_poll_event events; - int client_sock = -1; + const int client_sock = thread_state.client_sock; struct lttng_pipe *quit_pipe = data; const int thread_quit_pipe_fd = lttng_pipe_get_readfd(quit_pipe); @@ -2090,10 +1850,7 @@ static void *thread_manage_clients(void *data) is_root = (getuid() == 0); - client_sock = create_client_sock(); - if (client_sock < 0) { - goto error_listen; - } + pthread_cleanup_push(thread_init_cleanup, NULL); rcu_register_thread(); @@ -2127,6 +1884,10 @@ static void *thread_manage_clients(void *data) goto error; } + /* Set state as running. */ + set_thread_status(true); + pthread_cleanup_pop(0); + /* This testpoint is after we signal readiness to the parent. */ if (testpoint(sessiond_thread_manage_clients)) { goto error; @@ -2138,9 +1899,6 @@ static void *thread_manage_clients(void *data) health_code_update(); - /* Set state as running. */ - set_thread_state_running(); - while (1) { const struct cmd_completion_handler *cmd_completion_handler; @@ -2169,11 +1927,6 @@ static void *thread_manage_clients(void *data) health_code_update(); - if (!revents) { - /* No activity for this FD (poll implementation). */ - continue; - } - if (pollfd == thread_quit_pipe_fd) { err = 0; goto exit; @@ -2262,14 +2015,16 @@ static void *thread_manage_clients(void *data) * informations for the client. The command context struct contains * everything this function may needs. */ - ret = process_client_msg(cmd_ctx, sock, &sock_error); + ret = process_client_msg(cmd_ctx, &sock, &sock_error); rcu_thread_offline(); if (ret < 0) { - ret = close(sock); - if (ret) { - PERROR("close"); - } - sock = -1; + if (sock >= 0) { + ret = close(sock); + if (ret) { + PERROR("close"); + } + } + sock = -1; /* * TODO: Inform client somehow of the fatal error. At * this point, ret < 0 means that a zmalloc failed @@ -2295,21 +2050,24 @@ static void *thread_manage_clients(void *data) health_code_update(); - DBG("Sending response (size: %d, retcode: %s (%d))", - cmd_ctx->lttng_msg_size, - lttng_strerror(-cmd_ctx->llm->ret_code), - 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"); - } + if (sock >= 0) { + DBG("Sending response (size: %d, retcode: %s (%d))", + cmd_ctx->lttng_msg_size, + lttng_strerror(-cmd_ctx->llm->ret_code), + 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"); + } - /* End of transmission */ - ret = close(sock); - if (ret) { - PERROR("close"); - } - sock = -1; + /* End of transmission */ + ret = close(sock); + if (ret) { + PERROR("close"); + } + } + sock = -1; clean_command_ctx(&cmd_ctx); @@ -2331,11 +2089,9 @@ error: error_listen: error_create_poll: unlink(config.client_unix_sock_path.value); - if (client_sock >= 0) { - ret = close(client_sock); - if (ret) { - PERROR("close"); - } + ret = close(client_sock); + if (ret) { + PERROR("close"); } if (err) { @@ -2362,14 +2118,23 @@ bool shutdown_client_thread(void *thread_data) struct lttng_thread *launch_client_thread(void) { + bool thread_running; struct lttng_pipe *client_quit_pipe; - struct lttng_thread *thread; + struct lttng_thread *thread = NULL; + int client_sock_fd = -1; + sem_init(&thread_state.ready, 0, 0); client_quit_pipe = lttng_pipe_open(FD_CLOEXEC); if (!client_quit_pipe) { goto error; } + client_sock_fd = create_client_sock(); + if (client_sock_fd < 0) { + goto error; + } + + thread_state.client_sock = client_sock_fd; thread = lttng_thread_create("Client management", thread_manage_clients, shutdown_client_thread, @@ -2378,15 +2143,26 @@ struct lttng_thread *launch_client_thread(void) if (!thread) { goto error; } + /* The client thread now owns the client sock fd and the quit pipe. */ + client_sock_fd = -1; + client_quit_pipe = NULL; /* * This thread is part of the threads that need to be fully * initialized before the session daemon is marked as "ready". */ - wait_thread_state_running(); - + thread_running = wait_thread_status(); + if (!thread_running) { + goto error; + } return thread; error: + if (client_sock_fd >= 0) { + if (close(client_sock_fd)) { + PERROR("Failed to close client socket"); + } + } + lttng_thread_put(thread); cleanup_client_thread(client_quit_pipe); return NULL; }