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"
26 static struct timer_signal_data timer_signal
= {
30 .lock
= PTHREAD_MUTEX_INITIALIZER
,
34 * Set custom signal mask to current thread.
36 static void setmask(sigset_t
*mask
)
40 ret
= sigemptyset(mask
);
42 PERROR("sigemptyset");
44 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_TEARDOWN
);
46 PERROR("sigaddset teardown");
48 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_EXIT
);
50 PERROR("sigaddset exit");
52 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
54 PERROR("sigaddset switch");
56 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_ROTATE_TIMER
);
58 PERROR("sigaddset switch");
63 void sessiond_timer_signal_thread_qs(unsigned int signr
)
69 * We need to be the only thread interacting with the thread
70 * that manages signals for teardown synchronization.
72 pthread_mutex_lock(&timer_signal
.lock
);
74 /* Ensure we don't have any signal queued for this session. */
76 ret
= sigemptyset(&pending_set
);
78 PERROR("sigemptyset");
80 ret
= sigpending(&pending_set
);
84 if (!sigismember(&pending_set
, signr
)) {
91 * From this point, no new signal handler will be fired that would try to
92 * access "session". However, we still need to wait for any currently
93 * executing handler to complete.
96 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
100 * Kill with LTTNG_SESSIOND_SIG_TEARDOWN, so signal management thread wakes
103 kill(getpid(), LTTNG_SESSIOND_SIG_TEARDOWN
);
105 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
110 pthread_mutex_unlock(&timer_signal
.lock
);
114 * Start a timer on a session that will fire at a given interval
115 * (timer_interval_us) and fire a given signal (signal).
117 * Returns a negative value on error, 0 if a timer was created, and
118 * a positive value if no timer was created (not an error).
121 int session_timer_start(timer_t
*timer_id
, struct ltt_session
*session
,
122 unsigned int timer_interval_us
, int signal
)
124 int ret
= 0, delete_ret
;
126 struct itimerspec its
;
130 sev
.sigev_notify
= SIGEV_SIGNAL
;
131 sev
.sigev_signo
= signal
;
132 sev
.sigev_value
.sival_ptr
= session
;
133 ret
= timer_create(CLOCKID
, &sev
, timer_id
);
135 PERROR("timer_create");
139 its
.it_value
.tv_sec
= timer_interval_us
/ 1000000;
140 its
.it_value
.tv_nsec
= (timer_interval_us
% 1000000) * 1000;
141 its
.it_interval
.tv_sec
= its
.it_value
.tv_sec
;
142 its
.it_interval
.tv_nsec
= its
.it_value
.tv_nsec
;
144 ret
= timer_settime(*timer_id
, 0, &its
, NULL
);
146 PERROR("timer_settime");
147 goto error_destroy_timer
;
152 delete_ret
= timer_delete(*timer_id
);
153 if (delete_ret
== -1) {
154 PERROR("timer_delete");
163 int session_timer_stop(timer_t
*timer_id
, int signal
)
167 ret
= timer_delete(*timer_id
);
169 PERROR("timer_delete");
173 sessiond_timer_signal_thread_qs(signal
);
179 int sessiond_timer_rotate_pending_start(struct ltt_session
*session
,
180 unsigned int interval_us
)
184 ret
= session_timer_start(&session
->rotate_relay_pending_timer
,
185 session
, interval_us
,
186 LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
188 session
->rotate_relay_pending_timer_enabled
= true;
195 * Stop and delete the channel's live timer.
197 void sessiond_timer_rotate_pending_stop(struct ltt_session
*session
)
203 ret
= session_timer_stop(&session
->rotate_relay_pending_timer
,
204 LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
206 ERR("Failed to stop live timer");
209 session
->rotate_relay_pending_timer_enabled
= false;
212 int sessiond_rotate_timer_start(struct ltt_session
*session
,
213 unsigned int interval_us
)
217 ret
= session_timer_start(&session
->rotate_timer
, session
, interval_us
,
218 LTTNG_SESSIOND_SIG_ROTATE_TIMER
);
220 session
->rotate_timer_enabled
= true;
227 * Stop and delete the channel's live timer.
229 void sessiond_rotate_timer_stop(struct ltt_session
*session
)
235 ret
= session_timer_stop(&session
->rotate_timer
,
236 LTTNG_SESSIOND_SIG_ROTATE_TIMER
);
238 ERR("Failed to stop live timer");
241 session
->rotate_timer_enabled
= false;
245 * Block the RT signals for the entire process. It must be called from the
246 * sessiond main before creating the threads
248 int sessiond_timer_signal_init(void)
253 /* Block signal for entire process, so only our thread processes it. */
255 ret
= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
258 PERROR("pthread_sigmask");
265 void relay_rotation_pending_timer(struct timer_thread_parameters
*ctx
,
266 int sig
, siginfo_t
*si
)
269 struct ltt_session
*session
= si
->si_value
.sival_ptr
;
270 struct sessiond_rotation_timer timer_data
;
274 * Avoid sending too many requests in case the relay is slower to
275 * respond than the timer period.
277 if (session
->rotate_pending_relay_check_in_progress
||
278 !session
->rotate_pending_relay
) {
282 session
->rotate_pending_relay_check_in_progress
= true;
283 memset(&timer_data
, 0, sizeof(struct sessiond_rotation_timer
));
284 timer_data
.session_id
= session
->id
;
285 timer_data
.signal
= LTTNG_SESSIOND_SIG_ROTATE_PENDING
;
286 ret
= lttng_write(ctx
->rotate_timer_pipe
, &timer_data
,
288 if (ret
< sizeof(session
->id
)) {
289 PERROR("wakeup rotate pipe");
297 void rotate_timer(struct timer_thread_parameters
*ctx
, int sig
, siginfo_t
*si
)
300 struct ltt_session
*session
= si
->si_value
.sival_ptr
;
301 struct sessiond_rotation_timer timer_data
;
305 * No rate limiting here, so if the timer fires too quickly, there will
306 * be a backlog of timers queued up and the sessiond will try to catch
309 memset(&timer_data
, 0, sizeof(struct sessiond_rotation_timer
));
310 timer_data
.session_id
= session
->id
;
311 timer_data
.signal
= LTTNG_SESSIOND_SIG_ROTATE_TIMER
;
312 ret
= lttng_write(ctx
->rotate_timer_pipe
, &timer_data
,
314 if (ret
< sizeof(session
->id
)) {
315 PERROR("wakeup rotate pipe");
322 * This thread is the sighandler for the timer signals.
324 void *sessiond_timer_thread(void *data
)
329 struct timer_thread_parameters
*ctx
= data
;
331 rcu_register_thread();
334 health_register(health_sessiond
, HEALTH_SESSIOND_TYPE_NOTIFICATION
);
336 health_code_update();
338 /* Only self thread will receive signal mask. */
340 CMM_STORE_SHARED(timer_signal
.tid
, pthread_self());
343 health_code_update();
346 signr
= sigwaitinfo(&mask
, &info
);
350 * NOTE: cascading conditions are used instead of a switch case
351 * since the use of SIGRTMIN in the definition of the signals'
352 * values prevents the reduction to an integer constant.
355 if (errno
!= EINTR
) {
356 PERROR("sigwaitinfo");
359 } else if (signr
== LTTNG_SESSIOND_SIG_TEARDOWN
) {
360 fprintf(stderr
, "TEARDOWN\n");
362 CMM_STORE_SHARED(timer_signal
.qs_done
, 1);
364 DBG("Signal timer metadata thread teardown");
365 } else if (signr
== LTTNG_SESSIOND_SIG_EXIT
) {
366 fprintf(stderr
, "KILL\n");
368 } else if (signr
== LTTNG_SESSIOND_SIG_ROTATE_PENDING
) {
369 fprintf(stderr
, "PENDING TIMER\n");
370 relay_rotation_pending_timer(ctx
, info
.si_signo
, &info
);
371 } else if (signr
== LTTNG_SESSIOND_SIG_ROTATE_TIMER
) {
372 fprintf(stderr
, "ROTATE TIMER\n");
373 rotate_timer(ctx
, info
.si_signo
, &info
);
375 ERR("Unexpected signal %d\n", info
.si_signo
);
380 health_unregister(health_sessiond
);
381 rcu_thread_offline();
382 rcu_unregister_thread();