/*
- * Copyright (C) 2011 - Julien Desfossez <julien.desfossez@polymtl.ca>
- * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2011 Julien Desfossez <julien.desfossez@polymtl.ca>
+ * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2 only,
- * as published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _LGPL_SOURCE
static pthread_t channel_thread, data_thread, metadata_thread,
sessiond_thread, metadata_timer_thread, health_thread;
+static bool metadata_timer_thread_online;
/* to count the number of times the user pressed ctrl+c */
static int sigintcount = 0;
/*
* Signal handler for the daemon
*/
-static void sighandler(int sig)
+static void sighandler(int sig, siginfo_t *siginfo, void *arg)
{
if (sig == SIGINT && sigintcount++ == 0) {
DBG("ignoring first SIGINT");
return;
}
+ if (sig == SIGBUS) {
+ int write_ret;
+ const char msg[] = "Received SIGBUS, aborting program.\n";
+
+ lttng_consumer_sigbus_handle(siginfo->si_addr);
+ /*
+ * If ustctl did not catch this signal (triggering a
+ * siglongjmp), abort the program. Otherwise, the execution
+ * will resume from the ust-ctl call which caused this error.
+ *
+ * The return value is ignored since the program aborts anyhow.
+ */
+ write_ret = write(STDERR_FILENO, msg, sizeof(msg));
+ (void) write_ret;
+ abort();
+ }
+
if (ctx) {
lttng_consumer_should_exit(ctx);
}
/*
* Setup signal handler for :
- * SIGINT, SIGTERM, SIGPIPE
+ * SIGINT, SIGTERM, SIGPIPE, SIGBUS
*/
static int set_signal_handler(void)
{
}
sa.sa_mask = sigset;
- sa.sa_flags = 0;
+ sa.sa_flags = SA_SIGINFO;
- sa.sa_handler = sighandler;
+ sa.sa_sigaction = sighandler;
if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
PERROR("sigaction");
return ret;
return ret;
}
+ if ((ret = sigaction(SIGBUS, &sa, NULL)) < 0) {
+ PERROR("sigaction");
+ return ret;
+ }
+
+ sa.sa_flags = 0;
sa.sa_handler = SIG_IGN;
if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) {
PERROR("sigaction");
lttng_opt_quiet = 1;
break;
case 'v':
- lttng_opt_verbose = 1;
+ lttng_opt_verbose = 3;
break;
case 'V':
fprintf(stdout, "%s\n", VERSION);
rcu_register_thread();
+ if (run_as_create_worker(argv[0], NULL, NULL) < 0) {
+ goto exit_set_signal_handler;
+ }
+
if (set_signal_handler()) {
retval = -1;
goto exit_set_signal_handler;
set_ulimit();
}
- if (run_as_create_worker(argv[0]) < 0) {
- goto exit_init_data;
- }
-
/* create the consumer instance with and assign the callbacks */
ctx = lttng_consumer_create(opt_type, lttng_consumer_read_subbuffer,
NULL, lttng_consumer_on_recv_stream, NULL);
}
cmm_smp_mb(); /* Read ready before following operations */
+ /*
+ * Create the thread to manage the UST metadata periodic timer and
+ * live timer.
+ */
+ ret = pthread_create(&metadata_timer_thread, NULL,
+ consumer_timer_thread, (void *) ctx);
+ if (ret) {
+ errno = ret;
+ PERROR("pthread_create");
+ retval = -1;
+ goto exit_metadata_timer_thread;
+ }
+ metadata_timer_thread_online = true;
+
/* Create thread to manage channels */
ret = pthread_create(&channel_thread, default_pthread_attr(),
consumer_thread_channel_poll,
goto exit_sessiond_thread;
}
- /*
- * Create the thread to manage the UST metadata periodic timer and
- * live timer.
- */
- ret = pthread_create(&metadata_timer_thread, default_pthread_attr(),
- consumer_timer_thread, (void *) ctx);
- if (ret) {
- errno = ret;
- PERROR("pthread_create");
- retval = -1;
- goto exit_metadata_timer_thread;
- }
-
- ret = pthread_detach(metadata_timer_thread);
- if (ret) {
- errno = ret;
- PERROR("pthread_detach");
- retval = -1;
- goto exit_metadata_timer_detach;
- }
/*
* This is where we start awaiting program completion (e.g. through
* signal that asks threads to teardown.
*/
-exit_metadata_timer_detach:
-exit_metadata_timer_thread:
ret = pthread_join(sessiond_thread, &status);
if (ret) {
errno = ret;
PERROR("pthread_join sessiond_thread");
retval = -1;
}
-
- ret = consumer_timer_thread_get_channel_monitor_pipe();
- if (ret >= 0) {
- ret = close(ret);
- if (ret) {
- PERROR("close channel monitor pipe");
- }
- }
exit_sessiond_thread:
ret = pthread_join(data_thread, &status);
}
exit_channel_thread:
+exit_metadata_timer_thread:
+
ret = pthread_join(health_thread, &status);
if (ret) {
errno = ret;
exit_health_pipe:
exit_init_data:
- tmp_ctx = ctx;
- ctx = NULL;
- cmm_barrier(); /* Clear ctx for signal handler. */
/*
* Wait for all pending call_rcu work to complete before tearing
* down data structures. call_rcu worker may be trying to
* perform lookups in those structures.
*/
rcu_barrier();
- lttng_consumer_destroy(tmp_ctx);
lttng_consumer_cleanup();
+ /*
+ * Tearing down the metadata timer thread in a
+ * non-fully-symmetric fashion compared to its creation in case
+ * lttng_consumer_cleanup() ends up tearing down timers (which
+ * requires the timer thread to be alive).
+ */
+ if (metadata_timer_thread_online) {
+ /*
+ * Ensure the metadata timer thread exits only after all other
+ * threads are gone, because it is required to perform timer
+ * teardown synchronization.
+ */
+ kill(getpid(), LTTNG_CONSUMER_SIG_EXIT);
+ ret = pthread_join(metadata_timer_thread, &status);
+ if (ret) {
+ errno = ret;
+ PERROR("pthread_join metadata_timer_thread");
+ retval = -1;
+ }
+ ret = consumer_timer_thread_get_channel_monitor_pipe();
+ if (ret >= 0) {
+ ret = close(ret);
+ if (ret) {
+ PERROR("close channel monitor pipe");
+ }
+ }
+ metadata_timer_thread_online = false;
+ }
+ tmp_ctx = ctx;
+ ctx = NULL;
+ cmm_barrier(); /* Clear ctx for signal handler. */
+ lttng_consumer_destroy(tmp_ctx);
if (health_consumerd) {
health_app_destroy(health_consumerd);