2 * Copyright (C) 2012 - Julien Desfossez <julien.desfossez@efficios.com>
3 * David Goulet <dgoulet@efficios.com>
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.
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
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.
24 #include <common/common.h>
26 #include "consumer-timer.h"
27 #include "ust-consumer/ust-consumer.h"
29 static struct timer_signal_data timer_signal
= {
33 .lock
= PTHREAD_MUTEX_INITIALIZER
,
37 * Set custom signal mask to current thread.
39 static void setmask(sigset_t
*mask
)
43 ret
= sigemptyset(mask
);
45 PERROR("sigemptyset");
47 ret
= sigaddset(mask
, LTTNG_CONSUMER_SIG_SWITCH
);
51 ret
= sigaddset(mask
, LTTNG_CONSUMER_SIG_TEARDOWN
);
58 * Execute action on a timer switch.
60 * Beware: metadata_switch_timer() should *never* take a mutex also held
61 * while consumer_timer_switch_stop() is called. It would result in
64 static void metadata_switch_timer(struct lttng_consumer_local_data
*ctx
,
65 int sig
, siginfo_t
*si
, void *uc
)
68 struct lttng_consumer_channel
*channel
;
70 channel
= si
->si_value
.sival_ptr
;
73 if (channel
->switch_timer_error
) {
77 DBG("Switch timer for channel %" PRIu64
, channel
->key
);
79 case LTTNG_CONSUMER32_UST
:
80 case LTTNG_CONSUMER64_UST
:
82 * Locks taken by lttng_ustconsumer_request_metadata():
83 * - metadata_socket_lock
84 * - Calling lttng_ustconsumer_recv_metadata():
85 * - consumer_data.lock
87 * - channel->metadata_cache->lock
88 * - Calling consumer_metadata_cache_flushed():
89 * - channel->timer_lock
90 * - channel->metadata_cache->lock
92 * Ensure that neither consumer_data.lock nor
93 * channel->lock are taken within this function, since
94 * they are held while consumer_timer_switch_stop() is
97 ret
= lttng_ustconsumer_request_metadata(ctx
, channel
, 1);
99 channel
->switch_timer_error
= 1;
102 case LTTNG_CONSUMER_KERNEL
:
103 case LTTNG_CONSUMER_UNKNOWN
:
110 void consumer_timer_signal_thread_qs(unsigned int signr
)
112 sigset_t pending_set
;
116 * We need to be the only thread interacting with the thread
117 * that manages signals for teardown synchronization.
119 pthread_mutex_lock(&timer_signal
.lock
);
121 /* Ensure we don't have any signal queued for this channel. */
123 ret
= sigemptyset(&pending_set
);
125 PERROR("sigemptyset");
127 ret
= sigpending(&pending_set
);
129 PERROR("sigpending");
131 if (!sigismember(&pending_set
, LTTNG_CONSUMER_SIG_SWITCH
)) {
138 * From this point, no new signal handler will be fired that would try to
139 * access "chan". However, we still need to wait for any currently
140 * executing handler to complete.
143 CMM_STORE_SHARED(timer_signal
.qs_done
, 0);
147 * Kill with LTTNG_CONSUMER_SIG_TEARDOWN, so signal management thread wakes
150 kill(getpid(), LTTNG_CONSUMER_SIG_TEARDOWN
);
152 while (!CMM_LOAD_SHARED(timer_signal
.qs_done
)) {
157 pthread_mutex_unlock(&timer_signal
.lock
);
161 * Set the timer for periodical metadata flush.
163 void consumer_timer_switch_start(struct lttng_consumer_channel
*channel
,
164 unsigned int switch_timer_interval
)
168 struct itimerspec its
;
171 assert(channel
->key
);
173 if (switch_timer_interval
== 0) {
177 sev
.sigev_notify
= SIGEV_SIGNAL
;
178 sev
.sigev_signo
= LTTNG_CONSUMER_SIG_SWITCH
;
179 sev
.sigev_value
.sival_ptr
= channel
;
180 ret
= timer_create(CLOCKID
, &sev
, &channel
->switch_timer
);
182 PERROR("timer_create");
184 channel
->switch_timer_enabled
= 1;
186 its
.it_value
.tv_sec
= switch_timer_interval
/ 1000000;
187 its
.it_value
.tv_nsec
= switch_timer_interval
% 1000000;
188 its
.it_interval
.tv_sec
= its
.it_value
.tv_sec
;
189 its
.it_interval
.tv_nsec
= its
.it_value
.tv_nsec
;
191 ret
= timer_settime(channel
->switch_timer
, 0, &its
, NULL
);
193 PERROR("timer_settime");
198 * Stop and delete timer.
200 void consumer_timer_switch_stop(struct lttng_consumer_channel
*channel
)
206 ret
= timer_delete(channel
->switch_timer
);
208 PERROR("timer_delete");
211 consumer_timer_signal_thread_qs(LTTNG_CONSUMER_SIG_SWITCH
);
213 channel
->switch_timer
= 0;
214 channel
->switch_timer_enabled
= 0;
218 * Block the RT signals for the entire process. It must be called from the
219 * consumer main before creating the threads
221 void consumer_signal_init(void)
226 /* Block signal for entire process, so only our thread processes it. */
228 ret
= pthread_sigmask(SIG_BLOCK
, &mask
, NULL
);
231 PERROR("pthread_sigmask");
236 * This thread is the sighandler for signals LTTNG_CONSUMER_SIG_SWITCH and
237 * LTTNG_CONSUMER_SIG_TEARDOWN that are emitted by the periodic timer to check
238 * if new metadata is available.
240 void *consumer_timer_metadata_thread(void *data
)
245 struct lttng_consumer_local_data
*ctx
= data
;
247 /* Only self thread will receive signal mask. */
249 CMM_STORE_SHARED(timer_signal
.tid
, pthread_self());
252 signr
= sigwaitinfo(&mask
, &info
);
254 if (errno
!= EINTR
) {
255 PERROR("sigwaitinfo");
258 } else if (signr
== LTTNG_CONSUMER_SIG_SWITCH
) {
259 metadata_switch_timer(ctx
, info
.si_signo
, &info
, NULL
);
260 } else if (signr
== LTTNG_CONSUMER_SIG_TEARDOWN
) {
262 CMM_STORE_SHARED(timer_signal
.qs_done
, 1);
264 DBG("Signal timer metadata thread teardown");
266 ERR("Unexpected signal %d\n", info
.si_signo
);