LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING = 167, /* Error initializing event notifier error accounting. */
LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL = 168, /* Error event notifier error accounting full. */
LTTNG_ERR_INVALID_ERROR_QUERY_TARGET = 169, /* Invalid error query target. */
+ LTTNG_ERR_BUFFER_FLUSH_FAILED = 170, /* Buffer flush failed */
/* MUST be last element of the manually-assigned section of the enum */
LTTNG_ERR_NR,
/*
* 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_sessiond_SOURCES = utils.c utils.h \
trace-kernel.c trace-kernel.h \
kernel.c kernel.h \
- ust-app.h trace-ust.h notify-apps.h \
+ ust-app.h ust-sigbus.h trace-ust.h notify-apps.h \
lttng-ust-ctl.h lttng-ust-abi.h lttng-ust-error.h \
ust-ctl-internal.h ust-abi-internal.h ust-error-internal.h \
ust-registry.h \
lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \
ust-consumer.c ust-consumer.h notify-apps.c \
ust-metadata.c ust-clock.h agent-thread.c agent-thread.h \
- ust-field-utils.h ust-field-utils.c
+ ust-field-utils.h ust-field-utils.c \
+ ust-sigbus.c
endif
# Add main.c at the end for compile order
#include "manage-apps.h"
#include "manage-kernel.h"
#include "modprobe.h"
+#include "ust-sigbus.h"
static const char *help_msg =
#ifdef LTTNG_EMBED_HELP
* Simply stop all worker threads, leaving main() return gracefully after
* joining all threads and calling cleanup().
*/
-static void sighandler(int sig)
+static void sighandler(int sig, siginfo_t *siginfo, void *arg)
{
switch (sig) {
case SIGINT:
case SIGUSR1:
CMM_STORE_SHARED(recv_child_signal, 1);
break;
+ case SIGBUS:
+ {
+ int write_ret;
+ const char msg[] = "Received SIGBUS, aborting program.\n";
+
+ lttng_ust_handle_sigbus(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();
+ }
default:
break;
}
}
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");
return ret;
}
- DBG("Signal handler set for SIGTERM, SIGUSR1, SIGPIPE and SIGINT");
+ DBG("Signal handler set for SIGTERM, SIGUSR1, SIGPIPE, SIGINT, and SIGBUS");
return ret;
}
unsigned long *pos);
int lttng_ust_ctl_put_subbuf(struct lttng_ust_ctl_consumer_stream *stream);
-void lttng_ust_ctl_flush_buffer(struct lttng_ust_ctl_consumer_stream *stream,
+int lttng_ust_ctl_flush_buffer(struct lttng_ust_ctl_consumer_stream *stream,
int producer_active);
-void lttng_ust_ctl_clear_buffer(struct lttng_ust_ctl_consumer_stream *stream);
+int lttng_ust_ctl_clear_buffer(struct lttng_ust_ctl_consumer_stream *stream);
/* index */
int lttng_ust_ctl_counter_clear(struct lttng_ust_ctl_daemon_counter *counter,
const size_t *dimension_indexes);
+void ustctl_sigbus_handle(void *addr);
+
#endif /* LTTNG_UST_CTL_INTERNAL_H */
--- /dev/null
+/*
+ * Copyright (C) 2021 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <lttng/ust-sigbus.h>
+#include <lttng/ust-ctl.h>
+#include "ust-sigbus.h"
+
+DEFINE_LTTNG_UST_SIGBUS_STATE();
+
+void lttng_ust_handle_sigbus(void *address)
+{
+ lttng_ust_ctl_sigbus_handle(address);
+}
--- /dev/null
+/*
+ * Copyright (C) 2021 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_UST_SIGBUS_H
+#define LTTNG_UST_SIGBUS_H
+
+#ifdef HAVE_LIBLTTNG_UST_CTL
+
+void lttng_ust_handle_sigbus(void *address);
+
+#else /* HAVE_LIBLTTNG_UST_CTL */
+
+static inline
+void lttng_ust_handle_sigbus(void *address)
+{
+}
+
+#endif /* HAVE_LIBLTTNG_UST_CTL */
+
+#endif /* LTTNG_UST_SIGBUS_H */
break;
case LTTNG_CONSUMER32_UST:
case LTTNG_CONSUMER64_UST:
- lttng_ustconsumer_flush_buffer(stream, (int) producer_active);
+ ret = lttng_ustconsumer_flush_buffer(stream, (int) producer_active);
break;
default:
ERR("Unknown consumer_data type");
ERR("Failed to get the current timestamp");
goto end;
}
- lttng_ustconsumer_flush_buffer(stream, 1);
+ ret = lttng_ustconsumer_flush_buffer(stream, 1);
+ if (ret < 0) {
+ ERR("Failed to flush buffer while flushing index");
+ goto end;
+ }
ret = lttng_ustconsumer_take_snapshot(stream);
if (ret < 0) {
if (ret != -EAGAIN) {
break;
case LTTNG_CONSUMER32_UST:
case LTTNG_CONSUMER64_UST:
- lttng_ustconsumer_clear_buffer(stream);
+ ret = lttng_ustconsumer_clear_buffer(stream);
+ if (ret < 0) {
+ ERR("Failed to clear ust stream (ret = %d)", ret);
+ goto end;
+ }
break;
default:
ERR("Unknown consumer_data type");
pthread_mutex_unlock(&stream->lock);
goto end_rcu_unlock;
}
+
+void lttng_consumer_sigbus_handle(void *addr)
+{
+ lttng_ustconsumer_sigbus_handle(addr);
+}
enum lttcomm_return_code lttng_consumer_open_channel_packets(
struct lttng_consumer_channel *channel);
int consumer_metadata_wakeup_pipe(const struct lttng_consumer_channel *channel);
+void lttng_consumer_sigbus_handle(void *addr);
#endif /* LIB_CONSUMER_H */
[ ERROR_INDEX(LTTNG_ERR_EVENT_NOTIFIER_REGISTRATION) ] = "Failed to create event notifier",
[ ERROR_INDEX(LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING) ] = "Failed to initialize event notifier error accounting",
[ ERROR_INDEX(LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL) ] = "No index available in event notifier error accounting",
+ [ ERROR_INDEX(LTTNG_ERR_BUFFER_FLUSH_FAILED) ] = "Failed to flush stream buffer",
/* Last element */
[ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
#define _LGPL_SOURCE
#include <assert.h>
#include <lttng/ust-ctl.h>
+#include <lttng/ust-sigbus.h>
#include <poll.h>
#include <pthread.h>
#include <stdlib.h>
extern struct lttng_consumer_global_data the_consumer_data;
extern int consumer_poll_timeout;
+DEFINE_LTTNG_UST_SIGBUS_STATE();
+
/*
* Free channel object and all streams associated with it. This MUST be used
* only and only if the channel has _NEVER_ been added to the global channel
}
if (!stream->quiescent) {
- lttng_ust_ctl_flush_buffer(stream->ustream, 0);
+ ret = lttng_ust_ctl_flush_buffer(stream->ustream, 0);
+ if (ret) {
+ ERR("Failed to flush buffer while flushing channel: channel key = %" PRIu64 ", channel name = '%s'",
+ chan_key, channel->name);
+ ret = LTTNG_ERR_BUFFER_FLUSH_FAILED;
+ pthread_mutex_unlock(&stream->lock);
+ goto error;
+ }
stream->quiescent = true;
}
next:
* Else, if quiescent, it has already been done by the prior stop.
*/
if (!stream->quiescent) {
- lttng_ust_ctl_flush_buffer(stream->ustream, 0);
+ ret = lttng_ust_ctl_flush_buffer(stream->ustream, 0);
+ if (ret < 0) {
+ ERR("Failed to flush buffer during snapshot of channel: channel key = %" PRIu64 ", channel name = '%s'",
+ channel->key, channel->name);
+ goto error_unlock;
+ }
}
ret = lttng_ustconsumer_take_snapshot(stream);
return ret_func;
}
-void lttng_ust_flush_buffer(
- struct lttng_consumer_stream *stream, int producer_active)
+int lttng_ust_flush_buffer(struct lttng_consumer_stream *stream,
+ int producer_active)
{
assert(stream);
assert(stream->ustream);
- lttng_ust_ctl_flush_buffer(stream->ustream, producer_active);
+ return lttng_ust_ctl_flush_buffer(stream->ustream, producer_active);
}
/*
return lttng_ust_ctl_snapshot_get_consumed(stream->ustream, pos);
}
-void lttng_ustconsumer_flush_buffer(struct lttng_consumer_stream *stream,
+int lttng_ustconsumer_flush_buffer(struct lttng_consumer_stream *stream,
int producer)
{
assert(stream);
assert(stream->ustream);
- lttng_ust_ctl_flush_buffer(stream->ustream, producer);
+ return lttng_ust_ctl_flush_buffer(stream->ustream, producer);
}
-void lttng_ustconsumer_clear_buffer(struct lttng_consumer_stream *stream)
+int lttng_ustconsumer_clear_buffer(struct lttng_consumer_stream *stream)
{
assert(stream);
assert(stream->ustream);
- lttng_ust_ctl_clear_buffer(stream->ustream);
+ return lttng_ust_ctl_clear_buffer(stream->ustream);
}
int lttng_ustconsumer_get_current_timestamp(
pthread_mutex_lock(&stream->lock);
if (!stream->quiescent) {
- lttng_ust_ctl_flush_buffer(stream->ustream, 0);
- stream->quiescent = true;
+ if (lttng_ust_ctl_flush_buffer(stream->ustream, 0) < 0) {
+ ERR("Failed to flush buffer on stream hang-up");
+ } else {
+ stream->quiescent = true;
+ }
}
pthread_mutex_unlock(&stream->lock);
stream->hangup_flush_done = 1;
* a metadata packet. Since the subbuffer is fully filled (with padding,
* if needed), the stream is "quiescent" after this commit.
*/
- lttng_ust_ctl_flush_buffer(stream->ustream, 1);
- stream->quiescent = true;
+ if (lttng_ust_ctl_flush_buffer(stream->ustream, 1)) {
+ ERR("Failed to flush buffer while commiting one metadata packet");
+ ret = -EIO;
+ } else {
+ stream->quiescent = true;
+ }
end:
pthread_mutex_unlock(&stream->chan->metadata_cache->lock);
return ret;
return lttng_ust_ctl_get_stream_id(stream->ustream, stream_id);
}
+
+void lttng_ustconsumer_sigbus_handle(void *addr)
+{
+ lttng_ust_ctl_sigbus_handle(addr);
+}
void lttng_ustconsumer_on_stream_hangup(struct lttng_consumer_stream *stream);
-void lttng_ust_flush_buffer(
- struct lttng_consumer_stream *stream, int producer_active);
-int lttng_ustconsumer_get_stream_id(
- struct lttng_consumer_stream *stream, uint64_t *stream_id);
+int lttng_ust_flush_buffer(struct lttng_consumer_stream *stream,
+ int producer_active);
+int lttng_ustconsumer_get_stream_id(struct lttng_consumer_stream *stream,
+ uint64_t *stream_id);
int lttng_ustconsumer_data_pending(struct lttng_consumer_stream *stream);
void lttng_ustconsumer_close_all_metadata(struct lttng_ht *ht);
void lttng_ustconsumer_close_metadata(struct lttng_consumer_channel *metadata);
enum sync_metadata_status lttng_ustconsumer_sync_metadata(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *metadata);
-void lttng_ustconsumer_flush_buffer(struct lttng_consumer_stream *stream,
+int lttng_ustconsumer_flush_buffer(struct lttng_consumer_stream *stream,
int producer);
-void lttng_ustconsumer_clear_buffer(struct lttng_consumer_stream *stream);
+int lttng_ustconsumer_clear_buffer(struct lttng_consumer_stream *stream);
int lttng_ustconsumer_get_current_timestamp(
struct lttng_consumer_stream *stream, uint64_t *ts);
int lttng_ustconsumer_get_sequence_number(
struct lttng_consumer_stream *stream, uint64_t *seq);
+void lttng_ustconsumer_sigbus_handle(void *addr);
#else /* HAVE_LIBLTTNG_UST_CTL */
return -ENOSYS;
}
static inline
-void lttng_ust_flush_buffer(struct lttng_consumer_stream *stream,
+int lttng_ust_flush_buffer(struct lttng_consumer_stream *stream,
int producer_active)
{
+ return -ENOSYS;
}
static inline
void lttng_ustconsumer_close_all_metadata(struct lttng_ht *ht)
return SYNC_METADATA_STATUS_ERROR;
}
static inline
-void lttng_ustconsumer_flush_buffer(struct lttng_consumer_stream *stream,
+int lttng_ustconsumer_flush_buffer(struct lttng_consumer_stream *stream,
int producer)
{
+ return -ENOSYS;
}
static inline
-void lttng_ustconsumer_clear_buffer(struct lttng_consumer_stream *stream)
+int lttng_ustconsumer_clear_buffer(struct lttng_consumer_stream *stream)
{
+ return -ENOSYS;
}
static inline
int lttng_ustconsumer_get_current_timestamp(
{
return -ENOSYS;
}
+static inline
+void lttng_ustconsumer_sigbus_handle(void *addr)
+{
+}
#endif /* HAVE_LIBLTTNG_UST_CTL */
#endif /* _LTTNG_USTCONSUMER_H */
test_session_LDADD += $(SESSIOND_OBJS)
if HAVE_LIBLTTNG_UST_CTL
+test_session_SOURCES += ust-sigbus.c
test_session_LDADD += $(UST_CTL_LIBS)
endif
#include <bin/lttng-sessiond/ust-app.h>
#include <bin/lttng-sessiond/notification-thread.h>
+#include <lttng/ust-sigbus.h>
+
#include <tap/tap.h>
/* This path will NEVER be created in this test */
/* Number of TAP tests in this file */
#define NUM_TESTS 16
+DEFINE_LTTNG_UST_SIGBUS_STATE();
+
/* For error.h */
int lttng_opt_quiet = 1;
int lttng_opt_verbose;
--- /dev/null
+/*
+ * Copyright (C) 2021 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <lttng/ust-sigbus.h>
+
+DEFINE_LTTNG_UST_SIGBUS_STATE();