Add initial support for the multiple LTTNG_UST_APP_PATHs
[lttng-ust.git] / src / lib / lttng-ust / lttng-ust-comm.c
index f180c3bc8277874ddd673954b1e3bf8467b7e95a..9745c18246690b35e778cb19b5e593452cb5e141 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SPDX-License-Identifier: LGPL-2.1-only
  *
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 EfficiOS Inc.
  * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  */
 
@@ -38,6 +38,7 @@
 #include <lttng/ust-thread.h>
 #include <lttng/ust-tracer.h>
 #include <lttng/ust-common.h>
+#include <lttng/ust-cancelstate.h>
 #include <urcu/tls-compat.h>
 #include "lib/lttng-ust/futex.h"
 #include "common/ustcomm.h"
@@ -117,6 +118,28 @@ static int lttng_ust_comm_should_quit;
  */
 int lttng_ust_loaded __attribute__((weak));
 
+/*
+ * Notes on async-signal-safety of ust lock: a few libc functions are used
+ * which are not strictly async-signal-safe:
+ *
+ * - pthread_setcancelstate
+ * - pthread_mutex_lock
+ * - pthread_mutex_unlock
+ *
+ * As of glibc 2.35, the implementation of pthread_setcancelstate only
+ * touches TLS data, and it appears to be safe to use from signal
+ * handlers. If the libc implementation changes, this will need to be
+ * revisited, and we may ask glibc to provide an async-signal-safe
+ * pthread_setcancelstate.
+ *
+ * As of glibc 2.35, the implementation of pthread_mutex_lock/unlock
+ * for fast mutexes only relies on the pthread_mutex_t structure.
+ * Disabling signals around all uses of this mutex ensures
+ * signal-safety. If the libc implementation changes and eventually uses
+ * other global resources, this will need to be revisited and we may
+ * need to implement our own mutex.
+ */
+
 /*
  * Return 0 on success, -1 if should quit.
  * The lock is taken in both cases.
@@ -125,25 +148,21 @@ int lttng_ust_loaded __attribute__((weak));
 int ust_lock(void)
 {
        sigset_t sig_all_blocked, orig_mask;
-       int ret, oldstate;
+       int ret;
 
-       ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
-       if (ret) {
-               ERR("pthread_setcancelstate: %s", strerror(ret));
-       }
-       if (oldstate != PTHREAD_CANCEL_ENABLE) {
-               ERR("pthread_setcancelstate: unexpected oldstate");
+       if (lttng_ust_cancelstate_disable_push()) {
+               ERR("lttng_ust_cancelstate_disable_push");
        }
        sigfillset(&sig_all_blocked);
        ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
        if (ret) {
-               ERR("pthread_sigmask: %s", strerror(ret));
+               ERR("pthread_sigmask: ret=%d", ret);
        }
        if (!URCU_TLS(ust_mutex_nest)++)
                pthread_mutex_lock(&ust_mutex);
        ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
        if (ret) {
-               ERR("pthread_sigmask: %s", strerror(ret));
+               ERR("pthread_sigmask: ret=%d", ret);
        }
        if (lttng_ust_comm_should_quit) {
                return -1;
@@ -161,25 +180,21 @@ int ust_lock(void)
 void ust_lock_nocheck(void)
 {
        sigset_t sig_all_blocked, orig_mask;
-       int ret, oldstate;
+       int ret;
 
-       ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
-       if (ret) {
-               ERR("pthread_setcancelstate: %s", strerror(ret));
-       }
-       if (oldstate != PTHREAD_CANCEL_ENABLE) {
-               ERR("pthread_setcancelstate: unexpected oldstate");
+       if (lttng_ust_cancelstate_disable_push()) {
+               ERR("lttng_ust_cancelstate_disable_push");
        }
        sigfillset(&sig_all_blocked);
        ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
        if (ret) {
-               ERR("pthread_sigmask: %s", strerror(ret));
+               ERR("pthread_sigmask: ret=%d", ret);
        }
        if (!URCU_TLS(ust_mutex_nest)++)
                pthread_mutex_lock(&ust_mutex);
        ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
        if (ret) {
-               ERR("pthread_sigmask: %s", strerror(ret));
+               ERR("pthread_sigmask: ret=%d", ret);
        }
 }
 
@@ -189,25 +204,21 @@ void ust_lock_nocheck(void)
 void ust_unlock(void)
 {
        sigset_t sig_all_blocked, orig_mask;
-       int ret, oldstate;
+       int ret;
 
        sigfillset(&sig_all_blocked);
        ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask);
        if (ret) {
-               ERR("pthread_sigmask: %s", strerror(ret));
+               ERR("pthread_sigmask: ret=%d", ret);
        }
        if (!--URCU_TLS(ust_mutex_nest))
                pthread_mutex_unlock(&ust_mutex);
        ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
        if (ret) {
-               ERR("pthread_sigmask: %s", strerror(ret));
-       }
-       ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-       if (ret) {
-               ERR("pthread_setcancelstate: %s", strerror(ret));
+               ERR("pthread_sigmask: ret=%d", ret);
        }
-       if (oldstate != PTHREAD_CANCEL_DISABLE) {
-               ERR("pthread_setcancelstate: unexpected oldstate");
+       if (lttng_ust_cancelstate_disable_pop()) {
+               ERR("lttng_ust_cancelstate_disable_pop");
        }
 }
 
@@ -223,10 +234,10 @@ void ust_unlock(void)
  */
 static sem_t constructor_wait;
 /*
- * Doing this for both the global and local sessiond.
+ * Doing this for the ust_app, global and local sessiond.
  */
 enum {
-       sem_count_initial_value = 4,
+       sem_count_initial_value = 6,
 };
 
 static int sem_count = sem_count_initial_value;
@@ -246,26 +257,53 @@ struct sock_info {
        int root_handle;
        int registration_done;
        int allowed;
-       int global;
+       bool multi_user;
        int thread_active;
 
        char sock_path[PATH_MAX];
        int socket;
        int notify_socket;
 
+       /*
+        * If wait_shm_is_file is true, use standard open to open and
+        * create the shared memory used for waiting on session daemon.
+        * Otherwise, use shm_open to create this file.
+        */
+       bool wait_shm_is_file;
        char wait_shm_path[PATH_MAX];
        char *wait_shm_mmap;
+
        /* Keep track of lazy state dump not performed yet. */
        int statedump_pending;
        int initial_statedump_done;
        /* Keep procname for statedump */
-       char procname[LTTNG_UST_ABI_PROCNAME_LEN];
+       char procname[LTTNG_UST_CONTEXT_PROCNAME_LEN];
 };
 
 /* Socket from app (connect) to session daemon (listen) for communication */
+static struct sock_info ust_app = {
+       .name = "ust_app",
+       .multi_user = true,
+
+       .root_handle = -1,
+       .registration_done = 0,
+       .allowed = 0,
+       .thread_active = 0,
+
+       .socket = -1,
+       .notify_socket = -1,
+
+       .wait_shm_is_file = true,
+
+       .statedump_pending = 0,
+       .initial_statedump_done = 0,
+       .procname[0] = '\0'
+};
+
+
 static struct sock_info global_apps = {
        .name = "global",
-       .global = 1,
+       .multi_user = true,
 
        .root_handle = -1,
        .registration_done = 0,
@@ -276,6 +314,7 @@ static struct sock_info global_apps = {
        .socket = -1,
        .notify_socket = -1,
 
+       .wait_shm_is_file = false,
        .wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME,
 
        .statedump_pending = 0,
@@ -283,11 +322,9 @@ static struct sock_info global_apps = {
        .procname[0] = '\0'
 };
 
-/* TODO: allow global_apps_sock_path override */
-
 static struct sock_info local_apps = {
        .name = "local",
-       .global = 0,
+       .multi_user = false,
        .root_handle = -1,
        .registration_done = 0,
        .allowed = 0,   /* Check setuid bit first */
@@ -296,6 +333,8 @@ static struct sock_info local_apps = {
        .socket = -1,
        .notify_socket = -1,
 
+       .wait_shm_is_file = false,
+
        .statedump_pending = 0,
        .initial_statedump_done = 0,
        .procname[0] = '\0'
@@ -372,45 +411,84 @@ const char *get_lttng_home_dir(void)
        return (const char *) lttng_ust_getenv("HOME");
 }
 
+/*
+ * Returns the LTTNG_UST_APP_PATH path. If environment variable exists
+ * and contains a ':', the first path before the ':' separator is returned.
+ * The return value should be freed by the caller if it is not NULL.
+ */
+static
+char *get_lttng_ust_app_path(void)
+{
+       const char *env_val = lttng_ust_getenv("LTTNG_UST_APP_PATH");
+       char *val = NULL;
+       char *sep = NULL;
+       if (env_val == NULL)
+               goto error;
+       sep = strchr((char*)env_val, ':');
+       if (sep) {
+               /*
+                * Split into multiple paths using ':' as a separator.
+                * There is no escaping of the ':' separator.
+                */
+               WARN("':' separator in LTTNG_UST_APP_PATH, only the first path will be used.");
+               val = zmalloc(sep - env_val + 1);
+               if (!val) {
+                       PERROR("zmalloc get_lttng_ust_app_path");
+                       goto error;
+               }
+               memcpy(val, env_val, sep - env_val);
+               val[sep - env_val] = '\0';
+       } else {
+               val = strdup(env_val);
+               if (!val) {
+                       PERROR("strdup");
+                       goto error;
+               }
+       }
+
+error:
+       return val;
+}
+
 /*
  * Force a read (imply TLS allocation for dlopen) of TLS variables.
  */
 static
-void lttng_nest_count_alloc_tls(void)
+void lttng_ust_nest_count_alloc_tls(void)
 {
-       asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count)));
+       __asm__ __volatile__ ("" : : "m" (URCU_TLS(lttng_ust_nest_count)));
 }
 
 static
 void lttng_ust_mutex_nest_alloc_tls(void)
 {
-       asm volatile ("" : : "m" (URCU_TLS(ust_mutex_nest)));
+       __asm__ __volatile__ ("" : : "m" (URCU_TLS(ust_mutex_nest)));
 }
 
 /*
  * Allocate lttng-ust urcu TLS.
  */
 static
-void lttng_lttng_ust_urcu_alloc_tls(void)
+void lttng_ust_urcu_alloc_tls(void)
 {
        (void) lttng_ust_urcu_read_ongoing();
 }
 
-void lttng_ust_alloc_tls(void)
+void lttng_ust_common_init_thread(int flags)
 {
-       lttng_lttng_ust_urcu_alloc_tls();
+       lttng_ust_urcu_alloc_tls();
        lttng_ringbuffer_alloc_tls();
-       lttng_vtid_alloc_tls();
-       lttng_nest_count_alloc_tls();
-       lttng_procname_alloc_tls();
+       lttng_ust_vtid_init_thread(flags);
+       lttng_ust_nest_count_alloc_tls();
+       lttng_ust_procname_init_thread(flags);
        lttng_ust_mutex_nest_alloc_tls();
-       lttng_ust_perf_counter_alloc_tls();
+       lttng_ust_perf_counter_init_thread(flags);
        lttng_ust_common_alloc_tls();
-       lttng_cgroup_ns_alloc_tls();
-       lttng_ipc_ns_alloc_tls();
-       lttng_net_ns_alloc_tls();
-       lttng_time_ns_alloc_tls();
-       lttng_uts_ns_alloc_tls();
+       lttng_ust_cgroup_ns_init_thread(flags);
+       lttng_ust_ipc_ns_init_thread(flags);
+       lttng_ust_net_ns_init_thread(flags);
+       lttng_ust_time_ns_init_thread(flags);
+       lttng_ust_uts_ns_init_thread(flags);
        lttng_ust_ring_buffer_client_discard_alloc_tls();
        lttng_ust_ring_buffer_client_discard_rt_alloc_tls();
        lttng_ust_ring_buffer_client_overwrite_alloc_tls();
@@ -435,7 +513,9 @@ void lttng_ust_init_thread(void)
         * ensure those are initialized before a signal handler nesting over
         * this thread attempts to use them.
         */
-       lttng_ust_alloc_tls();
+       lttng_ust_common_init_thread(LTTNG_UST_INIT_THREAD_MASK);
+
+       lttng_ust_urcu_register_thread();
 }
 
 int lttng_get_notify_socket(void *owner)
@@ -467,12 +547,72 @@ void print_cmd(int cmd, int handle)
                lttng_ust_obj_get_name(handle), handle);
 }
 
+static
+int setup_ust_apps(void)
+{
+       char *ust_app_path = NULL;
+       int ret = 0;
+       uid_t uid;
+
+       assert(!ust_app.wait_shm_mmap);
+
+       uid = getuid();
+       /*
+        * Disallow ust apps tracing for setuid binaries, because we
+        * cannot use the environment variables anyway.
+        */
+       if (uid != geteuid()) {
+               DBG("UST app tracing disabled for setuid binary.");
+               assert(ust_app.allowed == 0);
+               ret = 0;
+               goto end;
+       }
+       ust_app_path = get_lttng_ust_app_path();
+       if (!ust_app_path) {
+               DBG("LTTNG_UST_APP_PATH environment variable not set.");
+               assert(ust_app.allowed == 0);
+               ret = -ENOENT;
+               goto end;
+       }
+       /*
+        * The LTTNG_UST_APP_PATH env. var. disables global and local
+        * sessiond connections.
+        */
+       ust_app.allowed = 1;
+       snprintf(ust_app.sock_path, PATH_MAX, "%s/%s",
+               ust_app_path, LTTNG_UST_SOCK_FILENAME);
+       snprintf(ust_app.wait_shm_path, PATH_MAX, "%s/%s",
+               ust_app_path,
+               LTTNG_UST_WAIT_FILENAME);
+
+       ust_app.wait_shm_mmap = get_map_shm(&ust_app);
+       if (!ust_app.wait_shm_mmap) {
+               WARN("Unable to get map shm for ust_app. Disabling LTTng-UST ust_app tracing.");
+               ust_app.allowed = 0;
+               ret = -EIO;
+               goto end;
+       }
+
+       lttng_pthread_getname_np(ust_app.procname, LTTNG_UST_CONTEXT_PROCNAME_LEN);
+end:
+       if (ust_app_path)
+               free(ust_app_path);
+       return ret;
+}
+
 static
 int setup_global_apps(void)
 {
        int ret = 0;
        assert(!global_apps.wait_shm_mmap);
 
+       /*
+        * The LTTNG_UST_APP_PATH env. var. disables global sessiond
+        * connections.
+        */
+       if (ust_app.allowed)
+               return 0;
+
        global_apps.wait_shm_mmap = get_map_shm(&global_apps);
        if (!global_apps.wait_shm_mmap) {
                WARN("Unable to get map shm for global apps. Disabling LTTng-UST global tracing.");
@@ -482,10 +622,11 @@ int setup_global_apps(void)
        }
 
        global_apps.allowed = 1;
-       lttng_pthread_getname_np(global_apps.procname, LTTNG_UST_ABI_PROCNAME_LEN);
+       lttng_pthread_getname_np(global_apps.procname, LTTNG_UST_CONTEXT_PROCNAME_LEN);
 error:
        return ret;
 }
+
 static
 int setup_local_apps(void)
 {
@@ -495,6 +636,13 @@ int setup_local_apps(void)
 
        assert(!local_apps.wait_shm_mmap);
 
+       /*
+        * The LTTNG_UST_APP_PATH env. var. disables local sessiond
+        * connections.
+        */
+       if (ust_app.allowed)
+               return 0;
+
        uid = getuid();
        /*
         * Disallow per-user tracing for setuid binaries.
@@ -528,7 +676,7 @@ int setup_local_apps(void)
                goto end;
        }
 
-       lttng_pthread_getname_np(local_apps.procname, LTTNG_UST_ABI_PROCNAME_LEN);
+       lttng_pthread_getname_np(local_apps.procname, LTTNG_UST_CONTEXT_PROCNAME_LEN);
 end:
        return ret;
 }
@@ -620,7 +768,8 @@ void get_allow_blocking(void)
 }
 
 static
-int register_to_sessiond(int socket, enum lttng_ust_ctl_socket_type type)
+int register_to_sessiond(int socket, enum lttng_ust_ctl_socket_type type,
+               const char *procname)
 {
        return ustcomm_send_reg_msg(socket,
                type,
@@ -629,7 +778,8 @@ int register_to_sessiond(int socket, enum lttng_ust_ctl_socket_type type)
                lttng_ust_rb_alignof(uint16_t) * CHAR_BIT,
                lttng_ust_rb_alignof(uint32_t) * CHAR_BIT,
                lttng_ust_rb_alignof(uint64_t) * CHAR_BIT,
-               lttng_ust_rb_alignof(unsigned long) * CHAR_BIT);
+               lttng_ust_rb_alignof(unsigned long) * CHAR_BIT,
+               procname);
 }
 
 static
@@ -1457,8 +1607,7 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting)
                }
                sock_info->root_handle = -1;
        }
-       sock_info->registration_done = 0;
-       sock_info->initial_statedump_done = 0;
+
 
        /*
         * wait_shm_mmap, socket and notify socket are used by listener
@@ -1470,6 +1619,9 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting)
        if (exiting)
                return;
 
+       sock_info->registration_done = 0;
+       sock_info->initial_statedump_done = 0;
+
        if (sock_info->socket != -1) {
                ret = ustcomm_close_unix_sock(sock_info->socket);
                if (ret) {
@@ -1503,6 +1655,15 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting)
        }
 }
 
+static
+int wait_shm_open(struct sock_info *sock_info, int flags, mode_t mode)
+{
+       if (sock_info->wait_shm_is_file)
+               return open(sock_info->wait_shm_path, flags, mode);
+       else
+               return shm_open(sock_info->wait_shm_path, flags, mode);
+}
+
 /*
  * Using fork to set umask in the child process (not multi-thread safe).
  * We deal with the shm_open vs ftruncate race (happening when the
@@ -1521,7 +1682,7 @@ int get_wait_shm(struct sock_info *sock_info, size_t mmap_size)
        /*
         * Try to open read-only.
         */
-       wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0);
+       wait_shm_fd = wait_shm_open(sock_info, O_RDONLY, 0);
        if (wait_shm_fd >= 0) {
                int32_t tmp_read;
                ssize_t len;
@@ -1567,21 +1728,21 @@ open_write:
        pid = fork();
        URCU_TLS(lttng_ust_nest_count)--;
        if (pid > 0) {
-               int status;
+               int status, wait_ret;
 
                /*
                 * Parent: wait for child to return, in which case the
                 * shared memory map will have been created.
                 */
-               pid = wait(&status);
-               if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+               wait_ret = waitpid(pid, &status, 0);
+               if (wait_ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
                        wait_shm_fd = -1;
                        goto end;
                }
                /*
                 * Try to open read-only again after creation.
                 */
-               wait_shm_fd = shm_open(sock_info->wait_shm_path, O_RDONLY, 0);
+               wait_shm_fd = wait_shm_open(sock_info, O_RDONLY, 0);
                if (wait_shm_fd < 0) {
                        /*
                         * Real-only open did not work. It's a failure
@@ -1596,7 +1757,7 @@ open_write:
 
                /* Child */
                create_mode = S_IRUSR | S_IWUSR | S_IRGRP;
-               if (sock_info->global)
+               if (sock_info->multi_user)
                        create_mode |= S_IROTH | S_IWGRP | S_IWOTH;
                /*
                 * We're alone in a child process, so we can modify the
@@ -1608,7 +1769,7 @@ open_write:
                 * We don't do an exclusive open, because we allow other
                 * processes to create+ftruncate it concurrently.
                 */
-               wait_shm_fd = shm_open(sock_info->wait_shm_path,
+               wait_shm_fd = wait_shm_open(sock_info,
                                O_RDWR | O_CREAT, create_mode);
                if (wait_shm_fd >= 0) {
                        ret = ftruncate(wait_shm_fd, mmap_size);
@@ -1626,7 +1787,7 @@ open_write:
                 * sessiond will be able to override all rights and wake
                 * us up.
                 */
-               if (!sock_info->global && errno != EACCES) {
+               if (!sock_info->multi_user && errno != EACCES) {
                        ERR("Error opening shm %s", sock_info->wait_shm_path);
                        _exit(EXIT_FAILURE);
                }
@@ -1639,7 +1800,7 @@ open_write:
                return -1;
        }
 end:
-       if (wait_shm_fd >= 0 && !sock_info->global) {
+       if (wait_shm_fd >= 0 && !sock_info->multi_user) {
                struct stat statbuf;
 
                /*
@@ -1742,18 +1903,25 @@ void wait_for_sessiond(struct sock_info *sock_info)
 
        DBG("Waiting for %s apps sessiond", sock_info->name);
        /* Wait for futex wakeup */
-       if (uatomic_read((int32_t *) sock_info->wait_shm_mmap))
-               goto end_wait;
-
-       while (lttng_ust_futex_async((int32_t *) sock_info->wait_shm_mmap,
-                       FUTEX_WAIT, 0, NULL, NULL, 0)) {
+       while (!uatomic_read((int32_t *) sock_info->wait_shm_mmap)) {
+               if (!lttng_ust_futex_async((int32_t *) sock_info->wait_shm_mmap, FUTEX_WAIT, 0, NULL, NULL, 0)) {
+                       /*
+                        * Prior queued wakeups queued by unrelated code
+                        * using the same address can cause futex wait to
+                        * return 0 even through the futex value is still
+                        * 0 (spurious wakeups). Check the value again
+                        * in user-space to validate whether it really
+                        * differs from 0.
+                        */
+                       continue;
+               }
                switch (errno) {
-               case EWOULDBLOCK:
+               case EAGAIN:
                        /* Value already changed. */
                        goto end_wait;
                case EINTR:
                        /* Retry if interrupted by signal. */
-                       break;  /* Get out of switch. */
+                       break;  /* Get out of switch. Check again. */
                case EFAULT:
                        wait_poll_fallback = 1;
                        DBG(
@@ -1793,7 +1961,7 @@ void *ust_listener_thread(void *arg)
        int sock, ret, prev_connect_failed = 0, has_waited = 0, fd;
        long timeout;
 
-       lttng_ust_alloc_tls();
+       lttng_ust_common_init_thread(0);
        /*
         * If available, add '-ust' to the end of this thread's
         * process name
@@ -1911,7 +2079,8 @@ restart:
                sock_info->root_handle = ret;
        }
 
-       ret = register_to_sessiond(sock_info->socket, LTTNG_UST_CTL_SOCKET_CMD);
+       ret = register_to_sessiond(sock_info->socket, LTTNG_UST_CTL_SOCKET_CMD,
+               sock_info->procname);
        if (ret < 0) {
                ERR("Error registering to %s ust cmd socket",
                        sock_info->name);
@@ -2004,7 +2173,7 @@ restart:
        }
 
        ret = register_to_sessiond(sock_info->notify_socket,
-                       LTTNG_UST_CTL_SOCKET_NOTIFY);
+                       LTTNG_UST_CTL_SOCKET_NOTIFY, sock_info->procname);
        if (ret < 0) {
                ERR("Error registering to %s ust notify socket",
                        sock_info->name);
@@ -2122,6 +2291,10 @@ void lttng_ust_check_soname_0(void)
  * Expose a canary symbol of the previous ABI to ensure we catch uses of a
  * liblttng-ust.so.0 dlopen'd after .so.1 has been loaded. Use a different
  * symbol than the detection code to ensure we don't detect ourself.
+ *
+ * This scheme will only work on systems where the global symbol table has
+ * priority when resolving the symbols of a dlopened shared object, which is
+ * the case on Linux but not on FreeBSD.
  */
 void init_usterr(void);
 void init_usterr(void)
@@ -2156,7 +2329,7 @@ void lttng_ust_ctor(void)
         * to be the dynamic linker mutex) and ust_lock, taken within
         * the ust lock.
         */
-       lttng_ust_alloc_tls();
+       lttng_ust_common_init_thread(0);
 
        lttng_ust_loaded = 1;
 
@@ -2176,7 +2349,7 @@ void lttng_ust_ctor(void)
         * this library so it never becomes zero, thus never gets unloaded from the
         * address space of the process. Since we are already running in the
         * constructor of the LTTNG_UST_LIB_SONAME library, calling dlopen will
-        * simply increment the refcount and no additionnal work is needed by the
+        * simply increment the refcount and no additional work is needed by the
         * dynamic loader as the shared library is already loaded in the address
         * space. As a safe guard, we use the RTLD_NODELETE flag to prevent
         * unloading of the UST library if its refcount becomes zero (which should
@@ -2229,6 +2402,11 @@ void lttng_ust_ctor(void)
                PERROR("sem_init");
        }
 
+       ret = setup_ust_apps();
+       if (ret) {
+               assert(ust_app.allowed == 0);
+               DBG("ust_app setup returned %d", ret);
+       }
        ret = setup_global_apps();
        if (ret) {
                assert(global_apps.allowed == 0);
@@ -2261,6 +2439,19 @@ void lttng_ust_ctor(void)
                ERR("pthread_attr_setdetachstate: %s", strerror(ret));
        }
 
+       if (ust_app.allowed) {
+               pthread_mutex_lock(&ust_exit_mutex);
+               ret = pthread_create(&ust_app.ust_listener, &thread_attr,
+                               ust_listener_thread, &ust_app);
+               if (ret) {
+                       ERR("pthread_create ust_app: %s", strerror(ret));
+               }
+               ust_app.thread_active = 1;
+               pthread_mutex_unlock(&ust_exit_mutex);
+       } else {
+               handle_register_done(&ust_app);
+       }
+
        if (global_apps.allowed) {
                pthread_mutex_lock(&ust_exit_mutex);
                ret = pthread_create(&global_apps.ust_listener, &thread_attr,
@@ -2340,8 +2531,10 @@ void lttng_ust_ctor(void)
 static
 void lttng_ust_cleanup(int exiting)
 {
+       cleanup_sock_info(&ust_app, exiting);
        cleanup_sock_info(&global_apps, exiting);
        cleanup_sock_info(&local_apps, exiting);
+       ust_app.allowed = 0;
        local_apps.allowed = 0;
        global_apps.allowed = 0;
        /*
@@ -2391,6 +2584,15 @@ void lttng_ust_exit(void)
 
        pthread_mutex_lock(&ust_exit_mutex);
        /* cancel threads */
+       if (ust_app.thread_active) {
+               ret = pthread_cancel(ust_app.ust_listener);
+               if (ret) {
+                       ERR("Error cancelling ust listener thread: %s",
+                               strerror(ret));
+               } else {
+                       ust_app.thread_active = 0;
+               }
+       }
        if (global_apps.thread_active) {
                ret = pthread_cancel(global_apps.ust_listener);
                if (ret) {
@@ -2470,7 +2672,7 @@ void lttng_ust_before_fork(sigset_t *save_sigset)
        int ret;
 
        /* Allocate lttng-ust TLS. */
-       lttng_ust_alloc_tls();
+       lttng_ust_common_init_thread(0);
 
        if (URCU_TLS(lttng_ust_nest_count))
                return;
@@ -2513,7 +2715,7 @@ void lttng_ust_after_fork_parent(sigset_t *restore_sigset)
                return;
        DBG("process %d", getpid());
        lttng_ust_urcu_after_fork_parent();
-       /* Release mutexes and reenable signals */
+       /* Release mutexes and re-enable signals */
        ust_after_fork_common(restore_sigset);
 }
 
@@ -2540,7 +2742,7 @@ void lttng_ust_after_fork_child(sigset_t *restore_sigset)
        /* Release urcu mutexes */
        lttng_ust_urcu_after_fork_child();
        lttng_ust_cleanup(0);
-       /* Release mutexes and reenable signals */
+       /* Release mutexes and re-enable signals */
        ust_after_fork_common(restore_sigset);
        lttng_ust_ctor();
 }
This page took 0.034117 seconds and 4 git commands to generate.