+
+static int add_action_to_subitem_array(struct lttng_action *action,
+ struct lttng_dynamic_array *subitems)
+{
+ int ret;
+ enum lttng_action_type type = lttng_action_get_type(action);
+ const char *session_name = NULL;
+ enum lttng_action_status status;
+ struct action_work_subitem subitem = {
+ .action = NULL,
+ .context = {
+ .session_id = LTTNG_OPTIONAL_INIT_UNSET,
+ },
+ };
+
+ assert(action);
+ assert(subitems);
+
+ if (type == LTTNG_ACTION_TYPE_GROUP) {
+ unsigned int count, i;
+
+ status = lttng_action_group_get_count(action, &count);
+ assert(status == LTTNG_ACTION_STATUS_OK);
+
+ for (i = 0; i < count; i++) {
+ struct lttng_action *inner_action = NULL;
+
+ inner_action = lttng_action_group_borrow_mutable_at_index(
+ action, i);
+ assert(inner_action);
+ ret = add_action_to_subitem_array(
+ inner_action, subitems);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ /*
+ * Go directly to the end since there is no need to add the
+ * group action by itself to the subitems array.
+ */
+ goto end;
+ }
+
+ /* Gather execution context. */
+ switch (type) {
+ case LTTNG_ACTION_TYPE_NOTIFY:
+ break;
+ case LTTNG_ACTION_TYPE_START_SESSION:
+ status = lttng_action_start_session_get_session_name(
+ action, &session_name);
+ assert(status == LTTNG_ACTION_STATUS_OK);
+ break;
+ case LTTNG_ACTION_TYPE_STOP_SESSION:
+ status = lttng_action_stop_session_get_session_name(
+ action, &session_name);
+ assert(status == LTTNG_ACTION_STATUS_OK);
+ break;
+ case LTTNG_ACTION_TYPE_ROTATE_SESSION:
+ status = lttng_action_rotate_session_get_session_name(
+ action, &session_name);
+ assert(status == LTTNG_ACTION_STATUS_OK);
+ break;
+ case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
+ status = lttng_action_snapshot_session_get_session_name(
+ action, &session_name);
+ assert(status == LTTNG_ACTION_STATUS_OK);
+ break;
+ case LTTNG_ACTION_TYPE_GROUP:
+ case LTTNG_ACTION_TYPE_UNKNOWN:
+ /* Fallthrough */
+ default:
+ abort();
+ break;
+ }
+
+ /*
+ * Fetch the session execution context info as needed.
+ * Note that we could decide to not add an action for which we know the
+ * execution will not happen (i.e no session exists for that name). For
+ * now we leave the decision to skip to the action executor for sake of
+ * simplicity and consistency.
+ */
+ if (session_name != NULL) {
+ struct ltt_session *session = NULL;
+
+ session_lock_list();
+ session = session_find_by_name(session_name);
+ if (session) {
+ LTTNG_OPTIONAL_SET(&subitem.context.session_id,
+ session->id);
+ session_put(session);
+ }
+
+ session_unlock_list();
+ }
+
+ /* Get a reference to the action. */
+ lttng_action_get(action);
+ subitem.action = action;
+
+ ret = lttng_dynamic_array_add_element(subitems, &subitem);
+ if (ret) {
+ ERR("Failed to add work subitem to the subitem array");
+ lttng_action_put(action);
+ ret = -1;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static int populate_subitem_array_from_trigger(struct lttng_trigger *trigger,
+ struct lttng_dynamic_array *subitems)
+{
+ struct lttng_action *action;
+
+ action = lttng_trigger_get_action(trigger);
+ assert(action);
+
+ return add_action_to_subitem_array(action, subitems);
+}