2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
3 * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * SPDX-License-Identifier: GPL-2.0-only
15 #include "health-sessiond.h"
16 #include "rotation-thread.h"
19 #define LTTNG_SESSIOND_SIG_QS SIGRTMIN + 10
20 #define LTTNG_SESSIOND_SIG_EXIT SIGRTMIN + 11
21 #define LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK SIGRTMIN + 12
22 #define LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION SIGRTMIN + 13
24 #define UINT_TO_PTR(value) \
26 assert(value <= UINTPTR_MAX); \
27 (void *) (uintptr_t) value; \
29 #define PTR_TO_UINT(ptr) ((uintptr_t) ptr)
32 * Handle timer teardown race wrt memory free of private data by sessiond
33 * signals are handled by a single thread, which permits a synchronization
34 * point between handling of each signal. Internal lock ensures mutual
38 struct timer_signal_data
{
39 /* Thread managing signals. */
46 .lock
= PTHREAD_MUTEX_INITIALIZER
,
50 * Set custom signal mask to current thread.
53 void setmask(sigset_t
*mask
)
57 ret
= sigemptyset(mask
);
59 PERROR("sigemptyset");
61 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_QS
);
63 PERROR("sigaddset teardown");
65 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_EXIT
);
67 PERROR("sigaddset exit");
69 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
);
71 PERROR("sigaddset pending rotation check");
73 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
);
75 PERROR("sigaddset scheduled rotation");
80 * This is the same function as timer_signal_thread_qs, when it
81 * returns, it means that no timer signr is currently pending or being handled
82 * by the timer thread. This cannot be called from the timer thread.
85 void timer_signal_thread_qs(unsigned int signr
)
91 * We need to be the only thread interacting with the thread
92 * that manages signals for teardown synchronization.
94 pthread_mutex_lock(&timer_signal
.lock
);
96 /* Ensure we don't have any signal queued for this session. */
98 ret
= sigemptyset(&pending_set
);
100 PERROR("sigemptyset");
102 ret
= sigpending(&pending_set
);
104 PERROR("sigpending");
106 if (!sigismember(&pending_set
, signr
)) {
113 * From this point, no new signal handler will be fired that would try to
114 * access "session". However, we still need to wait for any currently
115 * executing handler to complete.
118 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
122 * Kill with LTTNG_SESSIOND_SIG_QS, so signal management thread
125 kill(getpid(), LTTNG_SESSIOND_SIG_QS
);
127 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
132 pthread_mutex_unlock(&timer_signal
.lock
);
136 * Start a timer on a session that will fire at a given interval
137 * (timer_interval_us) and fire a given signal (signal).
139 * Returns a negative value on error, 0 if a timer was created, and
140 * a positive value if no timer was created (not an error).
143 int timer_start(timer_t
*timer_id
, struct ltt_session
*session
,
144 unsigned int timer_interval_us
, int signal
, bool one_shot
)
146 int ret
= 0, delete_ret
;
148 struct itimerspec its
;
150 sev
.sigev_notify
= SIGEV_SIGNAL
;
151 sev
.sigev_signo
= signal
;
152 sev
.sigev_value
.sival_ptr
= session
;
153 ret
= timer_create(CLOCK_MONOTONIC
, &sev
, timer_id
);
155 PERROR("timer_create");
159 its
.it_value
.tv_sec
= timer_interval_us
/ 1000000;
160 its
.it_value
.tv_nsec
= (timer_interval_us
% 1000000) * 1000;
162 its
.it_interval
.tv_sec
= 0;
163 its
.it_interval
.tv_nsec
= 0;
165 its
.it_interval
.tv_sec
= its
.it_value
.tv_sec
;
166 its
.it_interval
.tv_nsec
= its
.it_value
.tv_nsec
;
169 ret
= timer_settime(*timer_id
, 0, &its
, NULL
);
171 PERROR("timer_settime");
172 goto error_destroy_timer
;
177 delete_ret
= timer_delete(*timer_id
);
178 if (delete_ret
== -1) {
179 PERROR("timer_delete");
187 int timer_stop(timer_t
*timer_id
, int signal
)
191 ret
= timer_delete(*timer_id
);
193 PERROR("timer_delete");
197 timer_signal_thread_qs(signal
);
203 int timer_session_rotation_pending_check_start(struct ltt_session
*session
,
204 unsigned int interval_us
)
208 if (!session_get(session
)) {
212 DBG("Enabling session rotation pending check timer on session %" PRIu64
,
215 * We arm this timer in a one-shot mode so we don't have to disable it
216 * explicitly (which could deadlock if the timer thread is blocked
217 * writing in the rotation_timer_pipe).
219 * Instead, we re-arm it if needed after the rotation_pending check as
220 * returned. Also, this timer is usually only needed once, so there is
221 * no need to go through the whole signal teardown scheme everytime.
223 ret
= timer_start(&session
->rotation_pending_check_timer
,
224 session
, interval_us
,
225 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
,
226 /* one-shot */ true);
228 session
->rotation_pending_check_timer_enabled
= true;
235 * Call with session and session_list locks held.
237 int timer_session_rotation_pending_check_stop(struct ltt_session
*session
)
242 assert(session
->rotation_pending_check_timer_enabled
);
244 DBG("Disabling session rotation pending check timer on session %" PRIu64
,
246 ret
= timer_stop(&session
->rotation_pending_check_timer
,
247 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
);
249 ERR("Failed to stop rotate_pending_check timer");
251 session
->rotation_pending_check_timer_enabled
= false;
253 * The timer's reference to the session can be released safely.
255 session_put(session
);
261 * Call with session and session_list locks held.
263 int timer_session_rotation_schedule_timer_start(struct ltt_session
*session
,
264 unsigned int interval_us
)
268 if (!session_get(session
)) {
272 DBG("Enabling scheduled rotation timer on session \"%s\" (%ui %s)", session
->name
,
273 interval_us
, USEC_UNIT
);
274 ret
= timer_start(&session
->rotation_schedule_timer
, session
,
275 interval_us
, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
,
276 /* one-shot */ false);
280 session
->rotation_schedule_timer_enabled
= true;
286 * Call with session and session_list locks held.
288 int timer_session_rotation_schedule_timer_stop(struct ltt_session
*session
)
294 if (!session
->rotation_schedule_timer_enabled
) {
298 DBG("Disabling scheduled rotation timer on session %s", session
->name
);
299 ret
= timer_stop(&session
->rotation_schedule_timer
,
300 LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
);
302 ERR("Failed to stop scheduled rotation timer of session \"%s\"",
307 session
->rotation_schedule_timer_enabled
= false;
308 /* The timer's reference to the session can be released safely. */
309 session_put(session
);
316 * Block the RT signals for the entire process. It must be called from the
317 * sessiond main before creating the threads
319 int timer_signal_init(void)
324 /* Block signal for entire process, so only our thread processes it. */
326 ret
= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
329 PERROR("pthread_sigmask");
336 * This thread is the sighandler for the timer signals.
339 void *thread_timer(void *data
)
344 struct timer_thread_parameters
*ctx
= data
;
346 rcu_register_thread();
349 health_register(health_sessiond
, HEALTH_SESSIOND_TYPE_TIMER
);
350 health_code_update();
352 /* Only self thread will receive signal mask. */
354 CMM_STORE_SHARED(timer_signal
.tid
, pthread_self());
357 health_code_update();
360 signr
= sigwaitinfo(&mask
, &info
);
364 * NOTE: cascading conditions are used instead of a switch case
365 * since the use of SIGRTMIN in the definition of the signals'
366 * values prevents the reduction to an integer constant.
369 if (errno
!= EINTR
) {
370 PERROR("sigwaitinfo");
373 } else if (signr
== LTTNG_SESSIOND_SIG_QS
) {
375 CMM_STORE_SHARED(timer_signal
.qs_done
, 1);
377 } else if (signr
== LTTNG_SESSIOND_SIG_EXIT
) {
379 } else if (signr
== LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
) {
380 struct ltt_session
*session
=
381 (struct ltt_session
*) info
.si_value
.sival_ptr
;
383 rotation_thread_enqueue_job(ctx
->rotation_thread_job_queue
,
384 ROTATION_THREAD_JOB_TYPE_CHECK_PENDING_ROTATION
,
386 } else if (signr
== LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
) {
387 rotation_thread_enqueue_job(ctx
->rotation_thread_job_queue
,
388 ROTATION_THREAD_JOB_TYPE_SCHEDULED_ROTATION
,
389 (struct ltt_session
*) info
.si_value
.sival_ptr
);
391 * The scheduled periodic rotation timer is not in
392 * "one-shot" mode. The reference to the session is not
393 * released since the timer is still enabled and can
397 ERR("Unexpected signal %d\n", info
.si_signo
);
402 DBG("[timer-thread] Exit");
403 health_unregister(health_sessiond
);
404 rcu_thread_offline();
405 rcu_unregister_thread();
410 bool shutdown_timer_thread(void *data
)
412 return kill(getpid(), LTTNG_SESSIOND_SIG_EXIT
) == 0;
415 bool launch_timer_thread(
416 struct timer_thread_parameters
*timer_thread_parameters
)
418 struct lttng_thread
*thread
;
420 thread
= lttng_thread_create("Timer",
422 shutdown_timer_thread
,
424 timer_thread_parameters
);
428 lttng_thread_put(thread
);