Fix: sessiond: rotation thread: fatal error when not finding a session
[lttng-tools.git] / src / bin / lttng-sessiond / timer.cpp
CommitLineData
d086f507 1/*
ab5be9fa
MJ
2 * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
3 * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
d086f507 4 *
ab5be9fa 5 * SPDX-License-Identifier: GPL-2.0-only
d086f507 6 *
d086f507
JD
7 */
8
9#define _LGPL_SOURCE
d086f507
JD
10#include <inttypes.h>
11#include <signal.h>
12
8e319828 13#include "timer.h"
d086f507
JD
14#include "health-sessiond.h"
15#include "rotation-thread.h"
bc26e826 16#include "thread.h"
d086f507 17
92816cc3
JG
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
22
23#define UINT_TO_PTR(value) \
24 ({ \
a0377dfe 25 LTTNG_ASSERT(value <= UINTPTR_MAX); \
92816cc3
JG
26 (void *) (uintptr_t) value; \
27 })
28#define PTR_TO_UINT(ptr) ((uintptr_t) ptr)
29
30/*
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
34 * exclusion.
35 */
d086f507 36static
92816cc3
JG
37struct timer_signal_data {
38 /* Thread managing signals. */
39 pthread_t tid;
40 int qs_done;
41 pthread_mutex_t lock;
42} timer_signal = {
d086f507
JD
43 .tid = 0,
44 .qs_done = 0,
45 .lock = PTHREAD_MUTEX_INITIALIZER,
46};
47
48/*
49 * Set custom signal mask to current thread.
50 */
51static
52void setmask(sigset_t *mask)
53{
54 int ret;
55
56 ret = sigemptyset(mask);
57 if (ret) {
58 PERROR("sigemptyset");
59 }
92816cc3 60 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_QS);
d086f507
JD
61 if (ret) {
62 PERROR("sigaddset teardown");
63 }
64 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_EXIT);
65 if (ret) {
66 PERROR("sigaddset exit");
67 }
92816cc3 68 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK);
d88744a4 69 if (ret) {
92816cc3 70 PERROR("sigaddset pending rotation check");
d88744a4 71 }
92816cc3 72 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION);
259c2674 73 if (ret) {
92816cc3 74 PERROR("sigaddset scheduled rotation");
259c2674 75 }
d086f507
JD
76}
77
78/*
92816cc3 79 * This is the same function as timer_signal_thread_qs, when it
d086f507
JD
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.
82 */
83static
92816cc3 84void timer_signal_thread_qs(unsigned int signr)
d086f507
JD
85{
86 sigset_t pending_set;
87 int ret;
88
89 /*
90 * We need to be the only thread interacting with the thread
91 * that manages signals for teardown synchronization.
92 */
93 pthread_mutex_lock(&timer_signal.lock);
94
95 /* Ensure we don't have any signal queued for this session. */
96 for (;;) {
97 ret = sigemptyset(&pending_set);
98 if (ret == -1) {
99 PERROR("sigemptyset");
100 }
101 ret = sigpending(&pending_set);
102 if (ret == -1) {
103 PERROR("sigpending");
104 }
105 if (!sigismember(&pending_set, signr)) {
106 break;
107 }
108 caa_cpu_relax();
109 }
110
111 /*
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.
115 */
116 cmm_smp_mb();
117 CMM_STORE_SHARED(timer_signal.qs_done, 0);
118 cmm_smp_mb();
119
120 /*
92816cc3 121 * Kill with LTTNG_SESSIOND_SIG_QS, so signal management thread
d086f507
JD
122 * wakes up.
123 */
92816cc3 124 kill(getpid(), LTTNG_SESSIOND_SIG_QS);
d086f507
JD
125
126 while (!CMM_LOAD_SHARED(timer_signal.qs_done)) {
127 caa_cpu_relax();
128 }
129 cmm_smp_mb();
130
131 pthread_mutex_unlock(&timer_signal.lock);
132}
133
134/*
135 * Start a timer on a session that will fire at a given interval
136 * (timer_interval_us) and fire a given signal (signal).
137 *
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).
140 */
141static
c7031a2c 142int timer_start(timer_t *timer_id, struct ltt_session *session,
d086f507
JD
143 unsigned int timer_interval_us, int signal, bool one_shot)
144{
145 int ret = 0, delete_ret;
f79ead11 146 struct sigevent sev = {};
d086f507
JD
147 struct itimerspec its;
148
d086f507
JD
149 sev.sigev_notify = SIGEV_SIGNAL;
150 sev.sigev_signo = signal;
c7031a2c 151 sev.sigev_value.sival_ptr = session;
92816cc3 152 ret = timer_create(CLOCK_MONOTONIC, &sev, timer_id);
d086f507
JD
153 if (ret == -1) {
154 PERROR("timer_create");
155 goto end;
156 }
157
158 its.it_value.tv_sec = timer_interval_us / 1000000;
159 its.it_value.tv_nsec = (timer_interval_us % 1000000) * 1000;
160 if (one_shot) {
161 its.it_interval.tv_sec = 0;
162 its.it_interval.tv_nsec = 0;
163 } else {
164 its.it_interval.tv_sec = its.it_value.tv_sec;
165 its.it_interval.tv_nsec = its.it_value.tv_nsec;
166 }
167
168 ret = timer_settime(*timer_id, 0, &its, NULL);
169 if (ret == -1) {
170 PERROR("timer_settime");
171 goto error_destroy_timer;
172 }
173 goto end;
174
175error_destroy_timer:
176 delete_ret = timer_delete(*timer_id);
177 if (delete_ret == -1) {
178 PERROR("timer_delete");
179 }
180
181end:
182 return ret;
183}
184
185static
92816cc3 186int timer_stop(timer_t *timer_id, int signal)
d086f507
JD
187{
188 int ret = 0;
189
190 ret = timer_delete(*timer_id);
191 if (ret == -1) {
192 PERROR("timer_delete");
193 goto end;
194 }
195
92816cc3 196 timer_signal_thread_qs(signal);
d086f507
JD
197 *timer_id = 0;
198end:
199 return ret;
200}
201
92816cc3 202int timer_session_rotation_pending_check_start(struct ltt_session *session,
d88744a4
JD
203 unsigned int interval_us)
204{
205 int ret;
206
c7031a2c
JG
207 if (!session_get(session)) {
208 ret = -1;
209 goto end;
210 }
92816cc3
JG
211 DBG("Enabling session rotation pending check timer on session %" PRIu64,
212 session->id);
d88744a4
JD
213 /*
214 * We arm this timer in a one-shot mode so we don't have to disable it
92816cc3
JG
215 * explicitly (which could deadlock if the timer thread is blocked
216 * writing in the rotation_timer_pipe).
217 *
d88744a4 218 * Instead, we re-arm it if needed after the rotation_pending check as
92816cc3
JG
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.
d88744a4 221 */
92816cc3 222 ret = timer_start(&session->rotation_pending_check_timer,
c7031a2c 223 session, interval_us,
92816cc3 224 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK,
d88744a4
JD
225 /* one-shot */ true);
226 if (ret == 0) {
92816cc3 227 session->rotation_pending_check_timer_enabled = true;
d88744a4 228 }
c7031a2c 229end:
d88744a4
JD
230 return ret;
231}
232
233/*
92816cc3 234 * Call with session and session_list locks held.
d88744a4 235 */
92816cc3 236int timer_session_rotation_pending_check_stop(struct ltt_session *session)
d88744a4
JD
237{
238 int ret;
239
a0377dfe
FD
240 LTTNG_ASSERT(session);
241 LTTNG_ASSERT(session->rotation_pending_check_timer_enabled);
d88744a4 242
92816cc3
JG
243 DBG("Disabling session rotation pending check timer on session %" PRIu64,
244 session->id);
245 ret = timer_stop(&session->rotation_pending_check_timer,
246 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK);
d88744a4 247 if (ret == -1) {
92816cc3 248 ERR("Failed to stop rotate_pending_check timer");
259c2674 249 } else {
92816cc3 250 session->rotation_pending_check_timer_enabled = false;
c7031a2c
JG
251 /*
252 * The timer's reference to the session can be released safely.
253 */
254 session_put(session);
259c2674
JD
255 }
256 return ret;
257}
258
92816cc3
JG
259/*
260 * Call with session and session_list locks held.
261 */
262int timer_session_rotation_schedule_timer_start(struct ltt_session *session,
259c2674
JD
263 unsigned int interval_us)
264{
265 int ret;
266
c7031a2c
JG
267 if (!session_get(session)) {
268 ret = -1;
269 goto end;
270 }
2a1135fa
JG
271 DBG("Enabling scheduled rotation timer on session \"%s\" (%ui %s)", session->name,
272 interval_us, USEC_UNIT);
c7031a2c 273 ret = timer_start(&session->rotation_schedule_timer, session,
92816cc3
JG
274 interval_us, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION,
275 /* one-shot */ false);
259c2674
JD
276 if (ret < 0) {
277 goto end;
278 }
92816cc3 279 session->rotation_schedule_timer_enabled = true;
259c2674
JD
280end:
281 return ret;
282}
283
284/*
92816cc3 285 * Call with session and session_list locks held.
259c2674 286 */
92816cc3 287int timer_session_rotation_schedule_timer_stop(struct ltt_session *session)
259c2674
JD
288{
289 int ret = 0;
290
a0377dfe 291 LTTNG_ASSERT(session);
259c2674 292
92816cc3 293 if (!session->rotation_schedule_timer_enabled) {
259c2674
JD
294 goto end;
295 }
296
92816cc3
JG
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);
259c2674 300 if (ret < 0) {
92816cc3 301 ERR("Failed to stop scheduled rotation timer of session \"%s\"",
259c2674
JD
302 session->name);
303 goto end;
d88744a4
JD
304 }
305
92816cc3 306 session->rotation_schedule_timer_enabled = false;
c7031a2c
JG
307 /* The timer's reference to the session can be released safely. */
308 session_put(session);
259c2674
JD
309 ret = 0;
310end:
311 return ret;
d88744a4
JD
312}
313
d086f507
JD
314/*
315 * Block the RT signals for the entire process. It must be called from the
316 * sessiond main before creating the threads
317 */
92816cc3 318int timer_signal_init(void)
d086f507
JD
319{
320 int ret;
321 sigset_t mask;
322
323 /* Block signal for entire process, so only our thread processes it. */
324 setmask(&mask);
325 ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
326 if (ret) {
327 errno = ret;
328 PERROR("pthread_sigmask");
329 return -1;
330 }
331 return 0;
332}
333
334/*
335 * This thread is the sighandler for the timer signals.
336 */
bc26e826
JG
337static
338void *thread_timer(void *data)
d086f507
JD
339{
340 int signr;
341 sigset_t mask;
342 siginfo_t info;
7966af57 343 struct timer_thread_parameters *ctx = (timer_thread_parameters *) data;
d086f507
JD
344
345 rcu_register_thread();
346 rcu_thread_online();
347
412d7227 348 health_register(the_health_sessiond, HEALTH_SESSIOND_TYPE_TIMER);
d086f507
JD
349 health_code_update();
350
351 /* Only self thread will receive signal mask. */
352 setmask(&mask);
353 CMM_STORE_SHARED(timer_signal.tid, pthread_self());
354
355 while (1) {
356 health_code_update();
357
358 health_poll_entry();
359 signr = sigwaitinfo(&mask, &info);
360 health_poll_exit();
361
362 /*
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.
366 */
367 if (signr == -1) {
368 if (errno != EINTR) {
369 PERROR("sigwaitinfo");
370 }
371 continue;
92816cc3 372 } else if (signr == LTTNG_SESSIOND_SIG_QS) {
d086f507
JD
373 cmm_smp_mb();
374 CMM_STORE_SHARED(timer_signal.qs_done, 1);
375 cmm_smp_mb();
d086f507
JD
376 } else if (signr == LTTNG_SESSIOND_SIG_EXIT) {
377 goto end;
92816cc3 378 } else if (signr == LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK) {
c7031a2c
JG
379 struct ltt_session *session =
380 (struct ltt_session *) info.si_value.sival_ptr;
381
92816cc3
JG
382 rotation_thread_enqueue_job(ctx->rotation_thread_job_queue,
383 ROTATION_THREAD_JOB_TYPE_CHECK_PENDING_ROTATION,
c7031a2c 384 session);
92816cc3
JG
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,
c7031a2c
JG
388 (struct ltt_session *) info.si_value.sival_ptr);
389 /*
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
393 * still fire.
394 */
d086f507 395 } else {
bd0514a5 396 ERR("Unexpected signal %d", info.si_signo);
d086f507
JD
397 }
398 }
399
400end:
bd0514a5 401 DBG("Thread exit");
412d7227 402 health_unregister(the_health_sessiond);
d086f507
JD
403 rcu_thread_offline();
404 rcu_unregister_thread();
405 return NULL;
406}
92816cc3 407
bc26e826
JG
408static
409bool shutdown_timer_thread(void *data)
410{
411 return kill(getpid(), LTTNG_SESSIOND_SIG_EXIT) == 0;
412}
413
414bool launch_timer_thread(
415 struct timer_thread_parameters *timer_thread_parameters)
92816cc3 416{
bc26e826
JG
417 struct lttng_thread *thread;
418
419 thread = lttng_thread_create("Timer",
420 thread_timer,
421 shutdown_timer_thread,
422 NULL,
423 timer_thread_parameters);
424 if (!thread) {
425 goto error;
426 }
427 lttng_thread_put(thread);
428 return true;
429error:
430 return false;
92816cc3 431}
This page took 0.061334 seconds and 4 git commands to generate.