Cleanup: improve readability of filter expression condition
[lttng-tools.git] / src / bin / lttng-sessiond / sessiond-timer.c
CommitLineData
d086f507
JD
1/*
2 * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _LGPL_SOURCE
19#include <assert.h>
20#include <inttypes.h>
21#include <signal.h>
22
23#include "sessiond-timer.h"
24#include "health-sessiond.h"
25#include "rotation-thread.h"
26
27static
28struct timer_signal_data timer_signal = {
29 .tid = 0,
30 .qs_done = 0,
31 .lock = PTHREAD_MUTEX_INITIALIZER,
32};
33
34/*
35 * Set custom signal mask to current thread.
36 */
37static
38void setmask(sigset_t *mask)
39{
40 int ret;
41
42 ret = sigemptyset(mask);
43 if (ret) {
44 PERROR("sigemptyset");
45 }
46 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_TEARDOWN);
47 if (ret) {
48 PERROR("sigaddset teardown");
49 }
50 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_EXIT);
51 if (ret) {
52 PERROR("sigaddset exit");
53 }
d88744a4
JD
54 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_ROTATE_PENDING);
55 if (ret) {
56 PERROR("sigaddset switch");
57 }
259c2674
JD
58 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_ROTATE_TIMER);
59 if (ret) {
60 PERROR("sigaddset switch");
61 }
d086f507
JD
62}
63
64/*
65 * This is the same function as consumer_timer_signal_thread_qs, when it
66 * returns, it means that no timer signr is currently pending or being handled
67 * by the timer thread. This cannot be called from the timer thread.
68 */
69static
70void sessiond_timer_signal_thread_qs(unsigned int signr)
71{
72 sigset_t pending_set;
73 int ret;
74
75 /*
76 * We need to be the only thread interacting with the thread
77 * that manages signals for teardown synchronization.
78 */
79 pthread_mutex_lock(&timer_signal.lock);
80
81 /* Ensure we don't have any signal queued for this session. */
82 for (;;) {
83 ret = sigemptyset(&pending_set);
84 if (ret == -1) {
85 PERROR("sigemptyset");
86 }
87 ret = sigpending(&pending_set);
88 if (ret == -1) {
89 PERROR("sigpending");
90 }
91 if (!sigismember(&pending_set, signr)) {
92 break;
93 }
94 caa_cpu_relax();
95 }
96
97 /*
98 * From this point, no new signal handler will be fired that would try to
99 * access "session". However, we still need to wait for any currently
100 * executing handler to complete.
101 */
102 cmm_smp_mb();
103 CMM_STORE_SHARED(timer_signal.qs_done, 0);
104 cmm_smp_mb();
105
106 /*
107 * Kill with LTTNG_SESSIOND_SIG_TEARDOWN, so signal management thread
108 * wakes up.
109 */
110 kill(getpid(), LTTNG_SESSIOND_SIG_TEARDOWN);
111
112 while (!CMM_LOAD_SHARED(timer_signal.qs_done)) {
113 caa_cpu_relax();
114 }
115 cmm_smp_mb();
116
117 pthread_mutex_unlock(&timer_signal.lock);
118}
119
120/*
121 * Start a timer on a session that will fire at a given interval
122 * (timer_interval_us) and fire a given signal (signal).
123 *
124 * Returns a negative value on error, 0 if a timer was created, and
125 * a positive value if no timer was created (not an error).
126 */
127static
128int session_timer_start(timer_t *timer_id, struct ltt_session *session,
129 unsigned int timer_interval_us, int signal, bool one_shot)
130{
131 int ret = 0, delete_ret;
132 struct sigevent sev;
133 struct itimerspec its;
134
135 assert(session);
136
137 sev.sigev_notify = SIGEV_SIGNAL;
138 sev.sigev_signo = signal;
139 sev.sigev_value.sival_ptr = session;
140 ret = timer_create(CLOCKID, &sev, timer_id);
141 if (ret == -1) {
142 PERROR("timer_create");
143 goto end;
144 }
145
146 its.it_value.tv_sec = timer_interval_us / 1000000;
147 its.it_value.tv_nsec = (timer_interval_us % 1000000) * 1000;
148 if (one_shot) {
149 its.it_interval.tv_sec = 0;
150 its.it_interval.tv_nsec = 0;
151 } else {
152 its.it_interval.tv_sec = its.it_value.tv_sec;
153 its.it_interval.tv_nsec = its.it_value.tv_nsec;
154 }
155
156 ret = timer_settime(*timer_id, 0, &its, NULL);
157 if (ret == -1) {
158 PERROR("timer_settime");
159 goto error_destroy_timer;
160 }
161 goto end;
162
163error_destroy_timer:
164 delete_ret = timer_delete(*timer_id);
165 if (delete_ret == -1) {
166 PERROR("timer_delete");
167 }
168
169end:
170 return ret;
171}
172
173static
174int session_timer_stop(timer_t *timer_id, int signal)
175{
176 int ret = 0;
177
178 ret = timer_delete(*timer_id);
179 if (ret == -1) {
180 PERROR("timer_delete");
181 goto end;
182 }
183
184 sessiond_timer_signal_thread_qs(signal);
185 *timer_id = 0;
186end:
187 return ret;
188}
189
d88744a4
JD
190int sessiond_timer_rotate_pending_start(struct ltt_session *session,
191 unsigned int interval_us)
192{
193 int ret;
194
195 DBG("Enabling rotate pending timer on session %" PRIu64, session->id);
196 /*
197 * We arm this timer in a one-shot mode so we don't have to disable it
198 * explicitly (which could deadlock if the timer thread is blocked writing
199 * in the rotation_timer_pipe).
200 * Instead, we re-arm it if needed after the rotation_pending check as
201 * returned. Also, this timer is usually only needed once, so there is no
202 * need to go through the whole signal teardown scheme everytime.
203 */
204 ret = session_timer_start(&session->rotate_relay_pending_timer,
205 session, interval_us,
206 LTTNG_SESSIOND_SIG_ROTATE_PENDING,
207 /* one-shot */ true);
208 if (ret == 0) {
209 session->rotate_relay_pending_timer_enabled = true;
210 }
211
212 return ret;
213}
214
215/*
216 * Stop and delete the channel's live timer.
217 * Called with session and session_list locks held.
218 */
259c2674 219int sessiond_timer_rotate_pending_stop(struct ltt_session *session)
d88744a4
JD
220{
221 int ret;
222
223 assert(session);
224
225 DBG("Disabling timer rotate pending on session %" PRIu64, session->id);
226 ret = session_timer_stop(&session->rotate_relay_pending_timer,
227 LTTNG_SESSIOND_SIG_ROTATE_PENDING);
228 if (ret == -1) {
229 ERR("Failed to stop rotate_pending timer");
259c2674
JD
230 } else {
231 session->rotate_relay_pending_timer_enabled = false;
232 }
233 return ret;
234}
235
236int sessiond_rotate_timer_start(struct ltt_session *session,
237 unsigned int interval_us)
238{
239 int ret;
240
241 DBG("Enabling rotation timer on session \"%s\" (%ui µs)", session->name,
242 interval_us);
243 ret = session_timer_start(&session->rotate_timer, session, interval_us,
244 LTTNG_SESSIOND_SIG_ROTATE_TIMER, false);
245 if (ret < 0) {
246 goto end;
247 }
248 session->rotate_timer_enabled = true;
249end:
250 return ret;
251}
252
253/*
254 * Stop and delete the channel's live timer.
255 */
256int sessiond_rotate_timer_stop(struct ltt_session *session)
257{
258 int ret = 0;
259
260 assert(session);
261
262 if (!session->rotate_timer_enabled) {
263 goto end;
264 }
265
266 DBG("Disabling rotation timer on session %s", session->name);
267 ret = session_timer_stop(&session->rotate_timer,
268 LTTNG_SESSIOND_SIG_ROTATE_TIMER);
269 if (ret < 0) {
270 ERR("Failed to stop rotate timer of session \"%s\"",
271 session->name);
272 goto end;
d88744a4
JD
273 }
274
259c2674
JD
275 session->rotate_timer_enabled = false;
276 ret = 0;
277end:
278 return ret;
d88744a4
JD
279}
280
d086f507
JD
281/*
282 * Block the RT signals for the entire process. It must be called from the
283 * sessiond main before creating the threads
284 */
285int sessiond_timer_signal_init(void)
286{
287 int ret;
288 sigset_t mask;
289
290 /* Block signal for entire process, so only our thread processes it. */
291 setmask(&mask);
292 ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
293 if (ret) {
294 errno = ret;
295 PERROR("pthread_sigmask");
296 return -1;
297 }
298 return 0;
299}
300
d88744a4
JD
301/*
302 * Called with the rotation_timer_queue lock held.
303 * Return true if the same timer job already exists in the queue, false if not.
304 */
305static
306bool check_duplicate_timer_job(struct timer_thread_parameters *ctx,
307 struct ltt_session *session, unsigned int signal)
308{
309 bool ret = false;
310 struct sessiond_rotation_timer *node;
311
312 rcu_read_lock();
313 cds_list_for_each_entry(node, &ctx->rotation_timer_queue->list, head) {
314 if (node->session_id == session->id && node->signal == signal) {
315 ret = true;
316 goto end;
317 }
318 }
319
320end:
321 rcu_read_unlock();
322 return ret;
323}
324
325/*
326 * Add the session ID and signal value to the rotation_timer_queue if it is
327 * not already there and wakeup the rotation thread. The rotation thread
328 * empties the whole queue everytime it is woken up. The event_pipe is
329 * non-blocking, if it would block, we just return because we know the
330 * rotation thread will be awaken anyway.
331 */
332static
333int enqueue_timer_rotate_job(struct timer_thread_parameters *ctx,
334 struct ltt_session *session, unsigned int signal)
335{
336 int ret;
d88744a4 337 char *c = "!";
f5eeb9d7 338 struct sessiond_rotation_timer *timer_data = NULL;
d88744a4
JD
339
340 pthread_mutex_lock(&ctx->rotation_timer_queue->lock);
f5eeb9d7 341 if (check_duplicate_timer_job(ctx, session, signal)) {
d88744a4
JD
342 /*
343 * This timer job is already pending, we don't need to add
344 * it.
345 */
d88744a4
JD
346 ret = 0;
347 goto end;
348 }
f5eeb9d7
JG
349
350 timer_data = zmalloc(sizeof(struct sessiond_rotation_timer));
351 if (!timer_data) {
352 PERROR("Allocation of timer data");
353 ret = -1;
354 goto end;
355 }
356 timer_data->session_id = session->id;
357 timer_data->signal = signal;
358 cds_list_add_tail(&timer_data->head,
359 &ctx->rotation_timer_queue->list);
d88744a4
JD
360
361 ret = lttng_write(
362 lttng_pipe_get_writefd(ctx->rotation_timer_queue->event_pipe),
363 c, 1);
364 if (ret < 0) {
365 /*
366 * We do not want to block in the timer handler, the job has been
367 * enqueued in the list, the wakeup pipe is probably full, the job
368 * will be processed when the rotation_thread catches up.
369 */
370 if (errno == EAGAIN || errno == EWOULDBLOCK) {
371 ret = 0;
372 goto end;
373 }
374 PERROR("Timer wakeup rotation thread");
f5eeb9d7 375 goto end;
d88744a4
JD
376 }
377
378 ret = 0;
d88744a4 379
d88744a4 380end:
f5eeb9d7 381 pthread_mutex_unlock(&ctx->rotation_timer_queue->lock);
d88744a4
JD
382 return ret;
383}
384
385/*
386 * Ask the rotation thread to check if the last rotation started in this
387 * session is still pending on the relay.
388 */
389static
390void relay_rotation_pending_timer(struct timer_thread_parameters *ctx,
391 int sig, siginfo_t *si)
259c2674
JD
392{
393 struct ltt_session *session = si->si_value.sival_ptr;
394
395 assert(session);
396
397 (void) enqueue_timer_rotate_job(ctx, session,
398 LTTNG_SESSIOND_SIG_ROTATE_PENDING);
399}
400
401/*
402 * Handle the LTTNG_SESSIOND_SIG_ROTATE_TIMER timer. Add the session ID to
403 * the rotation_timer_queue so the rotation thread can trigger a new rotation
404 * on that session.
405 */
406static
407void rotate_timer(struct timer_thread_parameters *ctx, int sig, siginfo_t *si)
d88744a4
JD
408{
409 int ret;
259c2674
JD
410 /*
411 * The session cannot be freed/destroyed while we are running this
412 * signal handler.
413 */
d88744a4
JD
414 struct ltt_session *session = si->si_value.sival_ptr;
415 assert(session);
416
259c2674 417 ret = enqueue_timer_rotate_job(ctx, session, LTTNG_SESSIOND_SIG_ROTATE_TIMER);
d88744a4
JD
418 if (ret) {
419 PERROR("wakeup rotate pipe");
420 }
421}
422
d086f507
JD
423/*
424 * This thread is the sighandler for the timer signals.
425 */
426void *sessiond_timer_thread(void *data)
427{
428 int signr;
429 sigset_t mask;
430 siginfo_t info;
431 struct timer_thread_parameters *ctx = data;
432
433 rcu_register_thread();
434 rcu_thread_online();
435
436 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_TIMER);
437
438 health_code_update();
439
440 /* Only self thread will receive signal mask. */
441 setmask(&mask);
442 CMM_STORE_SHARED(timer_signal.tid, pthread_self());
443
444 while (1) {
445 health_code_update();
446
447 health_poll_entry();
448 signr = sigwaitinfo(&mask, &info);
449 health_poll_exit();
450
451 /*
452 * NOTE: cascading conditions are used instead of a switch case
453 * since the use of SIGRTMIN in the definition of the signals'
454 * values prevents the reduction to an integer constant.
455 */
456 if (signr == -1) {
457 if (errno != EINTR) {
458 PERROR("sigwaitinfo");
459 }
460 continue;
461 } else if (signr == LTTNG_SESSIOND_SIG_TEARDOWN) {
462 cmm_smp_mb();
463 CMM_STORE_SHARED(timer_signal.qs_done, 1);
464 cmm_smp_mb();
465 DBG("Signal timer metadata thread teardown");
466 } else if (signr == LTTNG_SESSIOND_SIG_EXIT) {
467 goto end;
d88744a4
JD
468 } else if (signr == LTTNG_SESSIOND_SIG_ROTATE_PENDING) {
469 relay_rotation_pending_timer(ctx, info.si_signo, &info);
259c2674
JD
470 } else if (signr == LTTNG_SESSIOND_SIG_ROTATE_TIMER) {
471 rotate_timer(ctx, info.si_signo, &info);
d086f507
JD
472 } else {
473 ERR("Unexpected signal %d\n", info.si_signo);
474 }
475 }
476
477end:
478 DBG("[timer-thread] Exit");
479 health_unregister(health_sessiond);
480 rcu_thread_offline();
481 rcu_unregister_thread();
482 return NULL;
483}
This page took 0.042426 seconds and 4 git commands to generate.