remove debug
[deliverable/lttng-tools.git] / src / bin / lttng-sessiond / sessiond-timer.c
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
26 static struct timer_signal_data timer_signal = {
27 .tid = 0,
28 .setup_done = 0,
29 .qs_done = 0,
30 .lock = PTHREAD_MUTEX_INITIALIZER,
31 };
32
33 /*
34 * Set custom signal mask to current thread.
35 */
36 static void setmask(sigset_t *mask)
37 {
38 int ret;
39
40 ret = sigemptyset(mask);
41 if (ret) {
42 PERROR("sigemptyset");
43 }
44 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_TEARDOWN);
45 if (ret) {
46 PERROR("sigaddset teardown");
47 }
48 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_EXIT);
49 if (ret) {
50 PERROR("sigaddset exit");
51 }
52 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_ROTATE_PENDING);
53 if (ret) {
54 PERROR("sigaddset switch");
55 }
56 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_ROTATE_TIMER);
57 if (ret) {
58 PERROR("sigaddset switch");
59 }
60 }
61
62 static
63 void sessiond_timer_signal_thread_qs(unsigned int signr)
64 {
65 sigset_t pending_set;
66 int ret;
67
68 /*
69 * We need to be the only thread interacting with the thread
70 * that manages signals for teardown synchronization.
71 */
72 pthread_mutex_lock(&timer_signal.lock);
73
74 /* Ensure we don't have any signal queued for this session. */
75 for (;;) {
76 ret = sigemptyset(&pending_set);
77 if (ret == -1) {
78 PERROR("sigemptyset");
79 }
80 ret = sigpending(&pending_set);
81 if (ret == -1) {
82 PERROR("sigpending");
83 }
84 if (!sigismember(&pending_set, signr)) {
85 break;
86 }
87 caa_cpu_relax();
88 }
89
90 /*
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.
94 */
95 cmm_smp_mb();
96 CMM_STORE_SHARED(timer_signal.qs_done, 0);
97 cmm_smp_mb();
98
99 /*
100 * Kill with LTTNG_SESSIOND_SIG_TEARDOWN, so signal management thread wakes
101 * up.
102 */
103 kill(getpid(), LTTNG_SESSIOND_SIG_TEARDOWN);
104
105 while (!CMM_LOAD_SHARED(timer_signal.qs_done)) {
106 caa_cpu_relax();
107 }
108 cmm_smp_mb();
109
110 pthread_mutex_unlock(&timer_signal.lock);
111 }
112
113 /*
114 * Start a timer on a session that will fire at a given interval
115 * (timer_interval_us) and fire a given signal (signal).
116 *
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).
119 */
120 static
121 int session_timer_start(timer_t *timer_id, struct ltt_session *session,
122 unsigned int timer_interval_us, int signal)
123 {
124 int ret = 0, delete_ret;
125 struct sigevent sev;
126 struct itimerspec its;
127
128 assert(session);
129
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);
134 if (ret == -1) {
135 PERROR("timer_create");
136 goto end;
137 }
138
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;
143
144 ret = timer_settime(*timer_id, 0, &its, NULL);
145 if (ret == -1) {
146 PERROR("timer_settime");
147 goto error_destroy_timer;
148 }
149 goto end;
150
151 error_destroy_timer:
152 delete_ret = timer_delete(*timer_id);
153 if (delete_ret == -1) {
154 PERROR("timer_delete");
155 }
156
157 end:
158 return ret;
159 }
160
161
162 static
163 int session_timer_stop(timer_t *timer_id, int signal)
164 {
165 int ret = 0;
166
167 ret = timer_delete(*timer_id);
168 if (ret == -1) {
169 PERROR("timer_delete");
170 goto end;
171 }
172
173 sessiond_timer_signal_thread_qs(signal);
174 *timer_id = 0;
175 end:
176 return ret;
177 }
178
179 int sessiond_timer_rotate_pending_start(struct ltt_session *session,
180 unsigned int interval_us)
181 {
182 int ret;
183
184 ret = session_timer_start(&session->rotate_relay_pending_timer,
185 session, interval_us,
186 LTTNG_SESSIOND_SIG_ROTATE_PENDING);
187 if (ret == 0) {
188 session->rotate_relay_pending_timer_enabled = true;
189 }
190
191 return ret;
192 }
193
194 /*
195 * Stop and delete the channel's live timer.
196 */
197 void sessiond_timer_rotate_pending_stop(struct ltt_session *session)
198 {
199 int ret;
200
201 assert(session);
202
203 ret = session_timer_stop(&session->rotate_relay_pending_timer,
204 LTTNG_SESSIOND_SIG_ROTATE_PENDING);
205 if (ret == -1) {
206 ERR("Failed to stop live timer");
207 }
208
209 session->rotate_relay_pending_timer_enabled = false;
210 }
211
212 int sessiond_rotate_timer_start(struct ltt_session *session,
213 unsigned int interval_us)
214 {
215 int ret;
216
217 ret = session_timer_start(&session->rotate_timer, session, interval_us,
218 LTTNG_SESSIOND_SIG_ROTATE_TIMER);
219 if (ret == 0) {
220 session->rotate_timer_enabled = true;
221 }
222
223 return ret;
224 }
225
226 /*
227 * Stop and delete the channel's live timer.
228 */
229 void sessiond_rotate_timer_stop(struct ltt_session *session)
230 {
231 int ret;
232
233 assert(session);
234
235 ret = session_timer_stop(&session->rotate_timer,
236 LTTNG_SESSIOND_SIG_ROTATE_TIMER);
237 if (ret == -1) {
238 ERR("Failed to stop live timer");
239 }
240
241 session->rotate_timer_enabled = false;
242 }
243
244 /*
245 * Block the RT signals for the entire process. It must be called from the
246 * sessiond main before creating the threads
247 */
248 int sessiond_timer_signal_init(void)
249 {
250 int ret;
251 sigset_t mask;
252
253 /* Block signal for entire process, so only our thread processes it. */
254 setmask(&mask);
255 ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
256 if (ret) {
257 errno = ret;
258 PERROR("pthread_sigmask");
259 return -1;
260 }
261 return 0;
262 }
263
264 static
265 void relay_rotation_pending_timer(struct timer_thread_parameters *ctx,
266 int sig, siginfo_t *si)
267 {
268 int ret;
269 struct ltt_session *session = si->si_value.sival_ptr;
270 struct sessiond_rotation_timer timer_data;
271 assert(session);
272
273 /*
274 * Avoid sending too many requests in case the relay is slower to
275 * respond than the timer period.
276 */
277 if (session->rotate_pending_relay_check_in_progress ||
278 !session->rotate_pending_relay) {
279 goto end;
280 }
281
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,
287 sizeof(timer_data));
288 if (ret < sizeof(session->id)) {
289 PERROR("wakeup rotate pipe");
290 }
291
292 end:
293 return;
294 }
295
296 static
297 void rotate_timer(struct timer_thread_parameters *ctx, int sig, siginfo_t *si)
298 {
299 int ret;
300 struct ltt_session *session = si->si_value.sival_ptr;
301 struct sessiond_rotation_timer timer_data;
302 assert(session);
303
304 /*
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
307 * up.
308 */
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,
313 sizeof(timer_data));
314 if (ret < sizeof(session->id)) {
315 PERROR("wakeup rotate pipe");
316 }
317
318 return;
319 }
320
321 /*
322 * This thread is the sighandler for the timer signals.
323 */
324 void *sessiond_timer_thread(void *data)
325 {
326 int signr;
327 sigset_t mask;
328 siginfo_t info;
329 struct timer_thread_parameters *ctx = data;
330
331 rcu_register_thread();
332 rcu_thread_online();
333
334 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_NOTIFICATION);
335
336 health_code_update();
337
338 /* Only self thread will receive signal mask. */
339 setmask(&mask);
340 CMM_STORE_SHARED(timer_signal.tid, pthread_self());
341
342 while (1) {
343 health_code_update();
344
345 health_poll_entry();
346 signr = sigwaitinfo(&mask, &info);
347 health_poll_exit();
348
349 /*
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.
353 */
354 if (signr == -1) {
355 if (errno != EINTR) {
356 PERROR("sigwaitinfo");
357 }
358 continue;
359 } else if (signr == LTTNG_SESSIOND_SIG_TEARDOWN) {
360 cmm_smp_mb();
361 CMM_STORE_SHARED(timer_signal.qs_done, 1);
362 cmm_smp_mb();
363 DBG("Signal timer metadata thread teardown");
364 } else if (signr == LTTNG_SESSIOND_SIG_EXIT) {
365 goto end;
366 } else if (signr == LTTNG_SESSIOND_SIG_ROTATE_PENDING) {
367 relay_rotation_pending_timer(ctx, info.si_signo, &info);
368 } else if (signr == LTTNG_SESSIOND_SIG_ROTATE_TIMER) {
369 rotate_timer(ctx, info.si_signo, &info);
370 } else {
371 ERR("Unexpected signal %d\n", info.si_signo);
372 }
373 }
374
375 end:
376 health_unregister(health_sessiond);
377 rcu_thread_offline();
378 rcu_unregister_thread();
379 return NULL;
380 }
This page took 0.043114 seconds and 5 git commands to generate.