From: Jérémie Galarneau Date: Tue, 2 Oct 2018 18:06:17 +0000 (-0400) Subject: Rename sessiond-timer.[hc] to timer.[hc] X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=commitdiff_plain;h=8e319828707210e48a5f3e74495881594dba73e8;hp=92816cc33a1add3c8276839bd6335e17423577dd Rename sessiond-timer.[hc] to timer.[hc] There is no need to namespace the timer files as they are already contained withing the lttng-sessiond directory. Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index d57c63963..2e4b95dce 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -39,7 +39,7 @@ lttng_sessiond_SOURCES = utils.c utils.h \ sessiond-config.h sessiond-config.c \ rotate.h rotate.c \ rotation-thread.h rotation-thread.c \ - sessiond-timer.c sessiond-timer.h + timer.c timer.h if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \ diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 0d860236e..b1bcc10a5 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -57,7 +57,7 @@ #include "notification-thread-commands.h" #include "rotate.h" #include "rotation-thread.h" -#include "sessiond-timer.h" +#include "timer.h" #include "agent-thread.h" #include "cmd.h" diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index bd111029c..67d990027 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -81,7 +81,7 @@ #include "agent.h" #include "ht-cleanup.h" #include "sessiond-config.h" -#include "sessiond-timer.h" +#include "timer.h" static const char *help_msg = #ifdef LTTNG_EMBED_HELP diff --git a/src/bin/lttng-sessiond/rotation-thread.c b/src/bin/lttng-sessiond/rotation-thread.c index 5b0267952..2dfd97357 100644 --- a/src/bin/lttng-sessiond/rotation-thread.c +++ b/src/bin/lttng-sessiond/rotation-thread.c @@ -42,7 +42,7 @@ #include "rotate.h" #include "cmd.h" #include "session.h" -#include "sessiond-timer.h" +#include "timer.h" #include "notification-thread-commands.h" #include diff --git a/src/bin/lttng-sessiond/sessiond-timer.c b/src/bin/lttng-sessiond/sessiond-timer.c deleted file mode 100644 index b8cf4825a..000000000 --- a/src/bin/lttng-sessiond/sessiond-timer.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (C) 2017 - Julien Desfossez - * Copyright (C) 2018 - Jérémie Galarneau - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License, version 2 only, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _LGPL_SOURCE -#include -#include -#include - -#include "sessiond-timer.h" -#include "health-sessiond.h" -#include "rotation-thread.h" - -#define LTTNG_SESSIOND_SIG_QS SIGRTMIN + 10 -#define LTTNG_SESSIOND_SIG_EXIT SIGRTMIN + 11 -#define LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK SIGRTMIN + 12 -#define LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION SIGRTMIN + 13 - -#define UINT_TO_PTR(value) \ - ({ \ - assert(value <= UINTPTR_MAX); \ - (void *) (uintptr_t) value; \ - }) -#define PTR_TO_UINT(ptr) ((uintptr_t) ptr) - -/* - * Handle timer teardown race wrt memory free of private data by sessiond - * signals are handled by a single thread, which permits a synchronization - * point between handling of each signal. Internal lock ensures mutual - * exclusion. - */ -static -struct timer_signal_data { - /* Thread managing signals. */ - pthread_t tid; - int qs_done; - pthread_mutex_t lock; -} timer_signal = { - .tid = 0, - .qs_done = 0, - .lock = PTHREAD_MUTEX_INITIALIZER, -}; - -/* - * Set custom signal mask to current thread. - */ -static -void setmask(sigset_t *mask) -{ - int ret; - - ret = sigemptyset(mask); - if (ret) { - PERROR("sigemptyset"); - } - ret = sigaddset(mask, LTTNG_SESSIOND_SIG_QS); - if (ret) { - PERROR("sigaddset teardown"); - } - ret = sigaddset(mask, LTTNG_SESSIOND_SIG_EXIT); - if (ret) { - PERROR("sigaddset exit"); - } - ret = sigaddset(mask, LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK); - if (ret) { - PERROR("sigaddset pending rotation check"); - } - ret = sigaddset(mask, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION); - if (ret) { - PERROR("sigaddset scheduled rotation"); - } -} - -/* - * This is the same function as timer_signal_thread_qs, when it - * returns, it means that no timer signr is currently pending or being handled - * by the timer thread. This cannot be called from the timer thread. - */ -static -void timer_signal_thread_qs(unsigned int signr) -{ - sigset_t pending_set; - int ret; - - /* - * We need to be the only thread interacting with the thread - * that manages signals for teardown synchronization. - */ - pthread_mutex_lock(&timer_signal.lock); - - /* Ensure we don't have any signal queued for this session. */ - for (;;) { - ret = sigemptyset(&pending_set); - if (ret == -1) { - PERROR("sigemptyset"); - } - ret = sigpending(&pending_set); - if (ret == -1) { - PERROR("sigpending"); - } - if (!sigismember(&pending_set, signr)) { - break; - } - caa_cpu_relax(); - } - - /* - * From this point, no new signal handler will be fired that would try to - * access "session". However, we still need to wait for any currently - * executing handler to complete. - */ - cmm_smp_mb(); - CMM_STORE_SHARED(timer_signal.qs_done, 0); - cmm_smp_mb(); - - /* - * Kill with LTTNG_SESSIOND_SIG_QS, so signal management thread - * wakes up. - */ - kill(getpid(), LTTNG_SESSIOND_SIG_QS); - - while (!CMM_LOAD_SHARED(timer_signal.qs_done)) { - caa_cpu_relax(); - } - cmm_smp_mb(); - - pthread_mutex_unlock(&timer_signal.lock); -} - -/* - * Start a timer on a session that will fire at a given interval - * (timer_interval_us) and fire a given signal (signal). - * - * Returns a negative value on error, 0 if a timer was created, and - * a positive value if no timer was created (not an error). - */ -static -int timer_start(timer_t *timer_id, uint64_t session_id, - unsigned int timer_interval_us, int signal, bool one_shot) -{ - int ret = 0, delete_ret; - struct sigevent sev; - struct itimerspec its; - - sev.sigev_notify = SIGEV_SIGNAL; - sev.sigev_signo = signal; - sev.sigev_value.sival_ptr = UINT_TO_PTR(session_id); - ret = timer_create(CLOCK_MONOTONIC, &sev, timer_id); - if (ret == -1) { - PERROR("timer_create"); - goto end; - } - - its.it_value.tv_sec = timer_interval_us / 1000000; - its.it_value.tv_nsec = (timer_interval_us % 1000000) * 1000; - if (one_shot) { - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; - } else { - its.it_interval.tv_sec = its.it_value.tv_sec; - its.it_interval.tv_nsec = its.it_value.tv_nsec; - } - - ret = timer_settime(*timer_id, 0, &its, NULL); - if (ret == -1) { - PERROR("timer_settime"); - goto error_destroy_timer; - } - goto end; - -error_destroy_timer: - delete_ret = timer_delete(*timer_id); - if (delete_ret == -1) { - PERROR("timer_delete"); - } - -end: - return ret; -} - -static -int timer_stop(timer_t *timer_id, int signal) -{ - int ret = 0; - - ret = timer_delete(*timer_id); - if (ret == -1) { - PERROR("timer_delete"); - goto end; - } - - timer_signal_thread_qs(signal); - *timer_id = 0; -end: - return ret; -} - -int timer_session_rotation_pending_check_start(struct ltt_session *session, - unsigned int interval_us) -{ - int ret; - - DBG("Enabling session rotation pending check 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 = timer_start(&session->rotation_pending_check_timer, - session->id, interval_us, - LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK, - /* one-shot */ true); - if (ret == 0) { - session->rotation_pending_check_timer_enabled = true; - } - - return ret; -} - -/* - * Call with session and session_list locks held. - */ -int timer_session_rotation_pending_check_stop(struct ltt_session *session) -{ - int ret; - - assert(session); - - DBG("Disabling session rotation pending check timer on session %" PRIu64, - session->id); - ret = timer_stop(&session->rotation_pending_check_timer, - LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK); - if (ret == -1) { - ERR("Failed to stop rotate_pending_check timer"); - } else { - session->rotation_pending_check_timer_enabled = false; - } - return ret; -} - -/* - * Call with session and session_list locks held. - */ -int timer_session_rotation_schedule_timer_start(struct ltt_session *session, - unsigned int interval_us) -{ - int ret; - - DBG("Enabling scheduled rotation timer on session \"%s\" (%ui µs)", session->name, - interval_us); - ret = timer_start(&session->rotation_schedule_timer, session->id, - interval_us, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION, - /* one-shot */ false); - if (ret < 0) { - goto end; - } - session->rotation_schedule_timer_enabled = true; -end: - return ret; -} - -/* - * Call with session and session_list locks held. - */ -int timer_session_rotation_schedule_timer_stop(struct ltt_session *session) -{ - int ret = 0; - - assert(session); - - if (!session->rotation_schedule_timer_enabled) { - goto end; - } - - DBG("Disabling scheduled rotation timer on session %s", session->name); - ret = timer_stop(&session->rotation_schedule_timer, - LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION); - if (ret < 0) { - ERR("Failed to stop scheduled rotation timer of session \"%s\"", - session->name); - goto end; - } - - session->rotation_schedule_timer_enabled = false; - ret = 0; -end: - return ret; -} - -/* - * Block the RT signals for the entire process. It must be called from the - * sessiond main before creating the threads - */ -int timer_signal_init(void) -{ - int ret; - sigset_t mask; - - /* Block signal for entire process, so only our thread processes it. */ - setmask(&mask); - ret = pthread_sigmask(SIG_BLOCK, &mask, NULL); - if (ret) { - errno = ret; - PERROR("pthread_sigmask"); - return -1; - } - return 0; -} - -/* - * This thread is the sighandler for the timer signals. - */ -void *timer_thread_func(void *data) -{ - int signr; - sigset_t mask; - siginfo_t info; - struct timer_thread_parameters *ctx = data; - - rcu_register_thread(); - rcu_thread_online(); - - health_register(health_sessiond, HEALTH_SESSIOND_TYPE_TIMER); - health_code_update(); - - /* Only self thread will receive signal mask. */ - setmask(&mask); - CMM_STORE_SHARED(timer_signal.tid, pthread_self()); - - while (1) { - health_code_update(); - - health_poll_entry(); - signr = sigwaitinfo(&mask, &info); - health_poll_exit(); - - /* - * NOTE: cascading conditions are used instead of a switch case - * since the use of SIGRTMIN in the definition of the signals' - * values prevents the reduction to an integer constant. - */ - if (signr == -1) { - if (errno != EINTR) { - PERROR("sigwaitinfo"); - } - continue; - } else if (signr == LTTNG_SESSIOND_SIG_QS) { - cmm_smp_mb(); - CMM_STORE_SHARED(timer_signal.qs_done, 1); - cmm_smp_mb(); - } else if (signr == LTTNG_SESSIOND_SIG_EXIT) { - goto end; - } else if (signr == LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK) { - rotation_thread_enqueue_job(ctx->rotation_thread_job_queue, - ROTATION_THREAD_JOB_TYPE_CHECK_PENDING_ROTATION, - /* session_id */ PTR_TO_UINT(info.si_value.sival_ptr)); - } else if (signr == LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION) { - rotation_thread_enqueue_job(ctx->rotation_thread_job_queue, - ROTATION_THREAD_JOB_TYPE_SCHEDULED_ROTATION, - /* session_id */ PTR_TO_UINT(info.si_value.sival_ptr)); - } else { - ERR("Unexpected signal %d\n", info.si_signo); - } - } - -end: - DBG("[timer-thread] Exit"); - health_unregister(health_sessiond); - rcu_thread_offline(); - rcu_unregister_thread(); - return NULL; -} - -void timer_exit(void) -{ - kill(getpid(), LTTNG_SESSIOND_SIG_EXIT); -} diff --git a/src/bin/lttng-sessiond/sessiond-timer.h b/src/bin/lttng-sessiond/sessiond-timer.h deleted file mode 100644 index 83be4873c..000000000 --- a/src/bin/lttng-sessiond/sessiond-timer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2017 - Julien Desfossez - * Copyright (C) 2018 - Jérémie Galarneau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef SESSIOND_TIMER_H -#define SESSIOND_TIMER_H - -#include - -#include "session.h" - -struct timer_thread_parameters { - struct rotation_thread_timer_queue *rotation_thread_job_queue; -}; - -int timer_signal_init(void); -void *timer_thread_func(void *data); - -void timer_exit(void); - -/* Start a session's rotation pending check timer (one-shot mode). */ -int timer_session_rotation_pending_check_start(struct ltt_session *session, - unsigned int interval_us); -/* Stop a session's rotation pending check timer. */ -int timer_session_rotation_pending_check_stop(struct ltt_session *session); - -/* Start a session's rotation schedule timer. */ -int timer_session_rotation_schedule_timer_start(struct ltt_session *session, - unsigned int interval_us); -/* Stop a session's rotation schedule timer. */ -int timer_session_rotation_schedule_timer_stop(struct ltt_session *session); - -#endif /* SESSIOND_TIMER_H */ diff --git a/src/bin/lttng-sessiond/timer.c b/src/bin/lttng-sessiond/timer.c new file mode 100644 index 000000000..06d1d4a98 --- /dev/null +++ b/src/bin/lttng-sessiond/timer.c @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2017 - Julien Desfossez + * Copyright (C) 2018 - Jérémie Galarneau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _LGPL_SOURCE +#include +#include +#include + +#include "timer.h" +#include "health-sessiond.h" +#include "rotation-thread.h" + +#define LTTNG_SESSIOND_SIG_QS SIGRTMIN + 10 +#define LTTNG_SESSIOND_SIG_EXIT SIGRTMIN + 11 +#define LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK SIGRTMIN + 12 +#define LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION SIGRTMIN + 13 + +#define UINT_TO_PTR(value) \ + ({ \ + assert(value <= UINTPTR_MAX); \ + (void *) (uintptr_t) value; \ + }) +#define PTR_TO_UINT(ptr) ((uintptr_t) ptr) + +/* + * Handle timer teardown race wrt memory free of private data by sessiond + * signals are handled by a single thread, which permits a synchronization + * point between handling of each signal. Internal lock ensures mutual + * exclusion. + */ +static +struct timer_signal_data { + /* Thread managing signals. */ + pthread_t tid; + int qs_done; + pthread_mutex_t lock; +} timer_signal = { + .tid = 0, + .qs_done = 0, + .lock = PTHREAD_MUTEX_INITIALIZER, +}; + +/* + * Set custom signal mask to current thread. + */ +static +void setmask(sigset_t *mask) +{ + int ret; + + ret = sigemptyset(mask); + if (ret) { + PERROR("sigemptyset"); + } + ret = sigaddset(mask, LTTNG_SESSIOND_SIG_QS); + if (ret) { + PERROR("sigaddset teardown"); + } + ret = sigaddset(mask, LTTNG_SESSIOND_SIG_EXIT); + if (ret) { + PERROR("sigaddset exit"); + } + ret = sigaddset(mask, LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK); + if (ret) { + PERROR("sigaddset pending rotation check"); + } + ret = sigaddset(mask, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION); + if (ret) { + PERROR("sigaddset scheduled rotation"); + } +} + +/* + * This is the same function as timer_signal_thread_qs, when it + * returns, it means that no timer signr is currently pending or being handled + * by the timer thread. This cannot be called from the timer thread. + */ +static +void timer_signal_thread_qs(unsigned int signr) +{ + sigset_t pending_set; + int ret; + + /* + * We need to be the only thread interacting with the thread + * that manages signals for teardown synchronization. + */ + pthread_mutex_lock(&timer_signal.lock); + + /* Ensure we don't have any signal queued for this session. */ + for (;;) { + ret = sigemptyset(&pending_set); + if (ret == -1) { + PERROR("sigemptyset"); + } + ret = sigpending(&pending_set); + if (ret == -1) { + PERROR("sigpending"); + } + if (!sigismember(&pending_set, signr)) { + break; + } + caa_cpu_relax(); + } + + /* + * From this point, no new signal handler will be fired that would try to + * access "session". However, we still need to wait for any currently + * executing handler to complete. + */ + cmm_smp_mb(); + CMM_STORE_SHARED(timer_signal.qs_done, 0); + cmm_smp_mb(); + + /* + * Kill with LTTNG_SESSIOND_SIG_QS, so signal management thread + * wakes up. + */ + kill(getpid(), LTTNG_SESSIOND_SIG_QS); + + while (!CMM_LOAD_SHARED(timer_signal.qs_done)) { + caa_cpu_relax(); + } + cmm_smp_mb(); + + pthread_mutex_unlock(&timer_signal.lock); +} + +/* + * Start a timer on a session that will fire at a given interval + * (timer_interval_us) and fire a given signal (signal). + * + * Returns a negative value on error, 0 if a timer was created, and + * a positive value if no timer was created (not an error). + */ +static +int timer_start(timer_t *timer_id, uint64_t session_id, + unsigned int timer_interval_us, int signal, bool one_shot) +{ + int ret = 0, delete_ret; + struct sigevent sev; + struct itimerspec its; + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = signal; + sev.sigev_value.sival_ptr = UINT_TO_PTR(session_id); + ret = timer_create(CLOCK_MONOTONIC, &sev, timer_id); + if (ret == -1) { + PERROR("timer_create"); + goto end; + } + + its.it_value.tv_sec = timer_interval_us / 1000000; + its.it_value.tv_nsec = (timer_interval_us % 1000000) * 1000; + if (one_shot) { + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + } else { + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + } + + ret = timer_settime(*timer_id, 0, &its, NULL); + if (ret == -1) { + PERROR("timer_settime"); + goto error_destroy_timer; + } + goto end; + +error_destroy_timer: + delete_ret = timer_delete(*timer_id); + if (delete_ret == -1) { + PERROR("timer_delete"); + } + +end: + return ret; +} + +static +int timer_stop(timer_t *timer_id, int signal) +{ + int ret = 0; + + ret = timer_delete(*timer_id); + if (ret == -1) { + PERROR("timer_delete"); + goto end; + } + + timer_signal_thread_qs(signal); + *timer_id = 0; +end: + return ret; +} + +int timer_session_rotation_pending_check_start(struct ltt_session *session, + unsigned int interval_us) +{ + int ret; + + DBG("Enabling session rotation pending check 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 = timer_start(&session->rotation_pending_check_timer, + session->id, interval_us, + LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK, + /* one-shot */ true); + if (ret == 0) { + session->rotation_pending_check_timer_enabled = true; + } + + return ret; +} + +/* + * Call with session and session_list locks held. + */ +int timer_session_rotation_pending_check_stop(struct ltt_session *session) +{ + int ret; + + assert(session); + + DBG("Disabling session rotation pending check timer on session %" PRIu64, + session->id); + ret = timer_stop(&session->rotation_pending_check_timer, + LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK); + if (ret == -1) { + ERR("Failed to stop rotate_pending_check timer"); + } else { + session->rotation_pending_check_timer_enabled = false; + } + return ret; +} + +/* + * Call with session and session_list locks held. + */ +int timer_session_rotation_schedule_timer_start(struct ltt_session *session, + unsigned int interval_us) +{ + int ret; + + DBG("Enabling scheduled rotation timer on session \"%s\" (%ui µs)", session->name, + interval_us); + ret = timer_start(&session->rotation_schedule_timer, session->id, + interval_us, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION, + /* one-shot */ false); + if (ret < 0) { + goto end; + } + session->rotation_schedule_timer_enabled = true; +end: + return ret; +} + +/* + * Call with session and session_list locks held. + */ +int timer_session_rotation_schedule_timer_stop(struct ltt_session *session) +{ + int ret = 0; + + assert(session); + + if (!session->rotation_schedule_timer_enabled) { + goto end; + } + + DBG("Disabling scheduled rotation timer on session %s", session->name); + ret = timer_stop(&session->rotation_schedule_timer, + LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION); + if (ret < 0) { + ERR("Failed to stop scheduled rotation timer of session \"%s\"", + session->name); + goto end; + } + + session->rotation_schedule_timer_enabled = false; + ret = 0; +end: + return ret; +} + +/* + * Block the RT signals for the entire process. It must be called from the + * sessiond main before creating the threads + */ +int timer_signal_init(void) +{ + int ret; + sigset_t mask; + + /* Block signal for entire process, so only our thread processes it. */ + setmask(&mask); + ret = pthread_sigmask(SIG_BLOCK, &mask, NULL); + if (ret) { + errno = ret; + PERROR("pthread_sigmask"); + return -1; + } + return 0; +} + +/* + * This thread is the sighandler for the timer signals. + */ +void *timer_thread_func(void *data) +{ + int signr; + sigset_t mask; + siginfo_t info; + struct timer_thread_parameters *ctx = data; + + rcu_register_thread(); + rcu_thread_online(); + + health_register(health_sessiond, HEALTH_SESSIOND_TYPE_TIMER); + health_code_update(); + + /* Only self thread will receive signal mask. */ + setmask(&mask); + CMM_STORE_SHARED(timer_signal.tid, pthread_self()); + + while (1) { + health_code_update(); + + health_poll_entry(); + signr = sigwaitinfo(&mask, &info); + health_poll_exit(); + + /* + * NOTE: cascading conditions are used instead of a switch case + * since the use of SIGRTMIN in the definition of the signals' + * values prevents the reduction to an integer constant. + */ + if (signr == -1) { + if (errno != EINTR) { + PERROR("sigwaitinfo"); + } + continue; + } else if (signr == LTTNG_SESSIOND_SIG_QS) { + cmm_smp_mb(); + CMM_STORE_SHARED(timer_signal.qs_done, 1); + cmm_smp_mb(); + } else if (signr == LTTNG_SESSIOND_SIG_EXIT) { + goto end; + } else if (signr == LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK) { + rotation_thread_enqueue_job(ctx->rotation_thread_job_queue, + ROTATION_THREAD_JOB_TYPE_CHECK_PENDING_ROTATION, + /* session_id */ PTR_TO_UINT(info.si_value.sival_ptr)); + } else if (signr == LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION) { + rotation_thread_enqueue_job(ctx->rotation_thread_job_queue, + ROTATION_THREAD_JOB_TYPE_SCHEDULED_ROTATION, + /* session_id */ PTR_TO_UINT(info.si_value.sival_ptr)); + } else { + ERR("Unexpected signal %d\n", info.si_signo); + } + } + +end: + DBG("[timer-thread] Exit"); + health_unregister(health_sessiond); + rcu_thread_offline(); + rcu_unregister_thread(); + return NULL; +} + +void timer_exit(void) +{ + kill(getpid(), LTTNG_SESSIOND_SIG_EXIT); +} diff --git a/src/bin/lttng-sessiond/timer.h b/src/bin/lttng-sessiond/timer.h new file mode 100644 index 000000000..83be4873c --- /dev/null +++ b/src/bin/lttng-sessiond/timer.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 - Julien Desfossez + * Copyright (C) 2018 - Jérémie Galarneau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef SESSIOND_TIMER_H +#define SESSIOND_TIMER_H + +#include + +#include "session.h" + +struct timer_thread_parameters { + struct rotation_thread_timer_queue *rotation_thread_job_queue; +}; + +int timer_signal_init(void); +void *timer_thread_func(void *data); + +void timer_exit(void); + +/* Start a session's rotation pending check timer (one-shot mode). */ +int timer_session_rotation_pending_check_start(struct ltt_session *session, + unsigned int interval_us); +/* Stop a session's rotation pending check timer. */ +int timer_session_rotation_pending_check_stop(struct ltt_session *session); + +/* Start a session's rotation schedule timer. */ +int timer_session_rotation_schedule_timer_start(struct ltt_session *session, + unsigned int interval_us); +/* Stop a session's rotation schedule timer. */ +int timer_session_rotation_schedule_timer_stop(struct ltt_session *session); + +#endif /* SESSIOND_TIMER_H */