f9c41c0eb0f8f9f32def26028f743ce7df45d322
[lttng-tools.git] / src / common / consumer-timer.c
1 /*
2 * Copyright (C) 2012 - Julien Desfossez <julien.desfossez@efficios.com>
3 * David Goulet <dgoulet@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <assert.h>
21 #include <inttypes.h>
22 #include <signal.h>
23
24 #include <common/common.h>
25
26 #include "consumer-timer.h"
27 #include "ust-consumer/ust-consumer.h"
28
29 static struct timer_signal_data timer_signal = {
30 .tid = 0,
31 .setup_done = 0,
32 .qs_done = 0,
33 .lock = PTHREAD_MUTEX_INITIALIZER,
34 };
35
36 /*
37 * Set custom signal mask to current thread.
38 */
39 static void setmask(sigset_t *mask)
40 {
41 int ret;
42
43 ret = sigemptyset(mask);
44 if (ret) {
45 PERROR("sigemptyset");
46 }
47 ret = sigaddset(mask, LTTNG_CONSUMER_SIG_SWITCH);
48 if (ret) {
49 PERROR("sigaddset");
50 }
51 ret = sigaddset(mask, LTTNG_CONSUMER_SIG_TEARDOWN);
52 if (ret) {
53 PERROR("sigaddset");
54 }
55 }
56
57 /*
58 * Execute action on a timer switch.
59 */
60 static void metadata_switch_timer(struct lttng_consumer_local_data *ctx,
61 int sig, siginfo_t *si, void *uc)
62 {
63 int ret;
64 struct lttng_consumer_channel *channel;
65
66 channel = si->si_value.sival_ptr;
67 assert(channel);
68
69 if (channel->switch_timer_error) {
70 return;
71 }
72
73 DBG("Switch timer for channel %" PRIu64, channel->key);
74 switch (ctx->type) {
75 case LTTNG_CONSUMER32_UST:
76 case LTTNG_CONSUMER64_UST:
77 ret = lttng_ustconsumer_request_metadata(ctx, channel);
78 if (ret < 0) {
79 channel->switch_timer_error = 1;
80 }
81 break;
82 case LTTNG_CONSUMER_KERNEL:
83 case LTTNG_CONSUMER_UNKNOWN:
84 assert(0);
85 break;
86 }
87 }
88
89 static
90 void consumer_timer_signal_thread_qs(unsigned int signr)
91 {
92 sigset_t pending_set;
93 int ret;
94
95 /*
96 * We need to be the only thread interacting with the thread
97 * that manages signals for teardown synchronization.
98 */
99 pthread_mutex_lock(&timer_signal.lock);
100
101 /* Ensure we don't have any signal queued for this channel. */
102 for (;;) {
103 ret = sigemptyset(&pending_set);
104 if (ret == -1) {
105 PERROR("sigemptyset");
106 }
107 ret = sigpending(&pending_set);
108 if (ret == -1) {
109 PERROR("sigpending");
110 }
111 if (!sigismember(&pending_set, LTTNG_CONSUMER_SIG_SWITCH)) {
112 break;
113 }
114 caa_cpu_relax();
115 }
116
117 /*
118 * From this point, no new signal handler will be fired that would try to
119 * access "chan". However, we still need to wait for any currently
120 * executing handler to complete.
121 */
122 cmm_smp_mb();
123 CMM_STORE_SHARED(timer_signal.qs_done, 0);
124 cmm_smp_mb();
125
126 /*
127 * Kill with LTTNG_CONSUMER_SIG_TEARDOWN, so signal management thread wakes
128 * up.
129 */
130 kill(getpid(), LTTNG_CONSUMER_SIG_TEARDOWN);
131
132 while (!CMM_LOAD_SHARED(timer_signal.qs_done)) {
133 caa_cpu_relax();
134 }
135 cmm_smp_mb();
136
137 pthread_mutex_unlock(&timer_signal.lock);
138 }
139
140 /*
141 * Set the timer for periodical metadata flush.
142 */
143 void consumer_timer_switch_start(struct lttng_consumer_channel *channel,
144 unsigned int switch_timer_interval)
145 {
146 int ret;
147 struct sigevent sev;
148 struct itimerspec its;
149
150 assert(channel);
151 assert(channel->key);
152
153 if (switch_timer_interval == 0) {
154 return;
155 }
156
157 sev.sigev_notify = SIGEV_SIGNAL;
158 sev.sigev_signo = LTTNG_CONSUMER_SIG_SWITCH;
159 sev.sigev_value.sival_ptr = channel;
160 ret = timer_create(CLOCKID, &sev, &channel->switch_timer);
161 if (ret == -1) {
162 PERROR("timer_create");
163 }
164 channel->switch_timer_enabled = 1;
165
166 its.it_value.tv_sec = switch_timer_interval / 1000000;
167 its.it_value.tv_nsec = switch_timer_interval % 1000000;
168 its.it_interval.tv_sec = its.it_value.tv_sec;
169 its.it_interval.tv_nsec = its.it_value.tv_nsec;
170
171 ret = timer_settime(channel->switch_timer, 0, &its, NULL);
172 if (ret == -1) {
173 PERROR("timer_settime");
174 }
175 }
176
177 /*
178 * Stop and delete timer.
179 */
180 void consumer_timer_switch_stop(struct lttng_consumer_channel *channel)
181 {
182 int ret;
183
184 assert(channel);
185
186 ret = timer_delete(channel->switch_timer);
187 if (ret == -1) {
188 PERROR("timer_delete");
189 }
190
191 consumer_timer_signal_thread_qs(LTTNG_CONSUMER_SIG_SWITCH);
192
193 channel->switch_timer = 0;
194 channel->switch_timer_enabled = 0;
195 }
196
197 /*
198 * Block the RT signals for the entire process. It must be called from the
199 * consumer main before creating the threads
200 */
201 void consumer_signal_init(void)
202 {
203 int ret;
204 sigset_t mask;
205
206 /* Block signal for entire process, so only our thread processes it. */
207 setmask(&mask);
208 ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
209 if (ret) {
210 errno = ret;
211 PERROR("pthread_sigmask");
212 }
213 }
214
215 /*
216 * This thread is the sighandler for signals LTTNG_CONSUMER_SIG_SWITCH and
217 * LTTNG_CONSUMER_SIG_TEARDOWN that are emitted by the periodic timer to check
218 * if new metadata is available.
219 */
220 void *consumer_timer_metadata_thread(void *data)
221 {
222 int signr;
223 sigset_t mask;
224 siginfo_t info;
225 struct lttng_consumer_local_data *ctx = data;
226
227 /* Only self thread will receive signal mask. */
228 setmask(&mask);
229 CMM_STORE_SHARED(timer_signal.tid, pthread_self());
230
231 while (1) {
232 signr = sigwaitinfo(&mask, &info);
233 if (signr == -1) {
234 if (errno != EINTR) {
235 PERROR("sigwaitinfo");
236 }
237 continue;
238 } else if (signr == LTTNG_CONSUMER_SIG_SWITCH) {
239 metadata_switch_timer(ctx, info.si_signo, &info, NULL);
240 } else if (signr == LTTNG_CONSUMER_SIG_TEARDOWN) {
241 cmm_smp_mb();
242 CMM_STORE_SHARED(timer_signal.qs_done, 1);
243 cmm_smp_mb();
244 DBG("Signal timer metadata thread teardown");
245 } else {
246 ERR("Unexpected signal %d\n", info.si_signo);
247 }
248 }
249
250 return NULL;
251 }
This page took 0.033006 seconds and 3 git commands to generate.