Fix: add UST context in the same order the user enabled them
[lttng-tools.git] / src / bin / lttng-sessiond / ust-registry.c
index 6c483e4b71c3107b614cc6201a53719d88307fd9..e22fc6fcfbfc93246172db98e398be6783b99285 100644 (file)
@@ -23,6 +23,7 @@
 #include <lttng/lttng.h>
 
 #include "ust-registry.h"
+#include "utils.h"
 
 /*
  * Hash table match function for event in the registry.
@@ -197,34 +198,34 @@ int ust_registry_create_event(struct ust_registry_session *session,
        assert(sig);
        assert(event_id_p);
 
+       rcu_read_lock();
+
        /*
         * This should not happen but since it comes from the UST tracer, an
         * external party, don't assert and simply validate values.
         */
        if (session_objd < 0 || channel_objd < 0) {
                ret = -EINVAL;
-               goto error;
+               goto error_free;
        }
 
-       rcu_read_lock();
-
        chan = ust_registry_channel_find(session, chan_key);
        if (!chan) {
                ret = -EINVAL;
-               goto error_unlock;
+               goto error_free;
        }
 
        /* Check if we've reached the maximum possible id. */
        if (ust_registry_is_max_id(chan->used_event_id)) {
                ret = -ENOENT;
-               goto error_unlock;
+               goto error_free;
        }
 
        event = alloc_event(session_objd, channel_objd, name, sig, nr_fields,
                        fields, loglevel, model_emf_uri);
        if (!event) {
                ret = -ENOMEM;
-               goto error_unlock;
+               goto error_free;
        }
 
        DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
@@ -278,9 +279,12 @@ int ust_registry_create_event(struct ust_registry_session *session,
        rcu_read_unlock();
        return 0;
 
+error_free:
+       free(sig);
+       free(fields);
+       free(model_emf_uri);
 error_unlock:
        rcu_read_unlock();
-error:
        destroy_event(event);
        return ret;
 }
@@ -308,12 +312,29 @@ void ust_registry_destroy_event(struct ust_registry_channel *chan,
        return;
 }
 
+/*
+ * We need to execute ht_destroy outside of RCU read-side critical
+ * section and outside of call_rcu thread, so we postpone its execution
+ * using ht_cleanup_push. It is simpler than to change the semantic of
+ * the many callers of delete_ust_app_session().
+ */
+static
+void destroy_channel_rcu(struct rcu_head *head)
+{
+       struct ust_registry_channel *chan =
+               caa_container_of(head, struct ust_registry_channel, rcu_head);
+
+       if (chan->ht) {
+               ht_cleanup_push(chan->ht);
+       }
+       free(chan->ctx_fields);
+       free(chan);
+}
+
 /*
  * Destroy every element of the registry and free the memory. This does NOT
  * free the registry pointer since it might not have been allocated before so
  * it's the caller responsability.
- *
- * This MUST be called within a RCU read side lock section.
  */
 static void destroy_channel(struct ust_registry_channel *chan)
 {
@@ -322,14 +343,14 @@ static void destroy_channel(struct ust_registry_channel *chan)
 
        assert(chan);
 
+       rcu_read_lock();
        /* Destroy all event associated with this registry. */
        cds_lfht_for_each_entry(chan->ht->ht, &iter.iter, event, node.node) {
                /* Delete the node from the ht and free it. */
                ust_registry_destroy_event(chan, event);
        }
-       lttng_ht_destroy(chan->ht);
-
-       free(chan);
+       rcu_read_unlock();
+       call_rcu(&chan->rcu_head, destroy_channel_rcu);
 }
 
 /*
@@ -347,7 +368,7 @@ int ust_registry_channel_add(struct ust_registry_session *session,
        if (!chan) {
                PERROR("zmalloc ust registry channel");
                ret = -ENOMEM;
-               goto error;
+               goto error_alloc;
        }
 
        chan->ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
@@ -376,7 +397,11 @@ int ust_registry_channel_add(struct ust_registry_session *session,
        lttng_ht_add_unique_u64(session->channels, &chan->node);
        rcu_read_unlock();
 
+       return 0;
+
 error:
+       destroy_channel(chan);
+error_alloc:
        return ret;
 }
 
@@ -418,22 +443,24 @@ void ust_registry_channel_del_free(struct ust_registry_session *session,
 {
        struct lttng_ht_iter iter;
        struct ust_registry_channel *chan;
+       int ret;
 
        assert(session);
 
        rcu_read_lock();
        chan = ust_registry_channel_find(session, key);
        if (!chan) {
+               rcu_read_unlock();
                goto end;
        }
 
        iter.iter.node = &chan->node.node;
-       lttng_ht_del(session->channels, &iter);
-
+       ret = lttng_ht_del(session->channels, &iter);
+       assert(!ret);
+       rcu_read_unlock();
        destroy_channel(chan);
 
 end:
-       rcu_read_unlock();
        return;
 }
 
@@ -464,7 +491,7 @@ int ust_registry_session_init(struct ust_registry_session **sessionp,
        session = zmalloc(sizeof(*session));
        if (!session) {
                PERROR("zmalloc ust registry session");
-               goto error;
+               goto error_alloc;
        }
 
        pthread_mutex_init(&session->lock, NULL);
@@ -500,6 +527,8 @@ int ust_registry_session_init(struct ust_registry_session **sessionp,
        return 0;
 
 error:
+       ust_registry_session_destroy(session);
+error_alloc:
        return -1;
 }
 
@@ -525,8 +554,8 @@ void ust_registry_session_destroy(struct ust_registry_session *reg)
                assert(!ret);
                destroy_channel(chan);
        }
-       lttng_ht_destroy(reg->channels);
        rcu_read_unlock();
 
+       ht_cleanup_push(reg->channels);
        free(reg->metadata);
 }
This page took 0.025739 seconds and 4 git commands to generate.