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
14 #include "health-sessiond.h"
15 #include "rotation-thread.h"
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)
31 * Handle timer teardown race wrt memory free of private data by sessiond
32 * signals are handled by a single thread, which permits a synchronization
33 * point between handling of each signal. Internal lock ensures mutual
37 struct timer_signal_data
{
38 /* Thread managing signals. */
45 .lock
= PTHREAD_MUTEX_INITIALIZER
,
49 * Set custom signal mask to current thread.
52 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.
84 void timer_signal_thread_qs(unsigned int signr
)
90 * We need to be the only thread interacting with the thread
91 * that manages signals for teardown synchronization.
93 pthread_mutex_lock(&timer_signal
.lock
);
95 /* Ensure we don't have any signal queued for this session. */
97 ret
= sigemptyset(&pending_set
);
99 PERROR("sigemptyset");
101 ret
= sigpending(&pending_set
);
103 PERROR("sigpending");
105 if (!sigismember(&pending_set
, signr
)) {
112 * From this point, no new signal handler will be fired that would try to
113 * access "session". However, we still need to wait for any currently
114 * executing handler to complete.
117 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
121 * Kill with LTTNG_SESSIOND_SIG_QS, so signal management thread
124 kill(getpid(), LTTNG_SESSIOND_SIG_QS
);
126 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
131 pthread_mutex_unlock(&timer_signal
.lock
);
135 * Start a timer on a session that will fire at a given interval
136 * (timer_interval_us) and fire a given signal (signal).
138 * Returns a negative value on error, 0 if a timer was created, and
139 * a positive value if no timer was created (not an error).
142 int timer_start(timer_t
*timer_id
, struct ltt_session
*session
,
143 unsigned int timer_interval_us
, int signal
, bool one_shot
)
145 int ret
= 0, delete_ret
;
146 struct sigevent sev
= {};
147 struct itimerspec its
;
149 sev
.sigev_notify
= SIGEV_SIGNAL
;
150 sev
.sigev_signo
= signal
;
151 sev
.sigev_value
.sival_ptr
= session
;
152 ret
= timer_create(CLOCK_MONOTONIC
, &sev
, timer_id
);
154 PERROR("timer_create");
158 its
.it_value
.tv_sec
= timer_interval_us
/ 1000000;
159 its
.it_value
.tv_nsec
= (timer_interval_us
% 1000000) * 1000;
161 its
.it_interval
.tv_sec
= 0;
162 its
.it_interval
.tv_nsec
= 0;
164 its
.it_interval
.tv_sec
= its
.it_value
.tv_sec
;
165 its
.it_interval
.tv_nsec
= its
.it_value
.tv_nsec
;
168 ret
= timer_settime(*timer_id
, 0, &its
, NULL
);
170 PERROR("timer_settime");
171 goto error_destroy_timer
;
176 delete_ret
= timer_delete(*timer_id
);
177 if (delete_ret
== -1) {
178 PERROR("timer_delete");
186 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
,
214 * We arm this timer in a one-shot mode so we don't have to disable it
215 * explicitly (which could deadlock if the timer thread is blocked
216 * writing in the rotation_timer_pipe).
218 * Instead, we re-arm it if needed after the rotation_pending check as
219 * returned. Also, this timer is usually only needed once, so there is
220 * no need to go through the whole signal teardown scheme everytime.
222 ret
= timer_start(&session
->rotation_pending_check_timer
,
223 session
, interval_us
,
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
,
245 ret
= timer_stop(&session
->rotation_pending_check_timer
,
246 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK
);
248 ERR("Failed to stop rotate_pending_check timer");
250 session
->rotation_pending_check_timer_enabled
= false;
252 * The timer's reference to the session can be released safely.
254 session_put(session
);
260 * Call with session and session_list locks held.
262 int timer_session_rotation_schedule_timer_start(struct ltt_session
*session
,
263 unsigned int interval_us
)
267 if (!session_get(session
)) {
271 DBG("Enabling scheduled rotation timer on session \"%s\" (%ui %s)", session
->name
,
272 interval_us
, USEC_UNIT
);
273 ret
= timer_start(&session
->rotation_schedule_timer
, session
,
274 interval_us
, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
,
275 /* one-shot */ false);
279 session
->rotation_schedule_timer_enabled
= true;
285 * Call with session and session_list locks held.
287 int timer_session_rotation_schedule_timer_stop(struct ltt_session
*session
)
291 LTTNG_ASSERT(session
);
293 if (!session
->rotation_schedule_timer_enabled
) {
297 DBG("Disabling scheduled rotation timer on session %s", session
->name
);
298 ret
= timer_stop(&session
->rotation_schedule_timer
,
299 LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION
);
301 ERR("Failed to stop scheduled rotation timer of session \"%s\"",
306 session
->rotation_schedule_timer_enabled
= false;
307 /* The timer's reference to the session can be released safely. */
308 session_put(session
);
315 * Block the RT signals for the entire process. It must be called from the
316 * sessiond main before creating the threads
318 int timer_signal_init(void)
323 /* Block signal for entire process, so only our thread processes it. */
325 ret
= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
328 PERROR("pthread_sigmask");
335 * This thread is the sighandler for the timer signals.
338 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();
409 bool shutdown_timer_thread(void *data
)
411 return kill(getpid(), LTTNG_SESSIOND_SIG_EXIT
) == 0;
414 bool launch_timer_thread(
415 struct timer_thread_parameters
*timer_thread_parameters
)
417 struct lttng_thread
*thread
;
419 thread
= lttng_thread_create("Timer",
421 shutdown_timer_thread
,
423 timer_thread_parameters
);
427 lttng_thread_put(thread
);