config for pending timer + rate limiting
[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 #if 0
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>
37 #endif
38
39 static struct timer_signal_data timer_signal = {
40 .tid = 0,
41 .setup_done = 0,
42 .qs_done = 0,
43 .lock = PTHREAD_MUTEX_INITIALIZER,
44 };
45
46 /*
47 * Set custom signal mask to current thread.
48 */
49 static void setmask(sigset_t *mask)
50 {
51 int ret;
52
53 ret = sigemptyset(mask);
54 if (ret) {
55 PERROR("sigemptyset");
56 }
57 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_TEARDOWN);
58 if (ret) {
59 PERROR("sigaddset teardown");
60 }
61 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_EXIT);
62 if (ret) {
63 PERROR("sigaddset exit");
64 }
65 ret = sigaddset(mask, LTTNG_SESSIOND_SIG_ROTATE_PENDING);
66 if (ret) {
67 PERROR("sigaddset switch");
68 }
69 }
70
71 static
72 void sessiond_timer_signal_thread_qs(unsigned int signr)
73 {
74 sigset_t pending_set;
75 int ret;
76
77 /*
78 * We need to be the only thread interacting with the thread
79 * that manages signals for teardown synchronization.
80 */
81 pthread_mutex_lock(&timer_signal.lock);
82
83 /* Ensure we don't have any signal queued for this session. */
84 for (;;) {
85 ret = sigemptyset(&pending_set);
86 if (ret == -1) {
87 PERROR("sigemptyset");
88 }
89 ret = sigpending(&pending_set);
90 if (ret == -1) {
91 PERROR("sigpending");
92 }
93 if (!sigismember(&pending_set, signr)) {
94 break;
95 }
96 caa_cpu_relax();
97 }
98
99 /*
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.
103 */
104 cmm_smp_mb();
105 CMM_STORE_SHARED(timer_signal.qs_done, 0);
106 cmm_smp_mb();
107
108 /*
109 * Kill with LTTNG_SESSIOND_SIG_TEARDOWN, so signal management thread wakes
110 * up.
111 */
112 kill(getpid(), LTTNG_SESSIOND_SIG_TEARDOWN);
113
114 while (!CMM_LOAD_SHARED(timer_signal.qs_done)) {
115 caa_cpu_relax();
116 }
117 cmm_smp_mb();
118
119 pthread_mutex_unlock(&timer_signal.lock);
120 }
121
122 /*
123 * Start a timer on a session that will fire at a given interval
124 * (timer_interval_us) and fire a given signal (signal).
125 *
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).
128 */
129 static
130 int session_timer_start(timer_t *timer_id, struct ltt_session *session,
131 unsigned int timer_interval_us, int signal)
132 {
133 int ret = 0, delete_ret;
134 struct sigevent sev;
135 struct itimerspec its;
136
137 assert(session);
138
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);
143 if (ret == -1) {
144 PERROR("timer_create");
145 goto end;
146 }
147
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;
152
153 ret = timer_settime(*timer_id, 0, &its, NULL);
154 if (ret == -1) {
155 PERROR("timer_settime");
156 goto error_destroy_timer;
157 }
158 goto end;
159
160 error_destroy_timer:
161 delete_ret = timer_delete(*timer_id);
162 if (delete_ret == -1) {
163 PERROR("timer_delete");
164 }
165
166 end:
167 return ret;
168 }
169
170
171 static
172 int session_timer_stop(timer_t *timer_id, int signal)
173 {
174 int ret = 0;
175
176 ret = timer_delete(*timer_id);
177 if (ret == -1) {
178 PERROR("timer_delete");
179 goto end;
180 }
181
182 sessiond_timer_signal_thread_qs(signal);
183 *timer_id = 0;
184 end:
185 return ret;
186 }
187
188 int sessiond_timer_rotate_pending_start(struct ltt_session *session, unsigned int
189 interval_us)
190 {
191 int ret;
192
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);
197
198 return ret;
199 }
200
201 /*
202 * Stop and delete the channel's live timer.
203 */
204 void sessiond_timer_rotate_pending_stop(struct ltt_session *session)
205 {
206 int ret;
207
208 assert(session);
209
210 ret = session_timer_stop(&session->rotate_relay_pending_timer,
211 LTTNG_SESSIOND_SIG_ROTATE_PENDING);
212 if (ret == -1) {
213 ERR("Failed to stop live timer");
214 }
215
216 session->rotate_relay_pending_timer_enabled = 0;
217 }
218
219 /*
220 * Block the RT signals for the entire process. It must be called from the
221 * sessiond main before creating the threads
222 */
223 int sessiond_timer_signal_init(void)
224 {
225 int ret;
226 sigset_t mask;
227
228 /* Block signal for entire process, so only our thread processes it. */
229 setmask(&mask);
230 ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
231 if (ret) {
232 errno = ret;
233 PERROR("pthread_sigmask");
234 return -1;
235 }
236 return 0;
237 }
238
239 static
240 void relay_rotation_pending_timer(struct timer_thread_parameters *ctx,
241 int sig, siginfo_t *si)
242 {
243 int ret;
244 struct ltt_session *session = si->si_value.sival_ptr;
245 assert(session);
246
247 /*
248 * Avoid sending too many requests in case the relay is slower to
249 * respond than the timer period.
250 */
251 if (session->rotate_pending_relay_check_in_progress ||
252 !session->rotate_pending_relay) {
253 goto end;
254 }
255
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");
261 }
262
263 end:
264 return;
265 }
266
267 /*
268 * This thread is the sighandler for the timer signals.
269 */
270 void *sessiond_timer_thread(void *data)
271 {
272 int signr;
273 sigset_t mask;
274 siginfo_t info;
275 struct timer_thread_parameters *ctx = data;
276
277 rcu_register_thread();
278 rcu_thread_online();
279
280 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_NOTIFICATION);
281
282 health_code_update();
283
284 /* Only self thread will receive signal mask. */
285 setmask(&mask);
286 CMM_STORE_SHARED(timer_signal.tid, pthread_self());
287
288 while (1) {
289 health_code_update();
290
291 health_poll_entry();
292 signr = sigwaitinfo(&mask, &info);
293 health_poll_exit();
294
295 /*
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.
299 */
300 if (signr == -1) {
301 if (errno != EINTR) {
302 PERROR("sigwaitinfo");
303 }
304 continue;
305 } else if (signr == LTTNG_SESSIOND_SIG_TEARDOWN) {
306 fprintf(stderr, "TEARDOWN\n");
307 cmm_smp_mb();
308 CMM_STORE_SHARED(timer_signal.qs_done, 1);
309 cmm_smp_mb();
310 DBG("Signal timer metadata thread teardown");
311 } else if (signr == LTTNG_SESSIOND_SIG_EXIT) {
312 fprintf(stderr, "KILL\n");
313 goto end;
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);
317 } else {
318 ERR("Unexpected signal %d\n", info.si_signo);
319 }
320 }
321
322 end:
323 health_unregister(health_sessiond);
324 rcu_thread_offline();
325 rcu_unregister_thread();
326 return NULL;
327 }
This page took 0.036802 seconds and 5 git commands to generate.