Version 2.6.0
[lttng-ust.git] / liblttng-ust / lttng-ust-comm.c
index 5df33f5f789e529a86249899b0ff4a2655757c7c..378ca21cfc71f354a282fe4a9a521cf77319ef02 100644 (file)
@@ -68,9 +68,14 @@ static int initialized;
  *
  * ust_exit_mutex must never nest in ust_mutex.
  *
+ * ust_fork_mutex must never nest in ust_mutex.
+ *
  * ust_mutex_nest is a per-thread nesting counter, allowing the perf
  * counter lazy initialization called by events within the statedump,
  * which traces while the ust_mutex is held.
+ *
+ * ust_lock nests within the dynamic loader lock (within glibc) because
+ * it is taken within the library constructor.
  */
 static pthread_mutex_t ust_mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -86,6 +91,14 @@ static DEFINE_URCU_TLS(int, ust_mutex_nest);
  */
 static pthread_mutex_t ust_exit_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+/*
+ * ust_fork_mutex protects base address statedump tracing against forks. It
+ * prevents the dynamic loader lock to be taken (by base address statedump
+ * tracing) while a fork is happening, thus preventing deadlock issues with
+ * the dynamic loader lock.
+ */
+static pthread_mutex_t ust_fork_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 /* Should the ust comm thread quit ? */
 static int lttng_ust_comm_should_quit;
 
@@ -322,6 +335,16 @@ void lttng_fixup_ust_mutex_nest_tls(void)
        asm volatile ("" : : "m" (URCU_TLS(ust_mutex_nest)));
 }
 
+/*
+ * Fixup urcu bp TLS.
+ */
+static
+void lttng_fixup_urcu_bp_tls(void)
+{
+       rcu_read_lock();
+       rcu_read_unlock();
+}
+
 int lttng_get_notify_socket(void *owner)
 {
        struct sock_info *info = owner;
@@ -506,7 +529,9 @@ void handle_pending_statedump(struct sock_info *sock_info)
 
        if (ctor_passed && sock_info->statedump_pending) {
                sock_info->statedump_pending = 0;
+               pthread_mutex_lock(&ust_fork_mutex);
                lttng_handle_pending_statedump(sock_info);
+               pthread_mutex_unlock(&ust_fork_mutex);
        }
 }
 
@@ -1404,6 +1429,7 @@ void __attribute__((constructor)) lttng_ust_init(void)
         * to be the dynamic linker mutex) and ust_lock, taken within
         * the ust lock.
         */
+       lttng_fixup_urcu_bp_tls();
        lttng_fixup_ringbuffer_tls();
        lttng_fixup_vtid_tls();
        lttng_fixup_nest_count_tls();
@@ -1627,6 +1653,9 @@ void ust_before_fork(sigset_t *save_sigset)
        if (ret == -1) {
                PERROR("sigprocmask");
        }
+
+       pthread_mutex_lock(&ust_fork_mutex);
+
        ust_lock_nocheck();
        rcu_bp_before_fork();
 }
@@ -1637,6 +1666,9 @@ static void ust_after_fork_common(sigset_t *restore_sigset)
 
        DBG("process %d", getpid());
        ust_unlock();
+
+       pthread_mutex_unlock(&ust_fork_mutex);
+
        /* Restore signals */
        ret = sigprocmask(SIG_SETMASK, restore_sigset, NULL);
        if (ret == -1) {
This page took 0.02413 seconds and 4 git commands to generate.