/* Flag session that trace should start automatically */
if (usess) {
- /*
- * Even though the start trace might fail, flag this session active so
- * other application coming in are started by default.
- */
- usess->active = 1;
-
ret = ust_app_start_trace_all(usess);
if (ret < 0) {
ret = LTTNG_ERR_UST_START_FAIL;
goto error;
}
- if (session->rotation_schedule_timer_enabled) {
- if (timer_session_rotation_schedule_timer_stop(
- session)) {
- ERR("Failed to stop the \"rotation schedule\" timer of session %s",
- session->name);
- }
- }
-
- /*
- * A rotation is still ongoing. The check timer will continue to wait
- * for the rotation to complete. When the rotation finally completes,
- * a check will be performed to rename the "active" chunk to the
- * expected "timestamp_begin-timestamp_end" format.
- */
- if (session->current_archive_id > 0 &&
- session->rotation_state != LTTNG_ROTATION_STATE_ONGOING) {
- ret = rename_active_chunk(session);
- if (ret) {
- /*
- * This error should not prevent the user from stopping
- * the session. However, it will be reported at the end.
- */
- error_occurred = true;
- }
- }
-
/* Kernel tracer */
if (ksession && ksession->active) {
DBG("Stop kernel tracing");
}
if (usess && usess->active) {
- /*
- * Even though the stop trace might fail, flag this session inactive so
- * other application coming in are not started by default.
- */
- usess->active = 0;
-
ret = ust_app_stop_trace_all(usess);
if (ret < 0) {
ret = LTTNG_ERR_UST_STOP_FAIL;
size_t nb_uri, lttng_sock_cred *creds, unsigned int live_timer)
{
int ret;
- struct ltt_session *session;
+ struct ltt_session *session = NULL;
assert(name);
assert(creds);
- /*
- * Verify if the session already exist
- *
- * XXX: There is no need for the session lock list here since the caller
- * (process_client_msg) is holding it. We might want to change that so a
- * single command does not lock the entire session list.
- */
+ /* Check if the session already exists. */
+ session_lock_list();
session = session_find_by_name(name);
+ session_unlock_list();
if (session != NULL) {
ret = LTTNG_ERR_EXIST_SESS;
- goto find_error;
+ goto end;
}
/* Create tracing session in the registry */
ret = session_create(name, LTTNG_SOCK_GET_UID_CRED(creds),
LTTNG_SOCK_GET_GID_CRED(creds));
if (ret != LTTNG_OK) {
- goto session_error;
+ goto end;
}
- /*
- * Get the newly created session pointer back
- *
- * XXX: There is no need for the session lock list here since the caller
- * (process_client_msg) is holding it. We might want to change that so a
- * single command does not lock the entire session list.
- */
+ /* Get the newly created session pointer back. */
+ session_lock_list();
session = session_find_by_name(name);
+ session_unlock_list();
assert(session);
session->live_timer = live_timer;
session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
if (session->consumer == NULL) {
ret = LTTNG_ERR_FATAL;
- goto consumer_error;
+ goto end;
}
if (uris) {
ret = cmd_set_consumer_uri(session, nb_uri, uris);
if (ret != LTTNG_OK) {
- goto consumer_error;
+ goto end;
}
session->output_traces = 1;
} else {
session->consumer->enabled = 1;
- return LTTNG_OK;
-
-consumer_error:
- session_destroy(session);
-session_error:
-find_error:
+ ret = LTTNG_OK;
+end:
+ if (session) {
+ session_lock_list();
+ session_put(session);
+ session_unlock_list();
+ }
return ret;
}
size_t nb_uri, lttng_sock_cred *creds)
{
int ret;
- struct ltt_session *session;
+ struct ltt_session *session = NULL;
struct snapshot_output *new_output = NULL;
assert(name);
*/
ret = cmd_create_session_uri(name, NULL, 0, creds, 0);
if (ret != LTTNG_OK) {
- goto error;
+ goto end;
}
/* Get the newly created session pointer back. This should NEVER fail. */
+ session_lock_list();
session = session_find_by_name(name);
+ session_unlock_list();
assert(session);
/* Flag session for snapshot mode. */
/* Skip snapshot output creation if no URI is given. */
if (nb_uri == 0) {
+ /* Not an error. */
goto end;
}
snapshot_add_output(&session->snapshot, new_output);
rcu_read_unlock();
-end:
- return LTTNG_OK;
+ ret = LTTNG_OK;
+ goto end;
error_snapshot:
snapshot_output_destroy(new_output);
error_snapshot_alloc:
- session_destroy(session);
-error:
+end:
+ if (session) {
+ session_lock_list();
+ session_put(session);
+ session_unlock_list();
+ }
return ret;
}
*
* Called with session lock held.
*/
-int cmd_destroy_session(struct ltt_session *session, int wpipe,
+int cmd_destroy_session(struct ltt_session *session,
struct notification_thread_handle *notification_thread_handle)
{
int ret;
- struct ltt_ust_session *usess;
- struct ltt_kernel_session *ksess;
/* Safety net */
assert(session);
- usess = session->ust_session;
- ksess = session->kernel_session;
-
DBG("Begin destroy session %s (id %" PRIu64 ")", session->name, session->id);
- if (session->rotation_pending_check_timer_enabled) {
- if (timer_session_rotation_pending_check_stop(session)) {
- ERR("Failed to stop the \"rotation pending check\" timer of session %s",
- session->name);
- }
- }
-
if (session->rotation_schedule_timer_enabled) {
if (timer_session_rotation_schedule_timer_stop(
session)) {
session->rotate_size = 0;
}
- /*
- * The rename of the current chunk is performed at stop, but if we rotated
- * the session after the previous stop command, we need to rename the
- * new (and empty) chunk that was started in between.
- */
- if (session->rotated_after_last_stop) {
- rename_active_chunk(session);
- }
-
- /* Clean kernel session teardown */
- kernel_destroy_session(ksess);
-
- /* UST session teardown */
- if (usess) {
- /* Close any relayd session */
- consumer_output_send_destroy_relayd(usess->consumer);
-
- /* Destroy every UST application related to this session. */
- ret = ust_app_destroy_trace_all(usess);
- if (ret) {
- ERR("Error in ust_app_destroy_trace_all");
+ if (session->current_archive_id != 0) {
+ if (!session->rotated_after_last_stop) {
+ ret = cmd_rotate_session(session, NULL);
+ if (ret != LTTNG_OK) {
+ ERR("Failed to perform an implicit rotation as part of the rotation: %s", lttng_strerror(-ret));
+ }
+ } else {
+ /*
+ * Rename the active chunk to ensure it has a name
+ * of the form ts_begin-ts_end-id.
+ *
+ * Note that no trace data has been produced since
+ * the last rotation; the directory should be
+ * removed.
+ */
+ ret = rename_active_chunk(session);
+ if (ret) {
+ ERR("Failed to rename active chunk during the destruction of session \"%s\"",
+ session->name);
+ }
}
-
- /* Clean up the rest. */
- trace_ust_destroy_session(usess);
- }
-
- /*
- * Must notify the kernel thread here to update it's poll set in order to
- * remove the channel(s)' fd just destroyed.
- */
- ret = notify_thread_pipe(wpipe);
- if (ret < 0) {
- PERROR("write kernel poll pipe");
}
if (session->shm_path[0]) {
sizeof(destroy_completion_handler.shm_path));
assert(!ret);
}
- ret = session_destroy(session);
+
+ /*
+ * The session is destroyed. However, note that the command context
+ * still holds a reference to the session, thus delaying its destruction
+ * _at least_ up to the point when that reference is released.
+ */
+ session_destroy(session);
+ ret = LTTNG_OK;
return ret;
}
* the buffer.
*/
cds_list_for_each_entry(session, &list->head, list) {
+ if (!session_get(session)) {
+ continue;
+ }
/*
* Only list the sessions the user can control.
*/
- if (!session_access_ok(session, uid, gid)) {
+ if (!session_access_ok(session, uid, gid) ||
+ session->destroyed) {
+ session_put(session);
continue;
}
}
if (ret < 0) {
PERROR("snprintf session path");
+ session_put(session);
continue;
}
sessions[i].snapshot_mode = session->snapshot_mode;
sessions[i].live_timer_interval = session->live_timer;
i++;
+ session_put(session);
}
}
now = time(NULL);
if (now == (time_t) -1) {
- cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE;
+ cmd_ret = LTTNG_ERR_UNK;
goto end;
}