X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fsessiond-timer.c;h=0d500aa5522ae92bd41a645dc587cd05c44faba7;hp=d7aaca0f11fd5c8b379b39020530d581c53ef769;hb=d88744a44aa5f2ca90ab87946692b9eed3120641;hpb=5c408ad8ef08a226c018702aca969536f36ac4e5 diff --git a/src/bin/lttng-sessiond/sessiond-timer.c b/src/bin/lttng-sessiond/sessiond-timer.c index d7aaca0f1..0d500aa55 100644 --- a/src/bin/lttng-sessiond/sessiond-timer.c +++ b/src/bin/lttng-sessiond/sessiond-timer.c @@ -51,6 +51,10 @@ void setmask(sigset_t *mask) if (ret) { PERROR("sigaddset exit"); } + ret = sigaddset(mask, LTTNG_SESSIOND_SIG_ROTATE_PENDING); + if (ret) { + PERROR("sigaddset switch"); + } } /* @@ -179,6 +183,51 @@ end: return ret; } +int sessiond_timer_rotate_pending_start(struct ltt_session *session, + unsigned int interval_us) +{ + int ret; + + DBG("Enabling rotate pending timer on session %" PRIu64, session->id); + /* + * We arm this timer in a one-shot mode so we don't have to disable it + * explicitly (which could deadlock if the timer thread is blocked writing + * in the rotation_timer_pipe). + * Instead, we re-arm it if needed after the rotation_pending check as + * returned. Also, this timer is usually only needed once, so there is no + * need to go through the whole signal teardown scheme everytime. + */ + ret = session_timer_start(&session->rotate_relay_pending_timer, + session, interval_us, + LTTNG_SESSIOND_SIG_ROTATE_PENDING, + /* one-shot */ true); + if (ret == 0) { + session->rotate_relay_pending_timer_enabled = true; + } + + return ret; +} + +/* + * Stop and delete the channel's live timer. + * Called with session and session_list locks held. + */ +void sessiond_timer_rotate_pending_stop(struct ltt_session *session) +{ + int ret; + + assert(session); + + DBG("Disabling timer rotate pending on session %" PRIu64, session->id); + ret = session_timer_stop(&session->rotate_relay_pending_timer, + LTTNG_SESSIOND_SIG_ROTATE_PENDING); + if (ret == -1) { + ERR("Failed to stop rotate_pending timer"); + } + + session->rotate_relay_pending_timer_enabled = false; +} + /* * Block the RT signals for the entire process. It must be called from the * sessiond main before creating the threads @@ -199,6 +248,116 @@ int sessiond_timer_signal_init(void) return 0; } +/* + * Called with the rotation_timer_queue lock held. + * Return true if the same timer job already exists in the queue, false if not. + */ +static +bool check_duplicate_timer_job(struct timer_thread_parameters *ctx, + struct ltt_session *session, unsigned int signal) +{ + bool ret = false; + struct sessiond_rotation_timer *node; + + rcu_read_lock(); + cds_list_for_each_entry(node, &ctx->rotation_timer_queue->list, head) { + if (node->session_id == session->id && node->signal == signal) { + ret = true; + goto end; + } + } + +end: + rcu_read_unlock(); + return ret; +} + +/* + * Add the session ID and signal value to the rotation_timer_queue if it is + * not already there and wakeup the rotation thread. The rotation thread + * empties the whole queue everytime it is woken up. The event_pipe is + * non-blocking, if it would block, we just return because we know the + * rotation thread will be awaken anyway. + */ +static +int enqueue_timer_rotate_job(struct timer_thread_parameters *ctx, + struct ltt_session *session, unsigned int signal) +{ + int ret; + bool has_duplicate_timer_job; + char *c = "!"; + + pthread_mutex_lock(&ctx->rotation_timer_queue->lock); + has_duplicate_timer_job = check_duplicate_timer_job(ctx, session, + signal); + + if (!has_duplicate_timer_job) { + struct sessiond_rotation_timer *timer_data = NULL; + + timer_data = zmalloc(sizeof(struct sessiond_rotation_timer)); + if (!timer_data) { + PERROR("Allocation of timer data"); + goto error; + } + timer_data->session_id = session->id; + timer_data->signal = signal; + cds_list_add_tail(&timer_data->head, + &ctx->rotation_timer_queue->list); + } else { + /* + * This timer job is already pending, we don't need to add + * it. + */ + pthread_mutex_unlock(&ctx->rotation_timer_queue->lock); + ret = 0; + goto end; + } + pthread_mutex_unlock(&ctx->rotation_timer_queue->lock); + + ret = lttng_write( + lttng_pipe_get_writefd(ctx->rotation_timer_queue->event_pipe), + c, 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) { + ret = 0; + goto end; + } + PERROR("Timer wakeup rotation thread"); + goto error; + } + + ret = 0; + goto end; + +error: + ret = -1; +end: + return ret; +} + +/* + * Ask the rotation thread to check if the last rotation started in this + * session is still pending on the relay. + */ +static +void relay_rotation_pending_timer(struct timer_thread_parameters *ctx, + int sig, siginfo_t *si) +{ + int ret; + struct ltt_session *session = si->si_value.sival_ptr; + assert(session); + + ret = enqueue_timer_rotate_job(ctx, session, LTTNG_SESSIOND_SIG_ROTATE_PENDING); + if (ret) { + PERROR("wakeup rotate pipe"); + } +} + /* * This thread is the sighandler for the timer signals. */ @@ -244,6 +403,8 @@ void *sessiond_timer_thread(void *data) DBG("Signal timer metadata thread teardown"); } else if (signr == LTTNG_SESSIOND_SIG_EXIT) { goto end; + } else if (signr == LTTNG_SESSIOND_SIG_ROTATE_PENDING) { + relay_rotation_pending_timer(ctx, info.si_signo, &info); } else { ERR("Unexpected signal %d\n", info.si_signo); }