X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Faction-executor.cpp;h=23a99a1acbbb7ec94458ad79a5dc7d9a85ba68ee;hp=cc7834f2745ca6e58d8299dd7c649fe68ecc0aaa;hb=HEAD;hpb=7966af5763c4aaca39df9bbfa9277ff15715c720 diff --git a/src/bin/lttng-sessiond/action-executor.cpp b/src/bin/lttng-sessiond/action-executor.cpp index cc7834f27..3fbb87f43 100644 --- a/src/bin/lttng-sessiond/action-executor.cpp +++ b/src/bin/lttng-sessiond/action-executor.cpp @@ -5,37 +5,55 @@ * */ -#include "action-executor.h" -#include "cmd.h" -#include "health-sessiond.h" -#include "lttng-sessiond.h" -#include "notification-thread-internal.h" -#include "session.h" -#include "thread.h" -#include -#include -#include -#include -#include +#include "action-executor.hpp" +#include "cmd.hpp" +#include "health-sessiond.hpp" +#include "lttng-sessiond.hpp" +#include "notification-thread-internal.hpp" +#include "session.hpp" +#include "thread.hpp" + +#include +#include +#include +#include + +#include +#include #include -#include +#include #include #include #include #include #include #include -#include +#include #include -#include +#include + #include #include #include #include -#define THREAD_NAME "Action Executor" +#define THREAD_NAME "Action Executor" #define MAX_QUEUED_WORK_COUNT 8192 +struct action_executor { + struct lttng_thread *thread; + struct notification_thread_handle *notification_thread_handle; + struct { + uint64_t pending_count; + struct cds_list_head list; + pthread_cond_t cond; + pthread_mutex_t lock; + } work; + bool should_quit; + uint64_t next_work_item_id; +}; + +namespace { /* * A work item is composed of a dynamic array of sub-items which * represent a flattened, and augmented, version of a trigger's actions. @@ -69,7 +87,6 @@ * trigger object at the moment of execution, if the trigger is found to be * unregistered, the execution is skipped. */ - struct action_work_item { uint64_t id; @@ -94,69 +111,50 @@ struct action_work_subitem { LTTNG_OPTIONAL(uint64_t) session_id; } context; }; - -struct action_executor { - struct lttng_thread *thread; - struct notification_thread_handle *notification_thread_handle; - struct { - uint64_t pending_count; - struct cds_list_head list; - pthread_cond_t cond; - pthread_mutex_t lock; - } work; - bool should_quit; - uint64_t next_work_item_id; -}; +} /* namespace */ /* * Only return non-zero on a fatal error that should shut down the action * executor. */ -typedef int (*action_executor_handler)(struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *item); +using action_executor_handler = int (*)(struct action_executor *, + const struct action_work_item *, + struct action_work_subitem *); static int action_executor_notify_handler(struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *); -static int action_executor_start_session_handler( - struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *); -static int action_executor_stop_session_handler( - struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *); -static int action_executor_rotate_session_handler( - struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *); -static int action_executor_snapshot_session_handler( - struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *); + const struct action_work_item *, + struct action_work_subitem *); +static int action_executor_start_session_handler(struct action_executor *executor, + const struct action_work_item *, + struct action_work_subitem *); +static int action_executor_stop_session_handler(struct action_executor *executor, + const struct action_work_item *, + struct action_work_subitem *); +static int action_executor_rotate_session_handler(struct action_executor *executor, + const struct action_work_item *, + struct action_work_subitem *); +static int action_executor_snapshot_session_handler(struct action_executor *executor, + const struct action_work_item *, + struct action_work_subitem *); static int action_executor_list_handler(struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *); + const struct action_work_item *, + struct action_work_subitem *); static int action_executor_generic_handler(struct action_executor *executor, - const struct action_work_item *, - struct action_work_subitem *); + const struct action_work_item *, + struct action_work_subitem *); static const action_executor_handler action_executors[] = { - action_executor_notify_handler, - action_executor_start_session_handler, - action_executor_stop_session_handler, - action_executor_rotate_session_handler, - action_executor_snapshot_session_handler, - action_executor_list_handler, + action_executor_notify_handler, action_executor_start_session_handler, + action_executor_stop_session_handler, action_executor_rotate_session_handler, + action_executor_snapshot_session_handler, action_executor_list_handler, }; /* Forward declaration */ static int add_action_to_subitem_array(struct lttng_action *action, - struct lttng_dynamic_array *subitems); + struct lttng_dynamic_array *subitems); static int populate_subitem_array_from_trigger(struct lttng_trigger *trigger, - struct lttng_dynamic_array *subitems); + struct lttng_dynamic_array *subitems); static void action_work_subitem_destructor(void *element) { @@ -176,7 +174,7 @@ static const char *get_action_name(const struct lttng_action *action) /* Check if this trigger allowed to interect with a given session. */ static bool is_trigger_allowed_for_session(const struct lttng_trigger *trigger, - struct ltt_session *session) + struct ltt_session *session) { bool is_allowed = false; const struct lttng_credentials session_creds = { @@ -184,17 +182,16 @@ static bool is_trigger_allowed_for_session(const struct lttng_trigger *trigger, .gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid), }; /* Can never be NULL. */ - const struct lttng_credentials *trigger_creds = - lttng_trigger_get_credentials(trigger); + const struct lttng_credentials *trigger_creds = lttng_trigger_get_credentials(trigger); is_allowed = (lttng_credentials_is_equal_uid(trigger_creds, &session_creds)) || - (lttng_credentials_get_uid(trigger_creds) == 0); + (lttng_credentials_get_uid(trigger_creds) == 0); if (!is_allowed) { WARN("Trigger is not allowed to interact with session `%s`: session uid = %ld, session gid = %ld, trigger uid = %ld", - session->name, - (long int) session->uid, - (long int) session->gid, - (long int) lttng_credentials_get_uid(trigger_creds)); + session->name, + (long int) session->uid, + (long int) session->gid, + (long int) lttng_credentials_get_uid(trigger_creds)); } return is_allowed; @@ -220,10 +217,9 @@ static const char *get_trigger_name(const struct lttng_trigger *trigger) return trigger_name; } -static int client_handle_transmission_status( - struct notification_client *client, - enum client_transmission_status status, - void *user_data) +static int client_handle_transmission_status(struct notification_client *client, + enum client_transmission_status status, + void *user_data) { int ret = 0; struct action_executor *executor = (action_executor *) user_data; @@ -232,20 +228,29 @@ static int client_handle_transmission_status( switch (status) { case CLIENT_TRANSMISSION_STATUS_COMPLETE: DBG("Successfully sent full notification to client, client_id = %" PRIu64, - client->id); + client->id); + /* + * There is no need to wake the (e)poll thread. If it was waiting for + * "out" events on the client's socket, it will see that no payload + * in queued and will unsubscribe from that event. + * + * In the other cases, we have to wake the the (e)poll thread to either + * handle the error on the client or to get it to monitor the client "out" + * events. + */ update_communication = false; break; case CLIENT_TRANSMISSION_STATUS_QUEUED: DBG("Queued notification in client outgoing buffer, client_id = %" PRIu64, - client->id); + client->id); break; case CLIENT_TRANSMISSION_STATUS_FAIL: DBG("Communication error occurred while sending notification to client, client_id = %" PRIu64, - client->id); + client->id); break; default: ERR("Fatal error encoutered while sending notification to client, client_id = %" PRIu64, - client->id); + client->id); ret = -1; goto end; } @@ -256,29 +261,28 @@ static int client_handle_transmission_status( /* Safe to read client's id without locking as it is immutable. */ ret = notification_thread_client_communication_update( - executor->notification_thread_handle, client->id, - status); + executor->notification_thread_handle, client->id, status); end: return ret; } static int action_executor_notify_handler(struct action_executor *executor, - const struct action_work_item *work_item, - struct action_work_subitem *item) + const struct action_work_item *work_item, + struct action_work_subitem *item __attribute__((unused))) { - return notification_client_list_send_evaluation(work_item->client_list, - work_item->trigger, - work_item->evaluation, - work_item->object_creds.is_set ? - &(work_item->object_creds.value) : - NULL, - client_handle_transmission_status, executor); + return notification_client_list_send_evaluation( + work_item->client_list, + work_item->trigger, + work_item->evaluation, + work_item->object_creds.is_set ? &(work_item->object_creds.value) : nullptr, + client_handle_transmission_status, + executor); } -static int action_executor_start_session_handler( - struct action_executor *executor, - const struct action_work_item *work_item, - struct action_work_subitem *item) +static int action_executor_start_session_handler(struct action_executor *executor + __attribute__((unused)), + const struct action_work_item *work_item, + struct action_work_subitem *item) { int ret = 0; const char *session_name; @@ -287,11 +291,11 @@ static int action_executor_start_session_handler( enum lttng_error_code cmd_ret; struct lttng_action *action = item->action; - action_status = lttng_action_start_session_get_session_name( - action, &session_name); + lttng::urcu::read_lock_guard read_lock; + + action_status = lttng_action_start_session_get_session_name(action, &session_name); if (action_status != LTTNG_ACTION_STATUS_OK) { - ERR("Failed to get session name from `%s` action", - get_action_name(action)); + ERR("Failed to get session name from `%s` action", get_action_name(action)); ret = -1; goto end; } @@ -301,63 +305,62 @@ static int action_executor_start_session_handler( * existed. If not skip the action altogether. */ if (!item->context.session_id.is_set) { - DBG("Session `%s` was not present at the moment the work item was enqueued for %s` action of trigger `%s`", - session_name, get_action_name(action), - get_trigger_name(work_item->trigger)); + DBG("Session `%s` was not present at the moment the work item was enqueued for `%s` action of trigger `%s`", + session_name, + get_action_name(action), + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); - ret = 0; goto end; } session_lock_list(); - session = session_find_by_name(session_name); + session = session_find_by_id(LTTNG_OPTIONAL_GET(item->context.session_id)); if (!session) { DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`", - session_name, get_action_name(action), - get_trigger_name(work_item->trigger)); + session_name, + get_action_name(action), + get_trigger_name(work_item->trigger)); + lttng_action_increase_execution_failure_count(action); goto error_unlock_list; } - /* - * Check if the session id is the same as when the work item was - * enqueued. - */ - if (session->id != LTTNG_OPTIONAL_GET(item->context.session_id)) { - DBG("Session id for session `%s` (id: %" PRIu64 - " is not the same that was sampled (id: %" PRIu64 - " at the moment the work item was enqueued for %s` action of trigger `%s`", - session_name, session->id, - LTTNG_OPTIONAL_GET(item->context.session_id), - get_action_name(action), - get_trigger_name(work_item->trigger)); - ret = 0; - goto error_unlock_list; + session_lock(session); + if (session->destroyed) { + DBG("Session `%s` with id = %" PRIu64 + " is flagged as destroyed. Skipping: action = `%s`, trigger = `%s`", + session->name, + session->id, + get_action_name(action), + get_trigger_name(work_item->trigger)); + goto error_unlock_session; } - session_lock(session); if (!is_trigger_allowed_for_session(work_item->trigger, session)) { - goto error_dispose_session; + goto error_unlock_session; } cmd_ret = (lttng_error_code) cmd_start_trace(session); switch (cmd_ret) { case LTTNG_OK: DBG("Successfully started session `%s` on behalf of trigger `%s`", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); break; case LTTNG_ERR_TRACE_ALREADY_STARTED: DBG("Attempted to start session `%s` on behalf of trigger `%s` but it was already started", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); break; default: WARN("Failed to start session `%s` on behalf of trigger `%s`: %s", - session_name, get_trigger_name(work_item->trigger), - lttng_strerror(-cmd_ret)); + session_name, + get_trigger_name(work_item->trigger), + lttng_strerror(-cmd_ret)); lttng_action_increase_execution_failure_count(action); break; } -error_dispose_session: +error_unlock_session: session_unlock(session); session_put(session); error_unlock_list: @@ -366,10 +369,10 @@ end: return ret; } -static int action_executor_stop_session_handler( - struct action_executor *executor, - const struct action_work_item *work_item, - struct action_work_subitem *item) +static int action_executor_stop_session_handler(struct action_executor *executor + __attribute__((unused)), + const struct action_work_item *work_item, + struct action_work_subitem *item) { int ret = 0; const char *session_name; @@ -378,11 +381,11 @@ static int action_executor_stop_session_handler( enum lttng_error_code cmd_ret; struct lttng_action *action = item->action; - action_status = lttng_action_stop_session_get_session_name( - action, &session_name); + lttng::urcu::read_lock_guard read_lock; + + action_status = lttng_action_stop_session_get_session_name(action, &session_name); if (action_status != LTTNG_ACTION_STATUS_OK) { - ERR("Failed to get session name from `%s` action", - get_action_name(action)); + ERR("Failed to get session name from `%s` action", get_action_name(action)); ret = -1; goto end; } @@ -392,64 +395,62 @@ static int action_executor_stop_session_handler( * existed. If not, skip the action altogether. */ if (!item->context.session_id.is_set) { - DBG("Session `%s` was not present at the moment the work item was enqueued for %s` action of trigger `%s`", - session_name, get_action_name(action), - get_trigger_name(work_item->trigger)); + DBG("Session `%s` was not present at the moment the work item was enqueued for `%s` action of trigger `%s`", + session_name, + get_action_name(action), + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); - ret = 0; goto end; } session_lock_list(); - session = session_find_by_name(session_name); + session = session_find_by_id(LTTNG_OPTIONAL_GET(item->context.session_id)); if (!session) { DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`", - session_name, get_action_name(action), - get_trigger_name(work_item->trigger)); + session_name, + get_action_name(action), + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); goto error_unlock_list; } - /* - * Check if the session id is the same as when the work item was - * enqueued - */ - if (session->id != LTTNG_OPTIONAL_GET(item->context.session_id)) { - DBG("Session id for session `%s` (id: %" PRIu64 - " is not the same that was sampled (id: %" PRIu64 - " at the moment the work item was enqueued for %s` action of trigger `%s`", - session_name, session->id, - LTTNG_OPTIONAL_GET(item->context.session_id), - get_action_name(action), - get_trigger_name(work_item->trigger)); - ret = 0; - goto error_unlock_list; + session_lock(session); + if (session->destroyed) { + DBG("Session `%s` with id = %" PRIu64 + " is flagged as destroyed. Skipping: action = `%s`, trigger = `%s`", + session->name, + session->id, + get_action_name(action), + get_trigger_name(work_item->trigger)); + goto error_unlock_session; } - session_lock(session); if (!is_trigger_allowed_for_session(work_item->trigger, session)) { - goto error_dispose_session; + goto error_unlock_session; } cmd_ret = (lttng_error_code) cmd_stop_trace(session); switch (cmd_ret) { case LTTNG_OK: DBG("Successfully stopped session `%s` on behalf of trigger `%s`", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); break; case LTTNG_ERR_TRACE_ALREADY_STOPPED: DBG("Attempted to stop session `%s` on behalf of trigger `%s` but it was already stopped", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); break; default: WARN("Failed to stop session `%s` on behalf of trigger `%s`: %s", - session_name, get_trigger_name(work_item->trigger), - lttng_strerror(-cmd_ret)); + session_name, + get_trigger_name(work_item->trigger), + lttng_strerror(-cmd_ret)); lttng_action_increase_execution_failure_count(action); break; } -error_dispose_session: +error_unlock_session: session_unlock(session); session_put(session); error_unlock_list: @@ -458,10 +459,10 @@ end: return ret; } -static int action_executor_rotate_session_handler( - struct action_executor *executor, - const struct action_work_item *work_item, - struct action_work_subitem *item) +static int action_executor_rotate_session_handler(struct action_executor *executor + __attribute__((unused)), + const struct action_work_item *work_item, + struct action_work_subitem *item) { int ret = 0; const char *session_name; @@ -470,11 +471,11 @@ static int action_executor_rotate_session_handler( enum lttng_error_code cmd_ret; struct lttng_action *action = item->action; - action_status = lttng_action_rotate_session_get_session_name( - action, &session_name); + lttng::urcu::read_lock_guard read_lock; + + action_status = lttng_action_rotate_session_get_session_name(action, &session_name); if (action_status != LTTNG_ACTION_STATUS_OK) { - ERR("Failed to get session name from `%s` action", - get_action_name(action)); + ERR("Failed to get session name from `%s` action", get_action_name(action)); ret = -1; goto end; } @@ -484,71 +485,70 @@ static int action_executor_rotate_session_handler( * existed. If not, skip the action altogether. */ if (!item->context.session_id.is_set) { - DBG("Session `%s` was not present at the moment the work item was enqueued for %s` action of trigger `%s`", - session_name, get_action_name(action), - get_trigger_name(work_item->trigger)); + DBG("Session `%s` was not present at the moment the work item was enqueued for `%s` action of trigger `%s`", + session_name, + get_action_name(action), + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); - ret = 0; goto end; } session_lock_list(); - session = session_find_by_name(session_name); + session = session_find_by_id(LTTNG_OPTIONAL_GET(item->context.session_id)); if (!session) { DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`", - session_name, get_action_name(action), - get_trigger_name(work_item->trigger)); + session_name, + get_action_name(action), + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); goto error_unlock_list; } - /* - * Check if the session id is the same as when the work item was - * enqueued. - */ - if (session->id != LTTNG_OPTIONAL_GET(item->context.session_id)) { - DBG("Session id for session `%s` (id: %" PRIu64 - " is not the same that was sampled (id: %" PRIu64 - " at the moment the work item was enqueued for %s` action of trigger `%s`", - session_name, session->id, - LTTNG_OPTIONAL_GET(item->context.session_id), - get_action_name(action), - get_trigger_name(work_item->trigger)); - ret = 0; - goto error_unlock_list; + session_lock(session); + if (session->destroyed) { + DBG("Session `%s` with id = %" PRIu64 + " is flagged as destroyed. Skipping: action = `%s`, trigger = `%s`", + session->name, + session->id, + get_action_name(action), + get_trigger_name(work_item->trigger)); + goto error_unlock_session; } - session_lock(session); if (!is_trigger_allowed_for_session(work_item->trigger, session)) { - goto error_dispose_session; + goto error_unlock_session; } - cmd_ret = (lttng_error_code) cmd_rotate_session(session, NULL, false, - LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED); + cmd_ret = (lttng_error_code) cmd_rotate_session( + session, nullptr, false, LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED); switch (cmd_ret) { case LTTNG_OK: DBG("Successfully started rotation of session `%s` on behalf of trigger `%s`", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); break; case LTTNG_ERR_ROTATION_PENDING: DBG("Attempted to start a rotation of session `%s` on behalf of trigger `%s` but a rotation is already ongoing", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); break; case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP: case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR: DBG("Attempted to start a rotation of session `%s` on behalf of trigger `%s` but a rotation has already been completed since the last stop or clear", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); break; default: WARN("Failed to start a rotation of session `%s` on behalf of trigger `%s`: %s", - session_name, get_trigger_name(work_item->trigger), - lttng_strerror(-cmd_ret)); + session_name, + get_trigger_name(work_item->trigger), + lttng_strerror(-cmd_ret)); lttng_action_increase_execution_failure_count(action); break; } -error_dispose_session: +error_unlock_session: session_unlock(session); session_put(session); error_unlock_list: @@ -557,101 +557,93 @@ end: return ret; } -static int action_executor_snapshot_session_handler( - struct action_executor *executor, - const struct action_work_item *work_item, - struct action_work_subitem *item) +static int action_executor_snapshot_session_handler(struct action_executor *executor + __attribute__((unused)), + const struct action_work_item *work_item, + struct action_work_subitem *item) { int ret = 0; const char *session_name; enum lttng_action_status action_status; struct ltt_session *session; lttng_snapshot_output default_snapshot_output; - const struct lttng_snapshot_output *snapshot_output = - &default_snapshot_output; + const struct lttng_snapshot_output *snapshot_output = &default_snapshot_output; enum lttng_error_code cmd_ret; struct lttng_action *action = item->action; default_snapshot_output.max_size = UINT64_MAX; + lttng::urcu::read_lock_guard read_lock; + /* * Validate if, at the moment the action was queued, the target session * existed. If not, skip the action altogether. */ if (!item->context.session_id.is_set) { - DBG("Session was not present at the moment the work item was enqueued for %s` action of trigger `%s`", - get_action_name(action), - get_trigger_name(work_item->trigger)); + DBG("Session was not present at the moment the work item was enqueued for `%s` action of trigger `%s`", + get_action_name(action), + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); - ret = 0; goto end; } - action_status = lttng_action_snapshot_session_get_session_name( - action, &session_name); + action_status = lttng_action_snapshot_session_get_session_name(action, &session_name); if (action_status != LTTNG_ACTION_STATUS_OK) { - ERR("Failed to get session name from `%s` action", - get_action_name(action)); + ERR("Failed to get session name from `%s` action", get_action_name(action)); ret = -1; goto end; } - action_status = lttng_action_snapshot_session_get_output( - action, &snapshot_output); - if (action_status != LTTNG_ACTION_STATUS_OK && - action_status != LTTNG_ACTION_STATUS_UNSET) { - ERR("Failed to get output from `%s` action", - get_action_name(action)); + action_status = lttng_action_snapshot_session_get_output(action, &snapshot_output); + if (action_status != LTTNG_ACTION_STATUS_OK && action_status != LTTNG_ACTION_STATUS_UNSET) { + ERR("Failed to get output from `%s` action", get_action_name(action)); ret = -1; goto end; } session_lock_list(); - session = session_find_by_name(session_name); + session = session_find_by_id(LTTNG_OPTIONAL_GET(item->context.session_id)); if (!session) { DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`", - session_name, get_action_name(action), - get_trigger_name(work_item->trigger)); + session_name, + get_action_name(action), + get_trigger_name(work_item->trigger)); lttng_action_increase_execution_failure_count(action); goto error_unlock_list; } - /* - * Check if the session id is the same as when the work item was - * enqueued. - */ - if (session->id != LTTNG_OPTIONAL_GET(item->context.session_id)) { - DBG("Session id for session `%s` (id: %" PRIu64 - " is not the same that was sampled (id: %" PRIu64 - " at the moment the work item was enqueued for %s` action of trigger `%s`", - session_name, session->id, - LTTNG_OPTIONAL_GET(item->context.session_id), - get_action_name(action), - get_trigger_name(work_item->trigger)); - ret = 0; - goto error_unlock_list; + session_lock(session); + if (session->destroyed) { + DBG("Session `%s` with id = %" PRIu64 + " is flagged as destroyed. Skipping: action = `%s`, trigger = `%s`", + session->name, + session->id, + get_action_name(action), + get_trigger_name(work_item->trigger)); + goto error_unlock_session; } - session_lock(session); if (!is_trigger_allowed_for_session(work_item->trigger, session)) { - goto error_dispose_session; + goto error_unlock_session; } cmd_ret = (lttng_error_code) cmd_snapshot_record(session, snapshot_output, 0); switch (cmd_ret) { case LTTNG_OK: DBG("Successfully recorded snapshot of session `%s` on behalf of trigger `%s`", - session_name, get_trigger_name(work_item->trigger)); + session_name, + get_trigger_name(work_item->trigger)); break; default: WARN("Failed to record snapshot of session `%s` on behalf of trigger `%s`: %s", - session_name, get_trigger_name(work_item->trigger), - lttng_strerror(-cmd_ret)); + session_name, + get_trigger_name(work_item->trigger), + lttng_strerror(-cmd_ret)); lttng_action_increase_execution_failure_count(action); break; } -error_dispose_session: +error_unlock_session: session_unlock(session); session_put(session); error_unlock_list: @@ -660,17 +652,18 @@ end: return ret; } -static int action_executor_list_handler(struct action_executor *executor, - const struct action_work_item *work_item, - struct action_work_subitem *item) +static int action_executor_list_handler(struct action_executor *executor __attribute__((unused)), + const struct action_work_item *work_item + __attribute__((unused)), + struct action_work_subitem *item __attribute__((unused))) { ERR("Execution of a list action by the action executor should never occur"); abort(); } static int action_executor_generic_handler(struct action_executor *executor, - const struct action_work_item *work_item, - struct action_work_subitem *item) + const struct action_work_item *work_item, + struct action_work_subitem *item) { int ret; struct lttng_action *action = item->action; @@ -681,46 +674,48 @@ static int action_executor_generic_handler(struct action_executor *executor, lttng_action_increase_execution_request_count(action); if (!lttng_action_should_execute(action)) { DBG("Policy prevented execution of action `%s` of trigger `%s` action work item %" PRIu64, - get_action_name(action), - get_trigger_name(work_item->trigger), - work_item->id); + get_action_name(action), + get_trigger_name(work_item->trigger), + work_item->id); ret = 0; goto end; } lttng_action_increase_execution_count(action); DBG("Executing action `%s` of trigger `%s` action work item %" PRIu64, - get_action_name(action), - get_trigger_name(work_item->trigger), - work_item->id); + get_action_name(action), + get_trigger_name(work_item->trigger), + work_item->id); ret = action_executors[action_type](executor, work_item, item); end: return ret; } static int action_work_item_execute(struct action_executor *executor, - struct action_work_item *work_item) + struct action_work_item *work_item) { int ret; size_t count, i; DBG("Starting execution of action work item %" PRIu64 " of trigger `%s`", - work_item->id, get_trigger_name(work_item->trigger)); + work_item->id, + get_trigger_name(work_item->trigger)); count = lttng_dynamic_array_get_count(&work_item->subitems); for (i = 0; i < count; i++) { struct action_work_subitem *item; - item = (action_work_subitem *) lttng_dynamic_array_get_element(&work_item->subitems, i); - ret = action_executor_generic_handler( - executor, work_item, item); + item = (action_work_subitem *) lttng_dynamic_array_get_element(&work_item->subitems, + i); + ret = action_executor_generic_handler(executor, work_item, item); if (ret) { goto end; } } end: DBG("Completed execution of action work item %" PRIu64 " of trigger `%s`", - work_item->id, get_trigger_name(work_item->trigger)); + work_item->id, + get_trigger_name(work_item->trigger)); return ret; } @@ -739,8 +734,7 @@ static void *action_executor_thread(void *_data) LTTNG_ASSERT(executor); - health_register(the_health_sessiond, - HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR); + health_register(the_health_sessiond, HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR); rcu_register_thread(); rcu_thread_online(); @@ -755,16 +749,15 @@ static void *action_executor_thread(void *_data) if (executor->work.pending_count == 0) { health_poll_entry(); DBG("No work items enqueued, entering wait"); - pthread_cond_wait(&executor->work.cond, - &executor->work.lock); + pthread_cond_wait(&executor->work.cond, &executor->work.lock); DBG("Woke-up from wait"); health_poll_exit(); continue; } /* Pop item from front of the list with work lock held. */ - work_item = cds_list_first_entry(&executor->work.list, - struct action_work_item, list_node); + work_item = cds_list_first_entry( + &executor->work.list, struct action_work_item, list_node); cds_list_del(&work_item->list_node); executor->work.pending_count--; @@ -777,19 +770,21 @@ static void *action_executor_thread(void *_data) /* Execute item only if a trigger is registered. */ lttng_trigger_lock(work_item->trigger); if (!lttng_trigger_is_registered(work_item->trigger)) { - const char *trigger_name = NULL; + const char *trigger_name = nullptr; uid_t trigger_owner_uid; enum lttng_trigger_status trigger_status; trigger_name = get_trigger_name(work_item->trigger); - trigger_status = lttng_trigger_get_owner_uid( - work_item->trigger, &trigger_owner_uid); + trigger_status = + lttng_trigger_get_owner_uid(work_item->trigger, &trigger_owner_uid); LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK); - DBG("Work item skipped since the associated trigger is no longer registered: work item id = %" PRIu64 ", trigger name = '%s', trigger owner uid = %d", - work_item->id, trigger_name, - (int) trigger_owner_uid); + DBG("Work item skipped since the associated trigger is no longer registered: work item id = %" PRIu64 + ", trigger name = `%s`, trigger owner uid = %d", + work_item->id, + trigger_name, + (int) trigger_owner_uid); ret = 0; goto skip_execute; } @@ -819,7 +814,7 @@ static void *action_executor_thread(void *_data) rcu_unregister_thread(); health_unregister(the_health_sessiond); - return NULL; + return nullptr; } static bool shutdown_action_executor_thread(void *_data) @@ -844,23 +839,24 @@ static void clean_up_action_executor_thread(void *_data) free(executor); } -struct action_executor *action_executor_create( - struct notification_thread_handle *handle) +struct action_executor *action_executor_create(struct notification_thread_handle *handle) { - struct action_executor *executor = (action_executor *) zmalloc(sizeof(*executor)); + struct action_executor *executor = zmalloc(); if (!executor) { goto end; } CDS_INIT_LIST_HEAD(&executor->work.list); - pthread_cond_init(&executor->work.cond, NULL); - pthread_mutex_init(&executor->work.lock, NULL); + pthread_cond_init(&executor->work.cond, nullptr); + pthread_mutex_init(&executor->work.lock, nullptr); executor->notification_thread_handle = handle; executor->thread = lttng_thread_create(THREAD_NAME, - action_executor_thread, shutdown_action_executor_thread, - clean_up_action_executor_thread, executor); + action_executor_thread, + shutdown_action_executor_thread, + clean_up_action_executor_thread, + executor); end: return executor; } @@ -874,17 +870,15 @@ void action_executor_destroy(struct action_executor *executor) pthread_mutex_lock(&executor->work.lock); if (executor->work.pending_count != 0) { WARN("%" PRIu64 - " trigger action%s still queued for execution and will be discarded", - executor->work.pending_count, - executor->work.pending_count == 1 ? " is" : - "s are"); + " trigger action%s still queued for execution and will be discarded", + executor->work.pending_count, + executor->work.pending_count == 1 ? " is" : "s are"); } - cds_list_for_each_entry_safe ( - work_item, tmp, &executor->work.list, list_node) { - WARN("Discarding action work item %" PRIu64 - " associated to trigger `%s`", - work_item->id, get_trigger_name(work_item->trigger)); + cds_list_for_each_entry_safe (work_item, tmp, &executor->work.list, list_node) { + WARN("Discarding action work item %" PRIu64 " associated to trigger `%s`", + work_item->id, + get_trigger_name(work_item->trigger)); cds_list_del(&work_item->list_node); action_work_item_destroy(work_item); } @@ -893,12 +887,12 @@ void action_executor_destroy(struct action_executor *executor) } /* RCU read-lock must be held by the caller. */ -enum action_executor_status action_executor_enqueue_trigger( - struct action_executor *executor, - struct lttng_trigger *trigger, - struct lttng_evaluation *evaluation, - const struct lttng_credentials *object_creds, - struct notification_client_list *client_list) +enum action_executor_status +action_executor_enqueue_trigger(struct action_executor *executor, + struct lttng_trigger *trigger, + struct lttng_evaluation *evaluation, + const struct lttng_credentials *object_creds, + struct notification_client_list *client_list) { int ret; enum action_executor_status executor_status = ACTION_EXECUTOR_STATUS_OK; @@ -907,29 +901,30 @@ enum action_executor_status action_executor_enqueue_trigger( bool signal = false; LTTNG_ASSERT(trigger); + ASSERT_RCU_READ_LOCKED(); pthread_mutex_lock(&executor->work.lock); /* Check for queue overflow. */ if (executor->work.pending_count >= MAX_QUEUED_WORK_COUNT) { /* Most likely spammy, remove if it is the case. */ DBG("Refusing to enqueue action for trigger (overflow): trigger name = `%s`, work item id = %" PRIu64, - get_trigger_name(trigger), work_item_id); + get_trigger_name(trigger), + work_item_id); executor_status = ACTION_EXECUTOR_STATUS_OVERFLOW; goto error_unlock; } - work_item = (action_work_item *) zmalloc(sizeof(*work_item)); + work_item = zmalloc(); if (!work_item) { - PERROR("Failed to allocate action executor work item: trigger name = '%s'", - get_trigger_name(trigger)); + PERROR("Failed to allocate action executor work item: trigger name = `%s`", + get_trigger_name(trigger)); executor_status = ACTION_EXECUTOR_STATUS_ERROR; goto error_unlock; } lttng_trigger_get(trigger); if (client_list) { - const bool reference_acquired = - notification_client_list_get(client_list); + const bool reference_acquired = notification_client_list_get(client_list); LTTNG_ASSERT(reference_acquired); } @@ -939,7 +934,7 @@ enum action_executor_status action_executor_enqueue_trigger( /* Ownership transferred to the work item. */ work_item->evaluation = evaluation; - evaluation = NULL; + evaluation = nullptr; work_item->client_list = client_list; work_item->object_creds.is_set = !!object_creds; @@ -951,14 +946,13 @@ enum action_executor_status action_executor_enqueue_trigger( /* Build the array of action work subitems for the passed trigger. */ lttng_dynamic_array_init(&work_item->subitems, - sizeof(struct action_work_subitem), - action_work_subitem_destructor); + sizeof(struct action_work_subitem), + action_work_subitem_destructor); - ret = populate_subitem_array_from_trigger( - trigger, &work_item->subitems); + ret = populate_subitem_array_from_trigger(trigger, &work_item->subitems); if (ret) { ERR("Failed to populate work item sub items on behalf of trigger: trigger name = `%s`", - get_trigger_name(trigger)); + get_trigger_name(trigger)); executor_status = ACTION_EXECUTOR_STATUS_ERROR; goto error_unlock; } @@ -966,7 +960,8 @@ enum action_executor_status action_executor_enqueue_trigger( cds_list_add_tail(&work_item->list_node, &executor->work.list); executor->work.pending_count++; DBG("Enqueued action for trigger: trigger name = `%s`, work item id = %" PRIu64, - get_trigger_name(trigger), work_item_id); + get_trigger_name(trigger), + work_item_id); signal = true; error_unlock: @@ -980,14 +975,14 @@ error_unlock: } static int add_action_to_subitem_array(struct lttng_action *action, - struct lttng_dynamic_array *subitems) + struct lttng_dynamic_array *subitems) { int ret = 0; enum lttng_action_type type = lttng_action_get_type(action); - const char *session_name = NULL; + const char *session_name = nullptr; enum lttng_action_status status; struct action_work_subitem subitem = { - .action = NULL, + .action = nullptr, .context = { .session_id = LTTNG_OPTIONAL_INIT_UNSET, }, @@ -997,19 +992,10 @@ static int add_action_to_subitem_array(struct lttng_action *action, LTTNG_ASSERT(subitems); if (type == LTTNG_ACTION_TYPE_LIST) { - unsigned int count, i; - - status = lttng_action_list_get_count(action, &count); - LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK); - - for (i = 0; i < count; i++) { - struct lttng_action *inner_action = NULL; - - inner_action = lttng_action_list_borrow_mutable_at_index( - action, i); + for (auto inner_action : lttng::ctl::action_list_view(action)) { LTTNG_ASSERT(inner_action); - ret = add_action_to_subitem_array( - inner_action, subitems); + + ret = add_action_to_subitem_array(inner_action, subitems); if (ret) { goto end; } @@ -1027,23 +1013,19 @@ static int add_action_to_subitem_array(struct lttng_action *action, case LTTNG_ACTION_TYPE_NOTIFY: break; case LTTNG_ACTION_TYPE_START_SESSION: - status = lttng_action_start_session_get_session_name( - action, &session_name); + status = lttng_action_start_session_get_session_name(action, &session_name); LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK); break; case LTTNG_ACTION_TYPE_STOP_SESSION: - status = lttng_action_stop_session_get_session_name( - action, &session_name); + status = lttng_action_stop_session_get_session_name(action, &session_name); LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK); break; case LTTNG_ACTION_TYPE_ROTATE_SESSION: - status = lttng_action_rotate_session_get_session_name( - action, &session_name); + status = lttng_action_rotate_session_get_session_name(action, &session_name); LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK); break; case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION: - status = lttng_action_snapshot_session_get_session_name( - action, &session_name); + status = lttng_action_snapshot_session_get_session_name(action, &session_name); LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK); break; case LTTNG_ACTION_TYPE_LIST: @@ -1061,7 +1043,7 @@ static int add_action_to_subitem_array(struct lttng_action *action, * now we leave the decision to skip to the action executor for sake of * simplicity and consistency. */ - if (session_name != NULL) { + if (session_name != nullptr) { uint64_t session_id; /* @@ -1079,8 +1061,7 @@ static int add_action_to_subitem_array(struct lttng_action *action, * execution time. */ if (sample_session_id_by_name(session_name, &session_id)) { - LTTNG_OPTIONAL_SET(&subitem.context.session_id, - session_id); + LTTNG_OPTIONAL_SET(&subitem.context.session_id, session_id); } } @@ -1101,7 +1082,7 @@ end: } static int populate_subitem_array_from_trigger(struct lttng_trigger *trigger, - struct lttng_dynamic_array *subitems) + struct lttng_dynamic_array *subitems) { struct lttng_action *action;