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"
27 #include <bin/lttng-sessiond/ust-ctl.h>
28 #include <bin/lttng-consumerd/health-consumerd.h>
29 #include <common/common.h>
30 #include <common/compat/endian.h>
31 #include <common/kernel-ctl/kernel-ctl.h>
32 #include <common/kernel-consumer/kernel-consumer.h>
33 #include <common/consumer/consumer-stream.h>
34 #include <common/consumer/consumer-timer.h>
35 #include <common/consumer/consumer-testpoint.h>
36 #include <common/ust-consumer/ust-consumer.h>
39 static struct timer_signal_data timer_signal
= {
43 .lock
= PTHREAD_MUTEX_INITIALIZER
,
47 * Set custom signal mask to current thread.
49 static void setmask(sigset_t
*mask
)
53 ret
= sigemptyset(mask
);
55 PERROR("sigemptyset");
57 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_TEARDOWN
);
59 PERROR("sigaddset teardown");
61 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_EXIT
);
63 PERROR("sigaddset exit");
65 ret
= sigaddset(mask
, LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
67 PERROR("sigaddset switch");
72 void sessiond_timer_signal_thread_qs(unsigned int signr
)
78 * We need to be the only thread interacting with the thread
79 * that manages signals for teardown synchronization.
81 pthread_mutex_lock(&timer_signal
.lock
);
83 /* Ensure we don't have any signal queued for this session. */
85 ret
= sigemptyset(&pending_set
);
87 PERROR("sigemptyset");
89 ret
= sigpending(&pending_set
);
93 if (!sigismember(&pending_set
, signr
)) {
100 * From this point, no new signal handler will be fired that would try to
101 * access "session". However, we still need to wait for any currently
102 * executing handler to complete.
105 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
109 * Kill with LTTNG_SESSIOND_SIG_TEARDOWN, so signal management thread wakes
112 kill(getpid(), LTTNG_SESSIOND_SIG_TEARDOWN
);
114 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
119 pthread_mutex_unlock(&timer_signal
.lock
);
123 * Start a timer on a session that will fire at a given interval
124 * (timer_interval_us) and fire a given signal (signal).
126 * Returns a negative value on error, 0 if a timer was created, and
127 * a positive value if no timer was created (not an error).
130 int session_timer_start(timer_t
*timer_id
, struct ltt_session
*session
,
131 unsigned int timer_interval_us
, int signal
)
133 int ret
= 0, delete_ret
;
135 struct itimerspec its
;
139 sev
.sigev_notify
= SIGEV_SIGNAL
;
140 sev
.sigev_signo
= signal
;
141 sev
.sigev_value
.sival_ptr
= session
;
142 ret
= timer_create(CLOCKID
, &sev
, timer_id
);
144 PERROR("timer_create");
148 its
.it_value
.tv_sec
= timer_interval_us
/ 1000000;
149 its
.it_value
.tv_nsec
= (timer_interval_us
% 1000000) * 1000;
150 its
.it_interval
.tv_sec
= its
.it_value
.tv_sec
;
151 its
.it_interval
.tv_nsec
= its
.it_value
.tv_nsec
;
153 ret
= timer_settime(*timer_id
, 0, &its
, NULL
);
155 PERROR("timer_settime");
156 goto error_destroy_timer
;
161 delete_ret
= timer_delete(*timer_id
);
162 if (delete_ret
== -1) {
163 PERROR("timer_delete");
172 int session_timer_stop(timer_t
*timer_id
, int signal
)
176 ret
= timer_delete(*timer_id
);
178 PERROR("timer_delete");
182 sessiond_timer_signal_thread_qs(signal
);
188 int sessiond_timer_rotate_pending_start(struct ltt_session
*session
, unsigned int
193 ret
= session_timer_start(&session
->rotate_relay_pending_timer
,
194 session
, interval_us
,
195 LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
196 session
->rotate_relay_pending_timer_enabled
= !!(ret
== 0);
202 * Stop and delete the channel's live timer.
204 void sessiond_timer_rotate_pending_stop(struct ltt_session
*session
)
210 ret
= session_timer_stop(&session
->rotate_relay_pending_timer
,
211 LTTNG_SESSIOND_SIG_ROTATE_PENDING
);
213 ERR("Failed to stop live timer");
216 session
->rotate_relay_pending_timer_enabled
= 0;
220 * Block the RT signals for the entire process. It must be called from the
221 * sessiond main before creating the threads
223 int sessiond_timer_signal_init(void)
228 /* Block signal for entire process, so only our thread processes it. */
230 ret
= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
233 PERROR("pthread_sigmask");
240 void relay_rotation_pending_timer(struct timer_thread_parameters
*ctx
,
241 int sig
, siginfo_t
*si
)
244 struct ltt_session
*session
= si
->si_value
.sival_ptr
;
248 * Avoid sending too many requests in case the relay is slower to
249 * respond than the timer period.
251 if (session
->rotate_pending_relay_check_in_progress
||
252 !session
->rotate_pending_relay
) {
256 session
->rotate_pending_relay_check_in_progress
= true;
257 ret
= lttng_write(ctx
->rotate_timer_pipe
, &session
->id
,
258 sizeof(session
->id
));
259 if (ret
< sizeof(session
->id
)) {
260 PERROR("wakeup rotate pipe");
268 * This thread is the sighandler for the timer signals.
270 void *sessiond_timer_thread(void *data
)
275 struct timer_thread_parameters
*ctx
= data
;
277 rcu_register_thread();
280 health_register(health_sessiond
, HEALTH_SESSIOND_TYPE_NOTIFICATION
);
282 health_code_update();
284 /* Only self thread will receive signal mask. */
286 CMM_STORE_SHARED(timer_signal
.tid
, pthread_self());
289 health_code_update();
292 signr
= sigwaitinfo(&mask
, &info
);
296 * NOTE: cascading conditions are used instead of a switch case
297 * since the use of SIGRTMIN in the definition of the signals'
298 * values prevents the reduction to an integer constant.
301 if (errno
!= EINTR
) {
302 PERROR("sigwaitinfo");
305 } else if (signr
== LTTNG_SESSIOND_SIG_TEARDOWN
) {
306 fprintf(stderr
, "TEARDOWN\n");
308 CMM_STORE_SHARED(timer_signal
.qs_done
, 1);
310 DBG("Signal timer metadata thread teardown");
311 } else if (signr
== LTTNG_SESSIOND_SIG_EXIT
) {
312 fprintf(stderr
, "KILL\n");
314 } else if (signr
== LTTNG_SESSIOND_SIG_ROTATE_PENDING
) {
315 fprintf(stderr
, "PENDING TIMER\n");
316 relay_rotation_pending_timer(ctx
, info
.si_signo
, &info
);
318 ERR("Unexpected signal %d\n", info
.si_signo
);
323 health_unregister(health_sessiond
);
324 rcu_thread_offline();
325 rcu_unregister_thread();