- * Lookup enumeration by name and comparing enumeration entries.
- * Needs to be called from RCU read-side critical section.
- */
-static struct ust_registry_enum *ust_registry_lookup_enum(
- struct ust_registry_session *session,
- const struct ust_registry_enum *reg_enum_lookup)
-{
- struct ust_registry_enum *reg_enum = NULL;
- struct lttng_ht_node_str *node;
- struct lttng_ht_iter iter;
-
- cds_lfht_lookup(session->enums->ht,
- ht_hash_enum((void *) reg_enum_lookup, lttng_ht_seed),
- ht_match_enum, reg_enum_lookup, &iter.iter);
- node = lttng_ht_iter_get_node_str(&iter);
- if (!node) {
- goto end;
- }
- reg_enum = caa_container_of(node, struct ust_registry_enum, node);
-end:
- return reg_enum;
-}
-
-/*
- * Lookup enumeration by enum ID.
- * Needs to be called from RCU read-side critical section.
- */
-struct ust_registry_enum *
- ust_registry_lookup_enum_by_id(struct ust_registry_session *session,
- const char *enum_name, uint64_t enum_id)
-{
- struct ust_registry_enum *reg_enum = NULL;
- struct lttng_ht_node_str *node;
- struct lttng_ht_iter iter;
- struct ust_registry_enum reg_enum_lookup;
-
- memset(®_enum_lookup, 0, sizeof(reg_enum_lookup));
- strncpy(reg_enum_lookup.name, enum_name, LTTNG_UST_ABI_SYM_NAME_LEN);
- reg_enum_lookup.name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0';
- reg_enum_lookup.id = enum_id;
- cds_lfht_lookup(session->enums->ht,
- ht_hash_enum((void *) ®_enum_lookup, lttng_ht_seed),
- ht_match_enum_id, ®_enum_lookup, &iter.iter);
- node = lttng_ht_iter_get_node_str(&iter);
- if (!node) {
- goto end;
- }
- reg_enum = caa_container_of(node, struct ust_registry_enum, node);
-end:
- return reg_enum;
-}
-
-/*
- * Create a ust_registry_enum from the given parameters and add it to the
- * registry hash table, or find it if already there.
- *
- * On success, return 0 else a negative value.
- *
- * Should be called with session registry mutex held.
- *
- * We receive ownership of entries.
- */
-int ust_registry_create_or_find_enum(struct ust_registry_session *session,
- int session_objd, char *enum_name,
- struct lttng_ust_ctl_enum_entry *entries, size_t nr_entries,
- uint64_t *enum_id)
-{
- int ret = 0;
- struct cds_lfht_node *nodep;
- struct ust_registry_enum *reg_enum = NULL, *old_reg_enum;
-
- LTTNG_ASSERT(session);
- LTTNG_ASSERT(enum_name);
-
- 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) {
- ret = -EINVAL;
- goto end;
- }
-
- /* Check if the enumeration was already dumped */
- reg_enum = (ust_registry_enum *) zmalloc(sizeof(*reg_enum));
- if (!reg_enum) {
- PERROR("zmalloc ust registry enumeration");
- ret = -ENOMEM;
- goto end;
- }
- strncpy(reg_enum->name, enum_name, LTTNG_UST_ABI_SYM_NAME_LEN);
- reg_enum->name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0';
- /* entries will be owned by reg_enum. */
- reg_enum->entries = entries;
- reg_enum->nr_entries = nr_entries;
- entries = NULL;
-
- old_reg_enum = ust_registry_lookup_enum(session, reg_enum);
- if (old_reg_enum) {
- DBG("enum %s already in sess_objd: %u", enum_name, session_objd);
- /* Fall through. Use prior enum. */
- destroy_enum(reg_enum);
- reg_enum = old_reg_enum;
- } else {
- DBG("UST registry creating enum: %s, sess_objd: %u",
- enum_name, session_objd);
- if (session->next_enum_id == -1ULL) {
- ret = -EOVERFLOW;
- destroy_enum(reg_enum);
- goto end;
- }
- reg_enum->id = session->next_enum_id++;
- cds_lfht_node_init(®_enum->node.node);
- nodep = cds_lfht_add_unique(session->enums->ht,
- ht_hash_enum(reg_enum, lttng_ht_seed),
- ht_match_enum_id, reg_enum,
- ®_enum->node.node);
- LTTNG_ASSERT(nodep == ®_enum->node.node);
- }
- DBG("UST registry reply with enum %s with id %" PRIu64 " in sess_objd: %u",
- enum_name, reg_enum->id, session_objd);
- *enum_id = reg_enum->id;
-end:
- free(entries);
- rcu_read_unlock();
- return ret;
-}
-
-/*
- * For a given enumeration in a registry, delete the entry and destroy
- * the enumeration.
- * This MUST be called within a RCU read side lock section.
- */
-static void ust_registry_destroy_enum(struct ust_registry_session *reg_session,
- struct ust_registry_enum *reg_enum)
-{
- int ret;
- struct lttng_ht_iter iter;
-
- LTTNG_ASSERT(reg_session);
- LTTNG_ASSERT(reg_enum);
-
- /* Delete the node first. */
- iter.iter.node = ®_enum->node.node;
- ret = lttng_ht_del(reg_session->enums, &iter);
- LTTNG_ASSERT(!ret);
- call_rcu(®_enum->rcu_head, destroy_enum_rcu);
-}
-
-/*
- * 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.
- */
-static void destroy_channel(struct ust_registry_channel *chan, bool notif)
-{
- struct lttng_ht_iter iter;
- struct ust_registry_event *event;
- enum lttng_error_code cmd_ret;
-
- LTTNG_ASSERT(chan);
-
- if (notif) {
- cmd_ret = notification_thread_command_remove_channel(
- the_notification_thread_handle,
- chan->consumer_key, LTTNG_DOMAIN_UST);
- if (cmd_ret != LTTNG_OK) {
- ERR("Failed to remove channel from notification thread");
- }
- }
-
- if (chan->ht) {
- 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);
- }
- rcu_read_unlock();
- }
- call_rcu(&chan->rcu_head, destroy_channel_rcu);
-}
-
-/*
- * Initialize registry with default values.
- */
-int ust_registry_channel_add(struct ust_registry_session *session,
- uint64_t key)
-{
- int ret = 0;
- struct ust_registry_channel *chan;
-
- LTTNG_ASSERT(session);
-
- chan = (ust_registry_channel *) zmalloc(sizeof(*chan));
- if (!chan) {
- PERROR("zmalloc ust registry channel");
- ret = -ENOMEM;
- goto error_alloc;
- }
-
- chan->ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
- if (!chan->ht) {
- ret = -ENOMEM;
- goto error;
- }
-
- /* Set custom match function. */
- chan->ht->match_fct = ht_match_event;
- chan->ht->hash_fct = ht_hash_event;
-
- /*
- * Assign a channel ID right now since the event notification comes
- * *before* the channel notify so the ID needs to be set at this point so
- * the metadata can be dumped for that event.
- */
- if (ust_registry_is_max_id(session->used_channel_id)) {
- ret = -1;
- goto error;
- }
- chan->chan_id = ust_registry_get_next_chan_id(session);
-
- rcu_read_lock();
- lttng_ht_node_init_u64(&chan->node, key);
- lttng_ht_add_unique_u64(session->channels, &chan->node);
- rcu_read_unlock();
-
- return 0;
-
-error:
- destroy_channel(chan, false);
-error_alloc:
- return ret;
-}
-
-/*
- * Find a channel in the given registry. RCU read side lock MUST be acquired
- * before calling this function and as long as the event reference is kept by
- * the caller.
- *
- * On success, the pointer is returned else NULL.