/*
- * 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
#include <poll.h>
#include <unistd.h>
#include <sys/mman.h>
-#include <assert.h>
#include <urcu/compiler.h>
#include <ulimit.h>
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;
}
- /*
- * Ignore SIGPIPE because it should not stop the consumer whenever a
- * SIGPIPE is catched through a FD operation.
- */
- if (sig == SIGPIPE) {
- 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) {
/*
* Setup signal handler for :
- * SIGINT, SIGTERM, SIGPIPE
+ * SIGINT, SIGTERM, SIGPIPE, SIGBUS
*/
static int set_signal_handler(void)
{
return ret;
}
- sa.sa_handler = sighandler;
sa.sa_mask = sigset;
- sa.sa_flags = 0;
+ sa.sa_flags = SA_SIGINFO;
+
+ 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");
return ret;
lttng_opt_quiet = 1;
break;
case 'v':
- lttng_opt_verbose = 1;
+ lttng_opt_verbose = 3;
break;
case 'V':
fprintf(stdout, "%s\n", VERSION);
void *status;
struct lttng_consumer_local_data *tmp_ctx;
+ 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;
goto exit_health_consumerd_cleanup;
}
- /* Set up max poll set size */
- if (lttng_poll_set_max_size()) {
- retval = -1;
- goto exit_init_data;
- }
-
if (*command_sock_path == '\0') {
switch (opt_type) {
case LTTNG_CONSUMER_KERNEL:
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);
}
/* Create thread to manage the client socket */
- ret = pthread_create(&health_thread, NULL,
+ ret = pthread_create(&health_thread, default_pthread_attr(),
thread_manage_health, (void *) NULL);
if (ret) {
errno = ret;
}
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, NULL,
+ ret = pthread_create(&channel_thread, default_pthread_attr(),
consumer_thread_channel_poll,
(void *) ctx);
if (ret) {
}
/* Create thread to manage the polling/writing of trace metadata */
- ret = pthread_create(&metadata_thread, NULL,
+ ret = pthread_create(&metadata_thread, default_pthread_attr(),
consumer_thread_metadata_poll,
(void *) ctx);
if (ret) {
}
/* Create thread to manage the polling/writing of trace data */
- ret = pthread_create(&data_thread, NULL, consumer_thread_data_poll,
- (void *) ctx);
+ ret = pthread_create(&data_thread, default_pthread_attr(),
+ consumer_thread_data_poll, (void *) ctx);
if (ret) {
errno = ret;
PERROR("pthread_create");
goto exit_data_thread;
}
- /* Create the thread to manage the receive of fd */
- ret = pthread_create(&sessiond_thread, NULL,
+ /* Create the thread to manage the reception of fds */
+ ret = pthread_create(&sessiond_thread, default_pthread_attr(),
consumer_thread_sessiond_poll,
(void *) ctx);
if (ret) {
goto exit_sessiond_thread;
}
- /*
- * 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;
- }
-
- 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;
}
exit_channel_thread:
+exit_metadata_timer_thread:
+
ret = pthread_join(health_thread, &status);
if (ret) {
errno = ret;
exit_health_pipe:
exit_init_data:
+ /*
+ * 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_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);
- lttng_consumer_cleanup();
if (health_consumerd) {
health_app_destroy(health_consumerd);
exit_options:
exit_set_signal_handler:
+ rcu_unregister_thread();
+
if (!retval) {
exit(EXIT_SUCCESS);
} else {