sessiond: propagate the use of ltt_session::locked_ref
[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
c9e313bc
SM
10#include "health-sessiond.hpp"
11#include "rotation-thread.hpp"
12#include "thread.hpp"
28ab034a
JG
13#include "timer.hpp"
14
15#include <inttypes.h>
16#include <signal.h>
d086f507 17
5c7248cd
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)
92816cc3 22
5c7248cd
JG
23#define UINT_TO_PTR(value) \
24 ({ \
25 LTTNG_ASSERT((value) <= UINTPTR_MAX); \
26 (void *) (uintptr_t) (value); \
92816cc3 27 })
5c7248cd 28#define PTR_TO_UINT(ptr) ((uintptr_t) (ptr))
92816cc3 29
f1494934 30namespace {
92816cc3
JG
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 */
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};
f1494934 47} /* namespace */
d086f507
JD
48
49/*
50 * Set custom signal mask to current thread.
51 */
28ab034a 52static void setmask(sigset_t *mask)
d086f507
JD
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 */
28ab034a 83static void timer_signal_thread_qs(unsigned int signr)
d086f507
JD
84{
85 sigset_t pending_set;
86 int ret;
87
88 /*
89 * We need to be the only thread interacting with the thread
90 * that manages signals for teardown synchronization.
91 */
92 pthread_mutex_lock(&timer_signal.lock);
93
94 /* Ensure we don't have any signal queued for this session. */
95 for (;;) {
96 ret = sigemptyset(&pending_set);
97 if (ret == -1) {
98 PERROR("sigemptyset");
99 }
100 ret = sigpending(&pending_set);
101 if (ret == -1) {
102 PERROR("sigpending");
103 }
104 if (!sigismember(&pending_set, signr)) {
105 break;
106 }
107 caa_cpu_relax();
108 }
109
110 /*
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.
114 */
115 cmm_smp_mb();
116 CMM_STORE_SHARED(timer_signal.qs_done, 0);
117 cmm_smp_mb();
118
119 /*
92816cc3 120 * Kill with LTTNG_SESSIOND_SIG_QS, so signal management thread
d086f507
JD
121 * wakes up.
122 */
92816cc3 123 kill(getpid(), LTTNG_SESSIOND_SIG_QS);
d086f507
JD
124
125 while (!CMM_LOAD_SHARED(timer_signal.qs_done)) {
126 caa_cpu_relax();
127 }
128 cmm_smp_mb();
129
130 pthread_mutex_unlock(&timer_signal.lock);
131}
132
133/*
134 * Start a timer on a session that will fire at a given interval
135 * (timer_interval_us) and fire a given signal (signal).
136 *
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).
139 */
28ab034a
JG
140static int timer_start(timer_t *timer_id,
141 struct ltt_session *session,
142 unsigned int timer_interval_us,
143 int signal,
144 bool one_shot)
d086f507
JD
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
cd9adb8b 169 ret = timer_settime(*timer_id, 0, &its, nullptr);
d086f507
JD
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
28ab034a 186static int 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);
cd9adb8b 197 *timer_id = nullptr;
d086f507
JD
198end:
199 return ret;
200}
201
a0a4f314 202int timer_session_rotation_pending_check_start(const ltt_session::locked_ref& session,
28ab034a 203 unsigned int interval_us)
d88744a4
JD
204{
205 int ret;
206
a0a4f314 207 if (!session_get(&session.get())) {
c7031a2c
JG
208 ret = -1;
209 goto end;
210 }
a0a4f314 211
28ab034a 212 DBG("Enabling session rotation pending check timer on session %" PRIu64, 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,
a0a4f314 223 &session.get(),
28ab034a
JG
224 interval_us,
225 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK,
226 /* one-shot */ true);
d88744a4 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/*
a0a4f314 235 * Call with session_list lock held.
d88744a4 236 */
a0a4f314 237int timer_session_rotation_pending_check_stop(const ltt_session::locked_ref& session)
d88744a4
JD
238{
239 int ret;
240
a0a4f314 241 LTTNG_ASSERT(session->rotation_pending_check_timer_enabled);
d88744a4 242
a0a4f314
JG
243 DBG("Disabling session rotation pending check timer on session %" PRIu64, session->id);
244 ret = timer_stop(&session->rotation_pending_check_timer,
28ab034a 245 LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK);
d88744a4 246 if (ret == -1) {
92816cc3 247 ERR("Failed to stop rotate_pending_check timer");
259c2674 248 } else {
a0a4f314 249 session->rotation_pending_check_timer_enabled = false;
c7031a2c
JG
250 /*
251 * The timer's reference to the session can be released safely.
252 */
a0a4f314 253 session_put(&session.get());
259c2674 254 }
0038180d 255
259c2674
JD
256 return ret;
257}
258
92816cc3 259/*
a0a4f314 260 * Call with session_list lock held.
92816cc3 261 */
a0a4f314 262int timer_session_rotation_schedule_timer_start(const ltt_session::locked_ref& session,
28ab034a 263 unsigned int interval_us)
259c2674
JD
264{
265 int ret;
266
a0a4f314 267 if (!session_get(&session.get())) {
c7031a2c
JG
268 ret = -1;
269 goto end;
270 }
28ab034a
JG
271 DBG("Enabling scheduled rotation timer on session \"%s\" (%ui %s)",
272 session->name,
273 interval_us,
274 USEC_UNIT);
275 ret = timer_start(&session->rotation_schedule_timer,
a0a4f314 276 &session.get(),
28ab034a
JG
277 interval_us,
278 LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION,
279 /* one-shot */ false);
259c2674
JD
280 if (ret < 0) {
281 goto end;
282 }
92816cc3 283 session->rotation_schedule_timer_enabled = true;
259c2674
JD
284end:
285 return ret;
286}
287
288/*
92816cc3 289 * Call with session and session_list locks held.
259c2674 290 */
a0a4f314 291int timer_session_rotation_schedule_timer_stop(const ltt_session::locked_ref& session)
259c2674
JD
292{
293 int ret = 0;
294
92816cc3 295 if (!session->rotation_schedule_timer_enabled) {
259c2674
JD
296 goto end;
297 }
298
92816cc3 299 DBG("Disabling scheduled rotation timer on session %s", session->name);
28ab034a 300 ret = timer_stop(&session->rotation_schedule_timer, LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION);
259c2674 301 if (ret < 0) {
28ab034a 302 ERR("Failed to stop scheduled rotation timer of session \"%s\"", session->name);
259c2674 303 goto end;
d88744a4
JD
304 }
305
92816cc3 306 session->rotation_schedule_timer_enabled = false;
c7031a2c 307 /* The timer's reference to the session can be released safely. */
a0a4f314 308 session_put(&session.get());
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 */
cd9adb8b 318int timer_signal_init()
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);
cd9adb8b 325 ret = pthread_sigmask(SIG_BLOCK, &mask, nullptr);
d086f507
JD
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 */
28ab034a 337static void *thread_timer(void *data)
d086f507
JD
338{
339 int signr;
340 sigset_t mask;
341 siginfo_t info;
7966af57 342 struct timer_thread_parameters *ctx = (timer_thread_parameters *) data;
d086f507
JD
343
344 rcu_register_thread();
345 rcu_thread_online();
346
412d7227 347 health_register(the_health_sessiond, HEALTH_SESSIOND_TYPE_TIMER);
d086f507
JD
348 health_code_update();
349
350 /* Only self thread will receive signal mask. */
351 setmask(&mask);
352 CMM_STORE_SHARED(timer_signal.tid, pthread_self());
353
cd9adb8b 354 while (true) {
d086f507
JD
355 health_code_update();
356
357 health_poll_entry();
358 signr = sigwaitinfo(&mask, &info);
359 health_poll_exit();
360
361 /*
362 * NOTE: cascading conditions are used instead of a switch case
363 * since the use of SIGRTMIN in the definition of the signals'
364 * values prevents the reduction to an integer constant.
365 */
366 if (signr == -1) {
367 if (errno != EINTR) {
368 PERROR("sigwaitinfo");
369 }
370 continue;
92816cc3 371 } else if (signr == LTTNG_SESSIOND_SIG_QS) {
d086f507
JD
372 cmm_smp_mb();
373 CMM_STORE_SHARED(timer_signal.qs_done, 1);
374 cmm_smp_mb();
d086f507
JD
375 } else if (signr == LTTNG_SESSIOND_SIG_EXIT) {
376 goto end;
92816cc3 377 } else if (signr == LTTNG_SESSIOND_SIG_PENDING_ROTATION_CHECK) {
c7031a2c 378 struct ltt_session *session =
28ab034a 379 (struct ltt_session *) info.si_value.sival_ptr;
c7031a2c 380
0038180d
JG
381 rotation_thread_enqueue_job(
382 ctx->rotation_thread_job_queue,
383 lttng::sessiond::rotation_thread_job_type::CHECK_PENDING_ROTATION,
384 session);
92816cc3 385 } else if (signr == LTTNG_SESSIOND_SIG_SCHEDULED_ROTATION) {
0038180d
JG
386 rotation_thread_enqueue_job(
387 ctx->rotation_thread_job_queue,
388 lttng::sessiond::rotation_thread_job_type::SCHEDULED_ROTATION,
389 (struct ltt_session *) info.si_value.sival_ptr);
c7031a2c
JG
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 396 } else {
bd0514a5 397 ERR("Unexpected signal %d", info.si_signo);
d086f507
JD
398 }
399 }
400
401end:
bd0514a5 402 DBG("Thread exit");
412d7227 403 health_unregister(the_health_sessiond);
d086f507
JD
404 rcu_thread_offline();
405 rcu_unregister_thread();
cd9adb8b 406 return nullptr;
d086f507 407}
92816cc3 408
28ab034a 409static bool shutdown_timer_thread(void *data __attribute__((unused)))
bc26e826
JG
410{
411 return kill(getpid(), LTTNG_SESSIOND_SIG_EXIT) == 0;
412}
413
28ab034a 414bool launch_timer_thread(struct timer_thread_parameters *timer_thread_parameters)
92816cc3 415{
bc26e826
JG
416 struct lttng_thread *thread;
417
28ab034a 418 thread = lttng_thread_create(
cd9adb8b 419 "Timer", thread_timer, shutdown_timer_thread, nullptr, timer_thread_parameters);
bc26e826
JG
420 if (!thread) {
421 goto error;
422 }
423 lttng_thread_put(thread);
424 return true;
425error:
426 return false;
92816cc3 427}
This page took 0.087743 seconds and 4 git commands to generate.