+ return ret;
+}
+
+/* Call with the session and session_list locks held. */
+static
+int launch_session_rotation(struct ltt_session *session)
+{
+ int ret;
+ struct lttng_rotate_session_return rotation_return;
+
+ DBG("[rotation-thread] Launching scheduled time-based rotation on session \"%s\"",
+ session->name);
+
+ ret = cmd_rotate_session(session, &rotation_return);
+ if (ret == LTTNG_OK) {
+ DBG("[rotation-thread] Scheduled time-based rotation successfully launched on session \"%s\"",
+ session->name);
+ } else {
+ /* Don't consider errors as fatal. */
+ DBG("[rotation-thread] Scheduled time-based rotation aborted for session %s: %s",
+ session->name, lttng_strerror(ret));
+ }
+ return 0;
+}
+
+static
+int run_job(struct rotation_thread_job *job, struct ltt_session *session,
+ struct notification_thread_handle *notification_thread_handle)
+{
+ int ret;
+
+ switch (job->type) {
+ case ROTATION_THREAD_JOB_TYPE_SCHEDULED_ROTATION:
+ ret = launch_session_rotation(session);
+ break;
+ case ROTATION_THREAD_JOB_TYPE_CHECK_PENDING_ROTATION:
+ ret = check_session_rotation_pending(session,
+ notification_thread_handle);
+ break;
+ default:
+ abort();
+ }
+ return ret;
+}
+
+static
+int handle_job_queue(struct rotation_thread_handle *handle,
+ struct rotation_thread *state,
+ struct rotation_thread_timer_queue *queue)
+{
+ int ret = 0;
+
+ for (;;) {
+ struct ltt_session *session;
+ struct rotation_thread_job *job;
+
+ /* Take the queue lock only to pop an element from the list. */
+ pthread_mutex_lock(&queue->lock);
+ if (cds_list_empty(&queue->list)) {
+ pthread_mutex_unlock(&queue->lock);
+ break;
+ }
+ job = cds_list_first_entry(&queue->list,
+ typeof(*job), head);
+ cds_list_del(&job->head);
+ pthread_mutex_unlock(&queue->lock);
+
+ session_lock_list();
+ session = job->session;
+ if (!session) {
+ DBG("[rotation-thread] Session \"%s\" not found",
+ session->name);
+ /*
+ * This is a non-fatal error, and we cannot report it to
+ * the user (timer), so just print the error and
+ * continue the processing.
+ *
+ * While the timer thread will purge pending signals for
+ * a session on the session's destruction, it is
+ * possible for a job targeting that session to have
+ * already been queued before it was destroyed.
+ */
+ session_unlock_list();
+ free(job);
+ session_put(session);
+ continue;
+ }
+
+ session_lock(session);
+ ret = run_job(job, session, handle->notification_thread_handle);
+ session_unlock(session);
+ /* Release reference held by the job. */
+ session_put(session);
+ session_unlock_list();
+ free(job);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static
+int handle_condition(const struct lttng_condition *condition,
+ const struct lttng_evaluation *evaluation,
+ struct notification_thread_handle *notification_thread_handle)
+{
+ int ret = 0;
+ const char *condition_session_name = NULL;
+ enum lttng_condition_type condition_type;
+ enum lttng_condition_status condition_status;
+ enum lttng_evaluation_status evaluation_status;
+ uint64_t consumed;
+ struct ltt_session *session;
+
+ condition_type = lttng_condition_get_type(condition);
+
+ if (condition_type != LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE) {
+ ret = -1;
+ ERR("[rotation-thread] Condition type and session usage type are not the same");
+ goto end;
+ }
+
+ /* Fetch info to test */
+ condition_status = lttng_condition_session_consumed_size_get_session_name(
+ condition, &condition_session_name);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ ERR("[rotation-thread] Session name could not be fetched");
+ ret = -1;
+ goto end;
+ }
+ evaluation_status = lttng_evaluation_session_consumed_size_get_consumed_size(evaluation,
+ &consumed);
+ if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
+ ERR("[rotation-thread] Failed to get evaluation");
+ ret = -1;
+ goto end;
+ }
+
+ session_lock_list();
+ session = session_find_by_name(condition_session_name);
+ if (!session) {
+ ret = -1;
+ session_unlock_list();
+ ERR("[rotation-thread] Session \"%s\" not found",
+ condition_session_name);
+ goto end;
+ }
+ session_lock(session);