+/*
+ * Called with the rotation_thread_timer_queue lock held.
+ * Return true if the same timer job already exists in the queue, false if not.
+ */
+static
+bool timer_job_exists(const struct rotation_thread_timer_queue *queue,
+ enum rotation_thread_job_type job_type,
+ struct ltt_session *session)
+{
+ bool exists = false;
+ struct rotation_thread_job *job;
+
+ cds_list_for_each_entry(job, &queue->list, head) {
+ if (job->session == session && job->type == job_type) {
+ exists = true;
+ goto end;
+ }
+ }
+end:
+ return exists;
+}
+
+void rotation_thread_enqueue_job(struct rotation_thread_timer_queue *queue,
+ enum rotation_thread_job_type job_type,
+ struct ltt_session *session)
+{
+ int ret;
+ const char * const dummy = "!";
+ struct rotation_thread_job *job = NULL;
+ const char *job_type_str = get_job_type_str(job_type);
+
+ pthread_mutex_lock(&queue->lock);
+ if (timer_job_exists(queue, job_type, session)) {
+ /*
+ * This timer job is already pending, we don't need to add
+ * it.
+ */
+ goto end;
+ }
+
+ job = zmalloc(sizeof(struct rotation_thread_job));
+ if (!job) {
+ PERROR("Failed to allocate rotation thread job of type \"%s\" for session \"%s\"",
+ job_type_str, session->name);
+ goto end;
+ }
+ /* No reason for this to fail as the caller must hold a reference. */
+ (void) session_get(session);
+
+ job->session = session;
+ job->type = job_type;
+ cds_list_add_tail(&job->head, &queue->list);
+
+ ret = lttng_write(lttng_pipe_get_writefd(queue->event_pipe), dummy,
+ 1);
+ if (ret < 0) {
+ /*
+ * We do not want to block in the timer handler, the job has
+ * been enqueued in the list, the wakeup pipe is probably full,
+ * the job will be processed when the rotation_thread catches
+ * up.
+ */
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /*
+ * Not an error, but would be surprising and indicate
+ * that the rotation thread can't keep up with the
+ * current load.
+ */
+ DBG("Wake-up pipe of rotation thread job queue is full");
+ goto end;
+ }
+ PERROR("Failed to wake-up the rotation thread after pushing a job of type \"%s\" for session \"%s\"",
+ job_type_str, session->name);
+ goto end;
+ }
+
+end:
+ pthread_mutex_unlock(&queue->lock);
+}
+