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
10 #include "health-sessiond.hpp"
11 #include "rotation-thread.hpp"
18 #define LTTNG_SESSIOND_SIG_QS SIGRTMIN + 10
19 #define LTTNG_SESSIOND_SIG_EXIT SIGRTMIN + 11
20 #define LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK SIGRTMIN + 12
21 #define LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION SIGRTMIN + 13
23 #define UINT_TO_PTR(value) \
25 LTTNG_ASSERT(value <= UINTPTR_MAX); \
26 (void *) (uintptr_t) value; \
28 #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
37 struct timer_signal_data
{
38 /* Thread managing signals. */
45 .lock
= PTHREAD_MUTEX_INITIALIZER
,
50 * Set custom signal mask to current thread.
52 static void setmask(sigset_t
*mask
)
56 ret
= sigemptyset(mask
);
58 PERROR("sigemptyset");
60 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_QS
);
62 PERROR("sigaddset teardown");
64 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_EXIT
);
66 PERROR("sigaddset exit");
68 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
);
70 PERROR("sigaddset pending rotation check");
72 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
);
74 PERROR("sigaddset scheduled rotation");
79 * This is the same function as timer_signal_thread_qs, when it
80 * returns, it means that no timer signr is currently pending or being handled
81 * by the timer thread. This cannot be called from the timer thread.
83 static void timer_signal_thread_qs(unsigned int signr
)
89 * We need to be the only thread interacting with the thread
90 * that manages signals for teardown synchronization.
92 pthread_mutex_lock(&timer_signal
.lock
);
94 /* Ensure we don't have any signal queued for this session. */
96 ret
= sigemptyset(&pending_set
);
98 PERROR("sigemptyset");
100 ret
= sigpending(&pending_set
);
102 PERROR("sigpending");
104 if (!sigismember(&pending_set
, signr
)) {
111 * From this point, no new signal handler will be fired that would try to
112 * access "session". However, we still need to wait for any currently
113 * executing handler to complete.
116 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
120 * Kill with LTTNG_SESSIOND_SIG_QS, so signal management thread
123 kill(getpid(), LTTNG_SESSIOND_SIG_QS
);
125 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
130 pthread_mutex_unlock(&timer_signal
.lock
);
134 * Start a timer on a session that will fire at a given interval
135 * (timer_interval_us) and fire a given signal (signal).
137 * Returns a negative value on error, 0 if a timer was created, and
138 * a positive value if no timer was created (not an error).
140 static int timer_start(timer_t
*timer_id
,
141 struct ltt_session
*session
,
142 unsigned int timer_interval_us
,
146 int ret
= 0, delete_ret
;
147 struct sigevent sev
= {};
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");
186 static int timer_stop(timer_t
*timer_id
, int signal
)
190 ret
= timer_delete(*timer_id
);
192 PERROR("timer_delete");
196 timer_signal_thread_qs(signal
);
202 int timer_session_rotation_pending_check_start(struct ltt_session
*session
,
203 unsigned int interval_us
)
207 if (!session_get(session
)) {
211 DBG("Enabling session rotation pending check timer on session %" PRIu64
, session
->id
);
213 * We arm this timer in a one-shot mode so we don't have to disable it
214 * explicitly (which could deadlock if the timer thread is blocked
215 * writing in the rotation_timer_pipe).
217 * Instead, we re-arm it if needed after the rotation_pending check as
218 * returned. Also, this timer is usually only needed once, so there is
219 * no need to go through the whole signal teardown scheme everytime.
221 ret
= timer_start(&session
->rotation_pending_check_timer
,
224 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
,
225 /* one-shot */ true);
227 session
->rotation_pending_check_timer_enabled
= true;
234 * Call with session and session_list locks held.
236 int timer_session_rotation_pending_check_stop(struct ltt_session
*session
)
240 LTTNG_ASSERT(session
);
241 LTTNG_ASSERT(session
->rotation_pending_check_timer_enabled
);
243 DBG("Disabling session rotation pending check timer on session %" PRIu64
, session
->id
);
244 ret
= timer_stop(&session
->rotation_pending_check_timer
,
245 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
);
247 ERR("Failed to stop rotate_pending_check timer");
249 session
->rotation_pending_check_timer_enabled
= false;
251 * The timer's reference to the session can be released safely.
253 session_put(session
);
259 * Call with session and session_list locks held.
261 int timer_session_rotation_schedule_timer_start(struct ltt_session
*session
,
262 unsigned int interval_us
)
266 if (!session_get(session
)) {
270 DBG("Enabling scheduled rotation timer on session \"%s\" (%ui %s)",
274 ret
= timer_start(&session
->rotation_schedule_timer
,
277 LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
,
278 /* one-shot */ false);
282 session
->rotation_schedule_timer_enabled
= true;
288 * Call with session and session_list locks held.
290 int timer_session_rotation_schedule_timer_stop(struct ltt_session
*session
)
294 LTTNG_ASSERT(session
);
296 if (!session
->rotation_schedule_timer_enabled
) {
300 DBG("Disabling scheduled rotation timer on session %s", session
->name
);
301 ret
= timer_stop(&session
->rotation_schedule_timer
, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
);
303 ERR("Failed to stop scheduled rotation timer of session \"%s\"", session
->name
);
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.
338 static void *thread_timer(void *data
)
343 struct timer_thread_parameters
*ctx
= (timer_thread_parameters
*) data
;
345 rcu_register_thread();
348 health_register(the_health_sessiond
, HEALTH_SESSIOND_TYPE_TIMER
);
349 health_code_update();
351 /* Only self thread will receive signal mask. */
353 CMM_STORE_SHARED(timer_signal
.tid
, pthread_self());
356 health_code_update();
359 signr
= sigwaitinfo(&mask
, &info
);
363 * NOTE: cascading conditions are used instead of a switch case
364 * since the use of SIGRTMIN in the definition of the signals'
365 * values prevents the reduction to an integer constant.
368 if (errno
!= EINTR
) {
369 PERROR("sigwaitinfo");
372 } else if (signr
== LTTNG_SESSIOND_SIG_QS
) {
374 CMM_STORE_SHARED(timer_signal
.qs_done
, 1);
376 } else if (signr
== LTTNG_SESSIOND_SIG_EXIT
) {
378 } else if (signr
== LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
) {
379 struct ltt_session
*session
=
380 (struct ltt_session
*) info
.si_value
.sival_ptr
;
382 rotation_thread_enqueue_job(ctx
->rotation_thread_job_queue
,
383 ROTATION_THREAD_JOB_TYPE_CHECK_PENDING_ROTATION
,
385 } else if (signr
== LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
) {
386 rotation_thread_enqueue_job(ctx
->rotation_thread_job_queue
,
387 ROTATION_THREAD_JOB_TYPE_SCHEDULED_ROTATION
,
388 (struct ltt_session
*) info
.si_value
.sival_ptr
);
390 * The scheduled periodic rotation timer is not in
391 * "one-shot" mode. The reference to the session is not
392 * released since the timer is still enabled and can
396 ERR("Unexpected signal %d", info
.si_signo
);
402 health_unregister(the_health_sessiond
);
403 rcu_thread_offline();
404 rcu_unregister_thread();
408 static bool shutdown_timer_thread(void *data
__attribute__((unused
)))
410 return kill(getpid(), LTTNG_SESSIOND_SIG_EXIT
) == 0;
413 bool launch_timer_thread(struct timer_thread_parameters
*timer_thread_parameters
)
415 struct lttng_thread
*thread
;
417 thread
= lttng_thread_create(
418 "Timer", thread_timer
, shutdown_timer_thread
, NULL
, timer_thread_parameters
);
422 lttng_thread_put(thread
);