The support of probe provider dlclose() allows for the following problematic
- Application is not linked against the
- Application dlopen() a probe provider library that is linked against
- Application dlclose() the probe provider

In this scenario, the probe provider has a dependency on, so
when it's loaded by the application, is loaded too. The probe
provider library now has the only reference to the library.
When the application calls dlclose() on it, all its references are dropped,
thus triggering the unloading of both the probe provider library and

This scenario is problematic because lttng ust_listener_threads are in DETACHED
state. We cannot join them and therefore we cannot unload the library
containing the code they run. Only the operating system can free those

The reason why those threads are in DETACHED state is to quickly teardown
applications on process exit.

A possible solution to investigate: if we can determine whether
is being dlopen (directly or undirectly) or it's linked against the
application, we could set the detached state accordingly.

To prevent that unloading, we pin it in memory by grabbing an extra reference
on the library, with a RTLD_NODELETE flag. This will prevent the dynamic loader
from ever removing the library from the process' address space.

Signed-off-by: Francis Deslauriers <>

Rephrase commit message and comment
---                  |  1 +
 liblttng-ust/      |  2 ++
 liblttng-ust/lttng-ust-comm.c | 25 +++++++++++++++++++++++++
 3 files changed, 28 insertions(+)

diff --git a/ b/
index b0b4157..4fc6f9c 100644
--- a/
+++ b/
@@ -25,6 +25,7 @@ m4_define([UST_LIB_V_MINOR], [0])
 m4_define([UST_LIB_V_PATCH], [0])
 # note: remember to update tracepoint.h dlopen() to match this version
 # number. TODO: eventually automate by exporting the major number.
diff --git a/liblttng-ust/ b/liblttng-ust/
index 982be69..a7edfd5 100644
--- a/liblttng-ust/
+++ b/liblttng-ust/
@@ -60,6 +60,8 @@ liblttng_ust_runtime_la_SOURCES = \
        string-utils.c \
+liblttng_ust_runtime_la_CFLAGS = 
 liblttng_ust_runtime_la_SOURCES += \
        lttng-context-perf-counters.c \
diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c
index 511b9cf..57e5ce6 100644
--- a/liblttng-ust/lttng-ust-comm.c
+++ b/liblttng-ust/lttng-ust-comm.c
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <dlfcn.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
@@ -59,6 +60,9 @@
 #include "../libringbuffer/getcpu.h"
 #include "getenv.h"
+/* Concatenate lttng ust shared library name with its major version number. */
+#define LTTNG_UST_LIB_SO_NAME "" 
  * Has lttng ust comm constructor been called ?
@@ -1648,6 +1652,7 @@ void __attribute__((constructor)) lttng_ust_init(void)
        pthread_attr_t thread_attr;
        int timeout_mode;
        int ret;
+       void *handle;
        if (uatomic_xchg(&initialized, 1) == 1)
@@ -1662,6 +1667,26 @@ void __attribute__((constructor)) lttng_ust_init(void)
        lttng_ust_loaded = 1;
+        * We need to ensure that the liblttng-ust library is not unloaded to 
+        * the unloading of code used by the ust_listener_threads as we can not
+        * reliably know when they exited. To do that, manually load
+        * to increment the dynamic loader's internal refcount 
+        * this library so it never becomes zero, thus never gets unloaded from 
+        * address space of the process. Since we are already running in the
+        * constructor of the LTTNG_UST_LIB_SO_NAME library, calling dlopen will
+        * simply increment the refcount and no additionnal work is needed by 
+        * 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 
+        * never happen). Do the return value check but discard the handle at 
+        * end of the function as it's not needed.
+        */
+       handle = dlopen(LTTNG_UST_LIB_SO_NAME, RTLD_LAZY | RTLD_NODELETE);
+       if (!handle) {
+               ERR("dlopen of liblttng-ust shared library (%s).", 
+       }
+       /*
         * We want precise control over the order in which we construct
         * our sub-libraries vs starting to receive commands from
         * sessiond (otherwise leading to errors when trying to create

lttng-dev mailing list

Reply via email to