Fix deadlock: don't take channel lock in timer
[lttng-tools.git] / src / common / consumer-timer.c
index f9c41c0eb0f8f9f32def26028f743ce7df45d322..37c9861b906a0a81c6b08a302c73e486e6c6d3dd 100644 (file)
@@ -56,6 +56,10 @@ static void setmask(sigset_t *mask)
 
 /*
  * Execute action on a timer switch.
+ *
+ * Beware: metadata_switch_timer() should *never* take a mutex also held
+ * while consumer_timer_switch_stop() is called. It would result in
+ * deadlocks.
  */
 static void metadata_switch_timer(struct lttng_consumer_local_data *ctx,
                int sig, siginfo_t *si, void *uc)
@@ -74,7 +78,21 @@ static void metadata_switch_timer(struct lttng_consumer_local_data *ctx,
        switch (ctx->type) {
        case LTTNG_CONSUMER32_UST:
        case LTTNG_CONSUMER64_UST:
-               ret = lttng_ustconsumer_request_metadata(ctx, channel);
+               /*
+                * Locks taken by lttng_ustconsumer_request_metadata():
+                * - metadata_socket_lock
+                *   - Calling lttng_ustconsumer_recv_metadata():
+                *     - channel->metadata_cache->lock
+                *     - Calling consumer_metadata_cache_flushed():
+                *       - channel->timer_lock
+                *         - channel->metadata_cache->lock
+                *
+                * Ensure that neither consumer_data.lock nor
+                * channel->lock are taken within this function, since
+                * they are held while consumer_timer_switch_stop() is
+                * called.
+                */
+               ret = lttng_ustconsumer_request_metadata(ctx, channel, 1);
                if (ret < 0) {
                        channel->switch_timer_error = 1;
                }
This page took 0.022797 seconds and 4 git commands to generate.