2 * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
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.
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
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.
23 #include "sessiond-timer.h"
24 #include "health-sessiond.h"
25 #include "rotation-thread.h"
28 struct timer_signal_data timer_signal
= {
31 .lock
= PTHREAD_MUTEX_INITIALIZER
,
35 * Set custom signal mask to current thread.
38 void setmask(sigset_t
*mask
)
42 ret
= sigemptyset(mask
);
44 PERROR("sigemptyset");
46 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_TEARDOWN
);
48 PERROR("sigaddset teardown");
50 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_EXIT
);
52 PERROR("sigaddset exit");
54 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
56 PERROR("sigaddset switch");
58 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_ROTATE_TIMER
);
60 PERROR("sigaddset switch");
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.
70 void sessiond_timer_signal_thread_qs(unsigned int signr
)
76 * We need to be the only thread interacting with the thread
77 * that manages signals for teardown synchronization.
79 pthread_mutex_lock(&timer_signal
.lock
);
81 /* Ensure we don't have any signal queued for this session. */
83 ret
= sigemptyset(&pending_set
);
85 PERROR("sigemptyset");
87 ret
= sigpending(&pending_set
);
91 if (!sigismember(&pending_set
, signr
)) {
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.
103 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
107 * Kill with LTTNG_SESSIOND_SIG_TEARDOWN, so signal management thread
110 kill(getpid(), LTTNG_SESSIOND_SIG_TEARDOWN
);
112 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
117 pthread_mutex_unlock(&timer_signal
.lock
);
121 * Start a timer on a session that will fire at a given interval
122 * (timer_interval_us) and fire a given signal (signal).
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).
128 int session_timer_start(timer_t
*timer_id
, struct ltt_session
*session
,
129 unsigned int timer_interval_us
, int signal
, bool one_shot
)
131 int ret
= 0, delete_ret
;
133 struct itimerspec its
;
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
);
142 PERROR("timer_create");
146 its
.it_value
.tv_sec
= timer_interval_us
/ 1000000;
147 its
.it_value
.tv_nsec
= (timer_interval_us
% 1000000) * 1000;
149 its
.it_interval
.tv_sec
= 0;
150 its
.it_interval
.tv_nsec
= 0;
152 its
.it_interval
.tv_sec
= its
.it_value
.tv_sec
;
153 its
.it_interval
.tv_nsec
= its
.it_value
.tv_nsec
;
156 ret
= timer_settime(*timer_id
, 0, &its
, NULL
);
158 PERROR("timer_settime");
159 goto error_destroy_timer
;
164 delete_ret
= timer_delete(*timer_id
);
165 if (delete_ret
== -1) {
166 PERROR("timer_delete");
174 int session_timer_stop(timer_t
*timer_id
, int signal
)
178 ret
= timer_delete(*timer_id
);
180 PERROR("timer_delete");
184 sessiond_timer_signal_thread_qs(signal
);
190 int sessiond_timer_rotate_pending_start(struct ltt_session
*session
,
191 unsigned int interval_us
)
195 DBG("Enabling rotate pending timer on session %" PRIu64
, session
->id
);
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.
204 ret
= session_timer_start(&session
->rotate_relay_pending_timer
,
205 session
, interval_us
,
206 LTTNG_SESSIOND_SIG_ROTATE_PENDING
,
207 /* one-shot */ true);
209 session
->rotate_relay_pending_timer_enabled
= true;
216 * Stop and delete the channel's live timer.
217 * Called with session and session_list locks held.
219 int sessiond_timer_rotate_pending_stop(struct ltt_session
*session
)
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
);
229 ERR("Failed to stop rotate_pending timer");
231 session
->rotate_relay_pending_timer_enabled
= false;
236 int sessiond_rotate_timer_start(struct ltt_session
*session
,
237 unsigned int interval_us
)
241 DBG("Enabling rotation timer on session \"%s\" (%ui µs)", session
->name
,
243 ret
= session_timer_start(&session
->rotate_timer
, session
, interval_us
,
244 LTTNG_SESSIOND_SIG_ROTATE_TIMER
, false);
248 session
->rotate_timer_enabled
= true;
254 * Stop and delete the channel's live timer.
256 int sessiond_rotate_timer_stop(struct ltt_session
*session
)
262 if (!session
->rotate_timer_enabled
) {
266 DBG("Disabling rotation timer on session %s", session
->name
);
267 ret
= session_timer_stop(&session
->rotate_timer
,
268 LTTNG_SESSIOND_SIG_ROTATE_TIMER
);
270 ERR("Failed to stop rotate timer of session \"%s\"",
275 session
->rotate_timer_enabled
= false;
282 * Block the RT signals for the entire process. It must be called from the
283 * sessiond main before creating the threads
285 int sessiond_timer_signal_init(void)
290 /* Block signal for entire process, so only our thread processes it. */
292 ret
= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
295 PERROR("pthread_sigmask");
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.
306 bool check_duplicate_timer_job(struct timer_thread_parameters
*ctx
,
307 struct ltt_session
*session
, unsigned int signal
)
310 struct sessiond_rotation_timer
*node
;
313 cds_list_for_each_entry(node
, &ctx
->rotation_timer_queue
->list
, head
) {
314 if (node
->session_id
== session
->id
&& node
->signal
== signal
) {
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.
333 int enqueue_timer_rotate_job(struct timer_thread_parameters
*ctx
,
334 struct ltt_session
*session
, unsigned int signal
)
338 struct sessiond_rotation_timer
*timer_data
= NULL
;
340 pthread_mutex_lock(&ctx
->rotation_timer_queue
->lock
);
341 if (check_duplicate_timer_job(ctx
, session
, signal
)) {
343 * This timer job is already pending, we don't need to add
350 timer_data
= zmalloc(sizeof(struct sessiond_rotation_timer
));
352 PERROR("Allocation of timer data");
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
);
362 lttng_pipe_get_writefd(ctx
->rotation_timer_queue
->event_pipe
),
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.
370 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
374 PERROR("Timer wakeup rotation thread");
381 pthread_mutex_unlock(&ctx
->rotation_timer_queue
->lock
);
386 * Ask the rotation thread to check if the last rotation started in this
387 * session is still pending on the relay.
390 void relay_rotation_pending_timer(struct timer_thread_parameters
*ctx
,
391 int sig
, siginfo_t
*si
)
393 struct ltt_session
*session
= si
->si_value
.sival_ptr
;
397 (void) enqueue_timer_rotate_job(ctx
, session
,
398 LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
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
407 void rotate_timer(struct timer_thread_parameters
*ctx
, int sig
, siginfo_t
*si
)
411 * The session cannot be freed/destroyed while we are running this
414 struct ltt_session
*session
= si
->si_value
.sival_ptr
;
417 ret
= enqueue_timer_rotate_job(ctx
, session
, LTTNG_SESSIOND_SIG_ROTATE_TIMER
);
419 PERROR("wakeup rotate pipe");
424 * This thread is the sighandler for the timer signals.
426 void *sessiond_timer_thread(void *data
)
431 struct timer_thread_parameters
*ctx
= data
;
433 rcu_register_thread();
436 health_register(health_sessiond
, HEALTH_SESSIOND_TYPE_TIMER
);
438 health_code_update();
440 /* Only self thread will receive signal mask. */
442 CMM_STORE_SHARED(timer_signal
.tid
, pthread_self());
445 health_code_update();
448 signr
= sigwaitinfo(&mask
, &info
);
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.
457 if (errno
!= EINTR
) {
458 PERROR("sigwaitinfo");
461 } else if (signr
== LTTNG_SESSIOND_SIG_TEARDOWN
) {
463 CMM_STORE_SHARED(timer_signal
.qs_done
, 1);
465 DBG("Signal timer metadata thread teardown");
466 } else if (signr
== LTTNG_SESSIOND_SIG_EXIT
) {
468 } else if (signr
== LTTNG_SESSIOND_SIG_ROTATE_PENDING
) {
469 relay_rotation_pending_timer(ctx
, info
.si_signo
, &info
);
470 } else if (signr
== LTTNG_SESSIOND_SIG_ROTATE_TIMER
) {
471 rotate_timer(ctx
, info
.si_signo
, &info
);
473 ERR("Unexpected signal %d\n", info
.si_signo
);
478 DBG("[timer-thread] Exit");
479 health_unregister(health_sessiond
);
480 rcu_thread_offline();
481 rcu_unregister_thread();