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");
57 * This is the same function as consumer_timer_signal_thread_qs, when it
58 * returns, it means that no timer signr is currently pending or being handled
59 * by the timer thread. This cannot be called from the timer thread.
62 void sessiond_timer_signal_thread_qs(unsigned int signr
)
68 * We need to be the only thread interacting with the thread
69 * that manages signals for teardown synchronization.
71 pthread_mutex_lock(&timer_signal
.lock
);
73 /* Ensure we don't have any signal queued for this session. */
75 ret
= sigemptyset(&pending_set
);
77 PERROR("sigemptyset");
79 ret
= sigpending(&pending_set
);
83 if (!sigismember(&pending_set
, signr
)) {
90 * From this point, no new signal handler will be fired that would try to
91 * access "session". However, we still need to wait for any currently
92 * executing handler to complete.
95 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
99 * Kill with LTTNG_SESSIOND_SIG_TEARDOWN, so signal management thread
102 kill(getpid(), LTTNG_SESSIOND_SIG_TEARDOWN
);
104 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
109 pthread_mutex_unlock(&timer_signal
.lock
);
113 * Start a timer on a session that will fire at a given interval
114 * (timer_interval_us) and fire a given signal (signal).
116 * Returns a negative value on error, 0 if a timer was created, and
117 * a positive value if no timer was created (not an error).
120 int session_timer_start(timer_t
*timer_id
, struct ltt_session
*session
,
121 unsigned int timer_interval_us
, int signal
, bool one_shot
)
123 int ret
= 0, delete_ret
;
125 struct itimerspec its
;
129 sev
.sigev_notify
= SIGEV_SIGNAL
;
130 sev
.sigev_signo
= signal
;
131 sev
.sigev_value
.sival_ptr
= session
;
132 ret
= timer_create(CLOCKID
, &sev
, timer_id
);
134 PERROR("timer_create");
138 its
.it_value
.tv_sec
= timer_interval_us
/ 1000000;
139 its
.it_value
.tv_nsec
= (timer_interval_us
% 1000000) * 1000;
141 its
.it_interval
.tv_sec
= 0;
142 its
.it_interval
.tv_nsec
= 0;
144 its
.it_interval
.tv_sec
= its
.it_value
.tv_sec
;
145 its
.it_interval
.tv_nsec
= its
.it_value
.tv_nsec
;
148 ret
= timer_settime(*timer_id
, 0, &its
, NULL
);
150 PERROR("timer_settime");
151 goto error_destroy_timer
;
156 delete_ret
= timer_delete(*timer_id
);
157 if (delete_ret
== -1) {
158 PERROR("timer_delete");
166 int session_timer_stop(timer_t
*timer_id
, int signal
)
170 ret
= timer_delete(*timer_id
);
172 PERROR("timer_delete");
176 sessiond_timer_signal_thread_qs(signal
);
183 * Block the RT signals for the entire process. It must be called from the
184 * sessiond main before creating the threads
186 int sessiond_timer_signal_init(void)
191 /* Block signal for entire process, so only our thread processes it. */
193 ret
= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
196 PERROR("pthread_sigmask");
203 * This thread is the sighandler for the timer signals.
205 void *sessiond_timer_thread(void *data
)
210 struct timer_thread_parameters
*ctx
= data
;
212 rcu_register_thread();
215 health_register(health_sessiond
, HEALTH_SESSIOND_TYPE_TIMER
);
217 health_code_update();
219 /* Only self thread will receive signal mask. */
221 CMM_STORE_SHARED(timer_signal
.tid
, pthread_self());
224 health_code_update();
227 signr
= sigwaitinfo(&mask
, &info
);
231 * NOTE: cascading conditions are used instead of a switch case
232 * since the use of SIGRTMIN in the definition of the signals'
233 * values prevents the reduction to an integer constant.
236 if (errno
!= EINTR
) {
237 PERROR("sigwaitinfo");
240 } else if (signr
== LTTNG_SESSIOND_SIG_TEARDOWN
) {
242 CMM_STORE_SHARED(timer_signal
.qs_done
, 1);
244 DBG("Signal timer metadata thread teardown");
245 } else if (signr
== LTTNG_SESSIOND_SIG_EXIT
) {
248 ERR("Unexpected signal %d\n", info
.si_signo
);
253 DBG("[timer-thread] Exit");
254 health_unregister(health_sessiond
);
255 rcu_thread_offline();
256 rcu_unregister_thread();