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