#define _LGPL_SOURCE
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/prctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <urcu/uatomic.h>
#include <urcu/futex.h>
+#include <urcu/compiler.h>
-#include <ust-comm.h>
#include <lttng/ust-events.h>
-#include <lttng/usterr-signal-safe.h>
#include <lttng/ust-abi.h>
-#include <lttng/tracepoint.h>
-#include <lttng/tracepoint-internal.h>
#include <lttng/ust.h>
-#include "ltt-tracer-core.h"
+#include <lttng/ust-error.h>
+#include <lttng/ust-ctl.h>
+#include <urcu/tls-compat.h>
+#include <ust-comm.h>
+#include <usterr-signal-safe.h>
+#include <helper.h>
+#include "tracepoint-internal.h"
+#include "lttng-tracer-core.h"
+#include "compat.h"
+#include "../libringbuffer/tlsfixup.h"
/*
* Has lttng ust comm constructor been called ?
*/
static int sem_count = { 2 };
+/*
+ * Counting nesting within lttng-ust. Used to ensure that calling fork()
+ * from liblttng-ust does not execute the pre/post fork handlers.
+ */
+static DEFINE_URCU_TLS(int, lttng_ust_nest_count);
+
/*
* Info about socket and associated listener thread.
*/
int constructor_sem_posted;
int allowed;
int global;
+ int thread_active;
char sock_path[PATH_MAX];
int socket;
.root_handle = -1,
.allowed = 1,
+ .thread_active = 0,
.sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK,
.socket = -1,
.global = 0,
.root_handle = -1,
.allowed = 0, /* Check setuid bit first */
+ .thread_active = 0,
.socket = -1,
};
static int wait_poll_fallback;
-extern void ltt_ring_buffer_client_overwrite_init(void);
-extern void ltt_ring_buffer_client_discard_init(void);
-extern void ltt_ring_buffer_metadata_client_init(void);
-extern void ltt_ring_buffer_client_overwrite_exit(void);
-extern void ltt_ring_buffer_client_discard_exit(void);
-extern void ltt_ring_buffer_metadata_client_exit(void);
+static const char *cmd_name_mapping[] = {
+ [ LTTNG_UST_RELEASE ] = "Release",
+ [ LTTNG_UST_SESSION ] = "Create Session",
+ [ LTTNG_UST_TRACER_VERSION ] = "Get Tracer Version",
+
+ [ LTTNG_UST_TRACEPOINT_LIST ] = "Create Tracepoint List",
+ [ LTTNG_UST_WAIT_QUIESCENT ] = "Wait for Quiescent State",
+ [ LTTNG_UST_REGISTER_DONE ] = "Registration Done",
+ [ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List",
+
+ /* Session FD commands */
+ [ LTTNG_UST_CHANNEL ] = "Create Channel",
+ [ LTTNG_UST_SESSION_START ] = "Start Session",
+ [ LTTNG_UST_SESSION_STOP ] = "Stop Session",
+
+ /* Channel FD commands */
+ [ LTTNG_UST_STREAM ] = "Create Stream",
+ [ LTTNG_UST_EVENT ] = "Create Event",
+
+ /* Event and Channel FD commands */
+ [ LTTNG_UST_CONTEXT ] = "Create Context",
+ [ LTTNG_UST_FLUSH_BUFFER ] = "Flush Buffer",
+
+ /* Event, Channel and Session commands */
+ [ LTTNG_UST_ENABLE ] = "Enable",
+ [ LTTNG_UST_DISABLE ] = "Disable",
+
+ /* Tracepoint list commands */
+ [ LTTNG_UST_TRACEPOINT_LIST_GET ] = "List Next Tracepoint",
+ [ LTTNG_UST_TRACEPOINT_FIELD_LIST_GET ] = "List Next Tracepoint Field",
+
+ /* Event FD commands */
+ [ LTTNG_UST_FILTER ] = "Create Filter",
+};
+
+extern void lttng_ring_buffer_client_overwrite_init(void);
+extern void lttng_ring_buffer_client_discard_init(void);
+extern void lttng_ring_buffer_metadata_client_init(void);
+extern void lttng_ring_buffer_client_overwrite_exit(void);
+extern void lttng_ring_buffer_client_discard_exit(void);
+extern void lttng_ring_buffer_metadata_client_exit(void);
+
+/*
+ * Force a read (imply TLS fixup for dlopen) of TLS variables.
+ */
+static
+void lttng_fixup_nest_count_tls(void)
+{
+ asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count)));
+}
+
+static
+void print_cmd(int cmd, int handle)
+{
+ const char *cmd_name = "Unknown";
+
+ if (cmd_name_mapping[cmd]) {
+ cmd_name = cmd_name_mapping[cmd];
+ }
+ DBG("Message Received \"%s\", Handle \"%s\" (%d)", cmd_name,
+ lttng_ust_obj_get_name(handle), handle);
+}
static
int setup_local_apps(void)
* Disallow per-user tracing for setuid binaries.
*/
if (uid != geteuid()) {
- local_apps.allowed = 0;
+ assert(local_apps.allowed == 0);
return 0;
- } else {
- local_apps.allowed = 1;
}
home_dir = (const char *) getenv("HOME");
- if (!home_dir)
+ if (!home_dir) {
+ WARN("HOME environment variable not set. Disabling LTTng-UST per-user tracing.");
+ assert(local_apps.allowed == 0);
return -ENOENT;
+ }
+ local_apps.allowed = 1;
snprintf(local_apps.sock_path, PATH_MAX,
DEFAULT_HOME_APPS_UNIX_SOCK, home_dir);
snprintf(local_apps.wait_shm_path, PATH_MAX,
int register_app_to_sessiond(int socket)
{
ssize_t ret;
- int prctl_ret;
struct {
uint32_t major;
uint32_t minor;
pid_t ppid;
uid_t uid;
gid_t gid;
+ uint32_t bits_per_long;
char name[16]; /* process name */
} reg_msg;
reg_msg.ppid = getppid();
reg_msg.uid = getuid();
reg_msg.gid = getgid();
- prctl_ret = prctl(PR_GET_NAME, (unsigned long) reg_msg.name, 0, 0, 0);
- if (prctl_ret) {
- ERR("Error executing prctl");
- return -errno;
- }
+ reg_msg.bits_per_long = CAA_BITS_PER_LONG;
+ lttng_ust_getprocname(reg_msg.name);
ret = ustcomm_send_unix_sock(socket, ®_msg, sizeof(reg_msg));
if (ret >= 0 && ret != sizeof(reg_msg))
case sizeof(*lur):
DBG("message successfully sent");
return 0;
- case -1:
- if (errno == ECONNRESET) {
- printf("remote end closed connection\n");
+ default:
+ if (len == -ECONNRESET) {
+ DBG("remote end closed connection");
return 0;
}
- return -1;
- default:
- printf("incorrect message size: %zd\n", len);
- return -1;
+ if (len < 0)
+ return len;
+ DBG("incorrect message size: %zd", len);
+ return -EINVAL;
}
}
int ret = 0;
const struct lttng_ust_objd_ops *ops;
struct ustcomm_ust_reply lur;
- int shm_fd, wait_fd;
+ union ust_args args;
+ ssize_t len;
ust_lock();
memset(&lur, 0, sizeof(lur));
if (lttng_ust_comm_should_quit) {
- ret = -EPERM;
+ ret = -LTTNG_UST_ERR_EXITING;
goto end;
}
else
ret = lttng_ust_objd_unref(lum->handle);
break;
+ case LTTNG_UST_FILTER:
+ {
+ /* Receive filter data */
+ struct lttng_ust_filter_bytecode_node *bytecode;
+
+ if (lum->u.filter.data_size > FILTER_BYTECODE_MAX_LEN) {
+ ERR("Filter data size is too large: %u bytes",
+ lum->u.filter.data_size);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (lum->u.filter.reloc_offset > lum->u.filter.data_size) {
+ ERR("Filter reloc offset %u is not within data",
+ lum->u.filter.reloc_offset);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ bytecode = zmalloc(sizeof(*bytecode) + lum->u.filter.data_size);
+ if (!bytecode) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ len = ustcomm_recv_unix_sock(sock, bytecode->bc.data,
+ lum->u.filter.data_size);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ free(bytecode);
+ goto error;
+ default:
+ if (len == lum->u.filter.data_size) {
+ DBG("filter data received");
+ break;
+ } else if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection", sock_info->name);
+ ret = len;
+ free(bytecode);
+ goto error;
+ }
+ ret = len;
+ goto end;
+ } else {
+ DBG("incorrect filter data message size: %zd", len);
+ ret = -EINVAL;
+ free(bytecode);
+ goto end;
+ }
+ }
+ bytecode->bc.len = lum->u.filter.data_size;
+ bytecode->bc.reloc_offset = lum->u.filter.reloc_offset;
+ bytecode->bc.seqnum = lum->u.filter.seqnum;
+ if (ops->cmd) {
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) bytecode,
+ &args, sock_info);
+ if (ret) {
+ free(bytecode);
+ }
+ /* don't free bytecode if everything went fine. */
+ } else {
+ ret = -ENOSYS;
+ free(bytecode);
+ }
+ break;
+ }
+ case LTTNG_UST_CHANNEL:
+ {
+ void *chan_data;
+
+ len = ustcomm_recv_channel_from_sessiond(sock,
+ &chan_data, lum->u.channel.len);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error;
+ default:
+ if (len == lum->u.channel.len) {
+ DBG("channel data received");
+ break;
+ } else if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection", sock_info->name);
+ ret = len;
+ goto error;
+ }
+ ret = len;
+ goto end;
+ } else {
+ DBG("incorrect channel data message size: %zd", len);
+ ret = -EINVAL;
+ goto end;
+ }
+ }
+ args.channel.chan_data = chan_data;
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
+ case LTTNG_UST_STREAM:
+ {
+ /* Receive shm_fd, wakeup_fd */
+ ret = ustcomm_recv_stream_from_sessiond(sock,
+ &lum->u.stream.len,
+ &args.stream.shm_fd,
+ &args.stream.wakeup_fd);
+ if (ret) {
+ goto end;
+ }
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
default:
if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
- (unsigned long) &lum->u);
+ (unsigned long) &lum->u,
+ &args, sock_info);
else
ret = -ENOSYS;
break;
lur.cmd = lum->cmd;
lur.ret_val = ret;
if (ret >= 0) {
- lur.ret_code = USTCOMM_OK;
+ lur.ret_code = LTTNG_UST_OK;
} else {
- //lur.ret_code = USTCOMM_SESSION_FAIL;
- lur.ret_code = ret;
- }
- switch (lum->cmd) {
- case LTTNG_UST_STREAM:
/*
- * Special-case reply to send stream info.
- * Use lum.u output.
+ * Use -LTTNG_UST_ERR as wildcard for UST internal
+ * error that are not caused by the transport, except if
+ * we already have a more precise error message to
+ * report.
*/
- lur.u.stream.memory_map_size = lum->u.stream.memory_map_size;
- shm_fd = lum->u.stream.shm_fd;
- wait_fd = lum->u.stream.wait_fd;
- break;
- case LTTNG_UST_METADATA:
- case LTTNG_UST_CHANNEL:
- lur.u.channel.memory_map_size = lum->u.channel.memory_map_size;
- shm_fd = lum->u.channel.shm_fd;
- wait_fd = lum->u.channel.wait_fd;
- break;
- case LTTNG_UST_VERSION:
- lur.u.version = lum->u.version;
- break;
- case LTTNG_UST_TRACEPOINT_LIST_GET:
- memcpy(lur.u.tracepoint_list_entry,
- lum->u.tracepoint_list_entry,
- LTTNG_UST_SYM_NAME_LEN);
- break;
+ if (ret > -LTTNG_UST_ERR) {
+ /* Translate code to UST error. */
+ switch (ret) {
+ case -EEXIST:
+ lur.ret_code = -LTTNG_UST_ERR_EXIST;
+ break;
+ case -EINVAL:
+ lur.ret_code = -LTTNG_UST_ERR_INVAL;
+ break;
+ case -ENOENT:
+ lur.ret_code = -LTTNG_UST_ERR_NOENT;
+ break;
+ case -EPERM:
+ lur.ret_code = -LTTNG_UST_ERR_PERM;
+ break;
+ case -ENOSYS:
+ lur.ret_code = -LTTNG_UST_ERR_NOSYS;
+ break;
+ default:
+ lur.ret_code = -LTTNG_UST_ERR;
+ break;
+ }
+ } else {
+ lur.ret_code = ret;
+ }
+ }
+ if (ret >= 0) {
+ switch (lum->cmd) {
+ case LTTNG_UST_TRACER_VERSION:
+ lur.u.version = lum->u.version;
+ break;
+ case LTTNG_UST_TRACEPOINT_LIST_GET:
+ memcpy(&lur.u.tracepoint, &lum->u.tracepoint, sizeof(lur.u.tracepoint));
+ break;
+ }
}
+ DBG("Return value: %d", lur.ret_val);
ret = send_reply(sock, &lur);
if (ret < 0) {
- perror("error sending reply");
+ DBG("error sending reply");
goto error;
}
- if ((lum->cmd == LTTNG_UST_STREAM
- || lum->cmd == LTTNG_UST_CHANNEL
- || lum->cmd == LTTNG_UST_METADATA)
- && lur.ret_code == USTCOMM_OK) {
- /* we also need to send the file descriptors. */
- ret = ustcomm_send_fds_unix_sock(sock,
- &shm_fd, &shm_fd,
- 1, sizeof(int));
- if (ret < 0) {
- perror("send shm_fd");
- goto error;
- }
- ret = ustcomm_send_fds_unix_sock(sock,
- &wait_fd, &wait_fd,
- 1, sizeof(int));
- if (ret < 0) {
- perror("send wait_fd");
- goto error;
+ /*
+ * LTTNG_UST_TRACEPOINT_FIELD_LIST_GET needs to send the field
+ * after the reply.
+ */
+ if (lur.ret_code == LTTNG_UST_OK) {
+ switch (lum->cmd) {
+ case LTTNG_UST_TRACEPOINT_FIELD_LIST_GET:
+ len = ustcomm_send_unix_sock(sock,
+ &args.field_list.entry,
+ sizeof(args.field_list.entry));
+ if (len < 0) {
+ ret = len;
+ goto error;
+ }
+ if (len != sizeof(args.field_list.entry)) {
+ ret = -EINVAL;
+ goto error;
+ }
}
}
+
error:
ust_unlock();
return ret;
}
static
-void cleanup_sock_info(struct sock_info *sock_info)
+void cleanup_sock_info(struct sock_info *sock_info, int exiting)
{
int ret;
if (sock_info->socket != -1) {
- ret = close(sock_info->socket);
+ ret = ustcomm_close_unix_sock(sock_info->socket);
if (ret) {
ERR("Error closing apps socket");
}
sock_info->root_handle = -1;
}
sock_info->constructor_sem_posted = 0;
- if (sock_info->wait_shm_mmap) {
+ /*
+ * wait_shm_mmap is used by listener threads outside of the
+ * ust lock, so we cannot tear it down ourselves, because we
+ * cannot join on these threads. Leave this task to the OS
+ * process exit.
+ */
+ if (!exiting && sock_info->wait_shm_mmap) {
ret = munmap(sock_info->wait_shm_mmap, sysconf(_SC_PAGE_SIZE));
if (ret) {
ERR("Error unmapping wait shm");
* If the open failed because the file did not exist, try
* creating it ourself.
*/
+ URCU_TLS(lttng_ust_nest_count)++;
pid = fork();
+ URCU_TLS(lttng_ust_nest_count)--;
if (pid > 0) {
int status;
* shared memory map will have been created.
*/
pid = wait(&status);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
wait_shm_fd = -1;
goto end;
}
ret = ftruncate(wait_shm_fd, mmap_size);
if (ret) {
PERROR("ftruncate");
- exit(EXIT_FAILURE);
+ _exit(EXIT_FAILURE);
}
- exit(EXIT_SUCCESS);
+ _exit(EXIT_SUCCESS);
}
/*
* For local shm, we need to have rw access to accept
*/
if (!sock_info->global && errno != EACCES) {
ERR("Error opening shm %s", sock_info->wait_shm_path);
- exit(EXIT_FAILURE);
+ _exit(EXIT_FAILURE);
}
/*
* The shm exists, but we cannot open it RW. Report
* success.
*/
- exit(EXIT_SUCCESS);
+ _exit(EXIT_SUCCESS);
} else {
return -1;
}
if (ret < 0) {
if (errno == EFAULT) {
wait_poll_fallback = 1;
- WARN(
+ DBG(
"Linux kernels 2.6.33 to 3.0 (with the exception of stable versions) "
"do not support FUTEX_WAKE on read-only memory mappings correctly. "
"Please upgrade your kernel "
"(fix is commit 9ea71503a8ed9184d2d0b8ccc4d269d05f7940ae in Linux kernel "
"mainline). LTTng-UST will use polling mode fallback.");
+ if (ust_debug())
+ PERROR("futex");
}
- PERROR("futex");
}
}
return;
* This thread does not allocate any resource, except within
* handle_message, within mutex protection. This mutex protects against
* fork and exit.
- * The other moment it allocates resources is at socket connexion, which
+ * The other moment it allocates resources is at socket connection, which
* is also protected by the mutex.
*/
static
ust_lock();
if (lttng_ust_comm_should_quit) {
- ust_unlock();
goto quit;
}
if (sock_info->socket != -1) {
- ret = close(sock_info->socket);
+ ret = ustcomm_close_unix_sock(sock_info->socket);
if (ret) {
ERR("Error closing %s apps socket", sock_info->name);
}
/*
* Create only one root handle per listener thread for the whole
- * process lifetime.
+ * process lifetime, so we ensure we get ID which is statically
+ * assigned to the root handle.
*/
if (sock_info->root_handle == -1) {
ret = lttng_abi_create_root_handle();
if (ret < 0) {
ERR("Error creating root handle");
- ust_unlock();
goto quit;
}
sock_info->root_handle = ret;
len = ustcomm_recv_unix_sock(sock, &lum, sizeof(lum));
switch (len) {
case 0: /* orderly shutdown */
- DBG("%s ltt-sessiond has performed an orderly shutdown\n", sock_info->name);
+ DBG("%s lttng-sessiond has performed an orderly shutdown", sock_info->name);
+ ust_lock();
+ if (lttng_ust_comm_should_quit) {
+ goto quit;
+ }
+ /*
+ * Either sessiond has shutdown or refused us by closing the socket.
+ * In either case, we don't want to delay construction execution,
+ * and we need to wait before retry.
+ */
+ prev_connect_failed = 1;
+ /*
+ * If we cannot register to the sessiond daemon, don't
+ * delay constructor execution.
+ */
+ ret = handle_register_done(sock_info);
+ assert(!ret);
+ ust_unlock();
goto end;
case sizeof(lum):
- DBG("message received\n");
+ print_cmd(lum.cmd, lum.handle);
ret = handle_message(sock_info, sock, &lum);
- if (ret < 0) {
+ if (ret) {
ERR("Error handling message for %s socket", sock_info->name);
}
continue;
- case -1:
- if (errno == ECONNRESET) {
- ERR("%s remote end closed connection\n", sock_info->name);
+ default:
+ if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+ } else {
+ DBG("incorrect message size (%s socket): %zd", sock_info->name, len);
+ }
+ if (len == -ECONNRESET) {
+ DBG("%s remote end closed connection", sock_info->name);
goto end;
}
goto end;
- default:
- ERR("incorrect message size (%s socket): %zd\n", sock_info->name, len);
- continue;
}
}
end:
+ ust_lock();
+ if (lttng_ust_comm_should_quit) {
+ goto quit;
+ }
+ /* Cleanup socket handles before trying to reconnect */
+ lttng_ust_objd_table_owner_cleanup(sock_info);
+ ust_unlock();
goto restart; /* try to reconnect */
+
quit:
+ sock_info->thread_active = 0;
+ ust_unlock();
return NULL;
}
* sessiond monitoring thread: monitor presence of global and per-user
* sessiond by polling the application common named pipe.
*/
-/* TODO */
-
void __attribute__((constructor)) lttng_ust_init(void)
{
struct timespec constructor_timeout;
+ sigset_t sig_all_blocked, orig_parent_mask;
+ pthread_attr_t thread_attr;
int timeout_mode;
int ret;
if (uatomic_xchg(&initialized, 1) == 1)
return;
+ /*
+ * Fixup interdependency between TLS fixup mutex (which happens
+ * to be the dynamic linker mutex) and ust_lock, taken within
+ * the ust lock.
+ */
+ lttng_fixup_ringbuffer_tls();
+ lttng_fixup_vtid_tls();
+ lttng_fixup_nest_count_tls();
+ lttng_fixup_procname_tls();
+
/*
* We want precise control over the order in which we construct
* our sub-libraries vs starting to receive commands from
*/
init_usterr();
init_tracepoint();
- ltt_ring_buffer_metadata_client_init();
- ltt_ring_buffer_client_overwrite_init();
- ltt_ring_buffer_client_discard_init();
+ lttng_ring_buffer_metadata_client_init();
+ lttng_ring_buffer_client_overwrite_init();
+ lttng_ring_buffer_client_discard_init();
timeout_mode = get_timeout(&constructor_timeout);
ret = setup_local_apps();
if (ret) {
- ERR("Error setting up to local apps");
+ DBG("local apps setup returned %d", ret);
+ }
+
+ /* A new thread created by pthread_create inherits the signal mask
+ * from the parent. To avoid any signal being received by the
+ * listener thread, we block all signals temporarily in the parent,
+ * while we create the listener thread.
+ */
+ sigfillset(&sig_all_blocked);
+ ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_parent_mask);
+ if (ret) {
+ ERR("pthread_sigmask: %s", strerror(ret));
+ }
+
+ ret = pthread_attr_init(&thread_attr);
+ if (ret) {
+ ERR("pthread_attr_init: %s", strerror(ret));
+ }
+ ret = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+ if (ret) {
+ ERR("pthread_attr_setdetachstate: %s", strerror(ret));
}
- ret = pthread_create(&local_apps.ust_listener, NULL,
- ust_listener_thread, &local_apps);
+
+ ust_lock();
+ ret = pthread_create(&global_apps.ust_listener, &thread_attr,
+ ust_listener_thread, &global_apps);
+ if (ret) {
+ ERR("pthread_create global: %s", strerror(ret));
+ }
+ global_apps.thread_active = 1;
+ ust_unlock();
if (local_apps.allowed) {
- ret = pthread_create(&global_apps.ust_listener, NULL,
- ust_listener_thread, &global_apps);
+ ust_lock();
+ ret = pthread_create(&local_apps.ust_listener, &thread_attr,
+ ust_listener_thread, &local_apps);
+ if (ret) {
+ ERR("pthread_create local: %s", strerror(ret));
+ }
+ local_apps.thread_active = 1;
+ ust_unlock();
} else {
handle_register_done(&local_apps);
}
+ ret = pthread_attr_destroy(&thread_attr);
+ if (ret) {
+ ERR("pthread_attr_destroy: %s", strerror(ret));
+ }
+
+ /* Restore original signal mask in parent */
+ ret = pthread_sigmask(SIG_SETMASK, &orig_parent_mask, NULL);
+ if (ret) {
+ ERR("pthread_sigmask: %s", strerror(ret));
+ }
switch (timeout_mode) {
case 1: /* timeout wait */
&constructor_timeout);
} while (ret < 0 && errno == EINTR);
if (ret < 0 && errno == ETIMEDOUT) {
- ERR("Timed out waiting for ltt-sessiond");
+ ERR("Timed out waiting for lttng-sessiond");
} else {
assert(!ret);
}
static
void lttng_ust_cleanup(int exiting)
{
- cleanup_sock_info(&global_apps);
+ cleanup_sock_info(&global_apps, exiting);
if (local_apps.allowed) {
- cleanup_sock_info(&local_apps);
+ cleanup_sock_info(&local_apps, exiting);
}
+ /*
+ * The teardown in this function all affect data structures
+ * accessed under the UST lock by the listener thread. This
+ * lock, along with the lttng_ust_comm_should_quit flag, ensure
+ * that none of these threads are accessing this data at this
+ * point.
+ */
lttng_ust_abi_exit();
lttng_ust_events_exit();
- ltt_ring_buffer_client_discard_exit();
- ltt_ring_buffer_client_overwrite_exit();
- ltt_ring_buffer_metadata_client_exit();
+ lttng_ring_buffer_client_discard_exit();
+ lttng_ring_buffer_client_overwrite_exit();
+ lttng_ring_buffer_metadata_client_exit();
exit_tracepoint();
if (!exiting) {
/* Reinitialize values for fork */
*/
ust_lock();
lttng_ust_comm_should_quit = 1;
- ust_unlock();
- ret = pthread_cancel(global_apps.ust_listener);
- if (ret) {
- ERR("Error cancelling global ust listener thread");
+ /* cancel threads */
+ if (global_apps.thread_active) {
+ ret = pthread_cancel(global_apps.ust_listener);
+ if (ret) {
+ ERR("Error cancelling global ust listener thread: %s",
+ strerror(ret));
+ } else {
+ global_apps.thread_active = 0;
+ }
}
- if (local_apps.allowed) {
+ if (local_apps.thread_active) {
ret = pthread_cancel(local_apps.ust_listener);
if (ret) {
- ERR("Error cancelling local ust listener thread");
+ ERR("Error cancelling local ust listener thread: %s",
+ strerror(ret));
+ } else {
+ local_apps.thread_active = 0;
}
}
+ ust_unlock();
+
+ /*
+ * Do NOT join threads: use of sys_futex makes it impossible to
+ * join the threads without using async-cancel, but async-cancel
+ * is delivered by a signal, which could hit the target thread
+ * anywhere in its code path, including while the ust_lock() is
+ * held, causing a deadlock for the other thread. Let the OS
+ * cleanup the threads if there are stalled in a syscall.
+ */
lttng_ust_cleanup(1);
}
sigset_t all_sigs;
int ret;
+ if (URCU_TLS(lttng_ust_nest_count))
+ return;
/* Disable signals */
sigfillset(&all_sigs);
ret = sigprocmask(SIG_BLOCK, &all_sigs, save_sigset);
DBG("process %d", getpid());
ust_unlock();
/* Restore signals */
- ret = sigprocmask(SIG_SETMASK, &restore_sigset, NULL);
+ ret = sigprocmask(SIG_SETMASK, restore_sigset, NULL);
if (ret == -1) {
PERROR("sigprocmask");
}
void ust_after_fork_parent(sigset_t *restore_sigset)
{
+ if (URCU_TLS(lttng_ust_nest_count))
+ return;
DBG("process %d", getpid());
rcu_bp_after_fork_parent();
/* Release mutexes and reenable signals */
*/
void ust_after_fork_child(sigset_t *restore_sigset)
{
+ if (URCU_TLS(lttng_ust_nest_count))
+ return;
DBG("process %d", getpid());
/* Release urcu mutexes */
rcu_bp_after_fork_child();