Fix: consumer metadata switch timer error handling
[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
31 /*
32 * Set custom signal mask to current thread.
33 */
34 static void setmask(sigset_t *mask)
35 {
36 int ret;
37
38 ret = sigemptyset(mask);
39 if (ret) {
40 PERROR("sigemptyset");
41 }
42 ret = sigaddset(mask, LTTNG_CONSUMER_SIG_SWITCH);
43 if (ret) {
44 PERROR("sigaddset");
45 }
46 ret = sigaddset(mask, LTTNG_CONSUMER_SIG_TEARDOWN);
47 if (ret) {
48 PERROR("sigaddset");
49 }
50 }
51
52 /*
53 * Execute action on a timer switch.
54 */
55 static void metadata_switch_timer(struct lttng_consumer_local_data *ctx,
56 int sig, siginfo_t *si, void *uc)
57 {
58 int ret;
59 struct lttng_consumer_channel *channel;
60
61 channel = si->si_value.sival_ptr;
62 assert(channel);
63
64 if (channel->switch_timer_error) {
65 return;
66 }
67
68 DBG("Switch timer for channel %" PRIu64, channel->key);
69 switch (ctx->type) {
70 case LTTNG_CONSUMER32_UST:
71 case LTTNG_CONSUMER64_UST:
72 ret = lttng_ustconsumer_request_metadata(ctx, channel);
73 if (ret < 0) {
74 channel->switch_timer_error = 1;
75 }
76 break;
77 case LTTNG_CONSUMER_KERNEL:
78 case LTTNG_CONSUMER_UNKNOWN:
79 assert(0);
80 break;
81 }
82 }
83
84 /*
85 * Set the timer for periodical metadata flush.
86 * Should be called only from the recv cmd thread (single thread ensures
87 * mutual exclusion).
88 */
89 void consumer_timer_switch_start(struct lttng_consumer_channel *channel,
90 unsigned int switch_timer_interval)
91 {
92 int ret;
93 struct sigevent sev;
94 struct itimerspec its;
95
96 assert(channel);
97 assert(channel->key);
98
99 if (switch_timer_interval == 0) {
100 return;
101 }
102
103 sev.sigev_notify = SIGEV_SIGNAL;
104 sev.sigev_signo = LTTNG_CONSUMER_SIG_SWITCH;
105 sev.sigev_value.sival_ptr = channel;
106 ret = timer_create(CLOCKID, &sev, &channel->switch_timer);
107 if (ret == -1) {
108 PERROR("timer_create");
109 }
110 channel->switch_timer_enabled = 1;
111
112 its.it_value.tv_sec = switch_timer_interval / 1000000;
113 its.it_value.tv_nsec = switch_timer_interval % 1000000;
114 its.it_interval.tv_sec = its.it_value.tv_sec;
115 its.it_interval.tv_nsec = its.it_value.tv_nsec;
116
117 ret = timer_settime(channel->switch_timer, 0, &its, NULL);
118 if (ret == -1) {
119 PERROR("timer_settime");
120 }
121 }
122
123 /*
124 * Stop and delete timer.
125 * Should be called only from the recv cmd thread (single thread ensures
126 * mutual exclusion).
127 */
128 void consumer_timer_switch_stop(struct lttng_consumer_channel *channel)
129 {
130 int ret;
131 sigset_t pending_set;
132
133 assert(channel);
134
135 ret = timer_delete(channel->switch_timer);
136 if (ret == -1) {
137 PERROR("timer_delete");
138 }
139
140 /* Ensure we don't have any signal queued for this channel. */
141 for (;;) {
142 ret = sigemptyset(&pending_set);
143 if (ret == -1) {
144 PERROR("sigemptyset");
145 }
146 ret = sigpending(&pending_set);
147 if (ret == -1) {
148 PERROR("sigpending");
149 }
150 if (!sigismember(&pending_set, LTTNG_CONSUMER_SIG_SWITCH)) {
151 break;
152 }
153 caa_cpu_relax();
154 }
155
156 /*
157 * From this point, no new signal handler will be fired that would try to
158 * access "chan". However, we still need to wait for any currently
159 * executing handler to complete.
160 */
161 cmm_smp_mb();
162 CMM_STORE_SHARED(timer_signal.qs_done, 0);
163 cmm_smp_mb();
164
165 /*
166 * Kill with LTTNG_CONSUMER_SIG_TEARDOWN, so signal management thread wakes
167 * up.
168 */
169 kill(getpid(), LTTNG_CONSUMER_SIG_TEARDOWN);
170
171 while (!CMM_LOAD_SHARED(timer_signal.qs_done)) {
172 caa_cpu_relax();
173 }
174 cmm_smp_mb();
175 }
176
177 /*
178 * Block the RT signals for the entire process. It must be called from the
179 * consumer main before creating the threads
180 */
181 void consumer_signal_init(void)
182 {
183 int ret;
184 sigset_t mask;
185
186 /* Block signal for entire process, so only our thread processes it. */
187 setmask(&mask);
188 ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
189 if (ret) {
190 errno = ret;
191 PERROR("pthread_sigmask");
192 }
193 }
194
195 /*
196 * This thread is the sighandler for signals LTTNG_CONSUMER_SIG_SWITCH and
197 * LTTNG_CONSUMER_SIG_TEARDOWN that are emitted by the periodic timer to check
198 * if new metadata is available.
199 */
200 void *consumer_timer_metadata_thread(void *data)
201 {
202 int signr;
203 sigset_t mask;
204 siginfo_t info;
205 struct lttng_consumer_local_data *ctx = data;
206
207 /* Only self thread will receive signal mask. */
208 setmask(&mask);
209 CMM_STORE_SHARED(timer_signal.tid, pthread_self());
210
211 while (1) {
212 signr = sigwaitinfo(&mask, &info);
213 if (signr == -1) {
214 if (errno != EINTR) {
215 PERROR("sigwaitinfo");
216 }
217 continue;
218 } else if (signr == LTTNG_CONSUMER_SIG_SWITCH) {
219 metadata_switch_timer(ctx, info.si_signo, &info, NULL);
220 } else if (signr == LTTNG_CONSUMER_SIG_TEARDOWN) {
221 cmm_smp_mb();
222 CMM_STORE_SHARED(timer_signal.qs_done, 1);
223 cmm_smp_mb();
224 DBG("Signal timer metadata thread teardown");
225 } else {
226 ERR("Unexpected signal %d\n", info.si_signo);
227 }
228 }
229
230 return NULL;
231 }
This page took 0.035788 seconds and 6 git commands to generate.