Global type declarations can be used more than once in a single tracepoint, or many tracepoints can use it. It must be statedumped only once in a given session.
Signed-off-by: Geneviève Bastien <[email protected]> --- src/bin/lttng-sessiond/ust-metadata.c | 46 +++++++++++++++++++++++ src/bin/lttng-sessiond/ust-registry.c | 69 +++++++++++++++++++++++++++++++++++ src/bin/lttng-sessiond/ust-registry.h | 15 ++++++++ 3 files changed, 130 insertions(+) diff --git a/src/bin/lttng-sessiond/ust-metadata.c b/src/bin/lttng-sessiond/ust-metadata.c index 743901a..dc144e1 100644 --- a/src/bin/lttng-sessiond/ust-metadata.c +++ b/src/bin/lttng-sessiond/ust-metadata.c @@ -322,6 +322,40 @@ int _lttng_one_global_type_statedump(struct ust_registry_session *session, const struct ustctl_global_type_decl *global_type_decl) { int ret = 0, i; + struct ust_registry_global_type_decl *global_type; + struct cds_lfht_node *nodep; + struct lttng_ht_iter iter; + struct lttng_ht_node_str *node; + + /* Check if the global type was already dumped */ + global_type = zmalloc(sizeof(*global_type)); + if (!global_type) { + PERROR("zmalloc ust registry global type"); + return -ENOMEM; + } + global_type->category = global_type_decl->mtype; + switch (global_type_decl->mtype) { + case ustctl_mtype_enum: + strncpy(global_type->name, global_type_decl->u.ctf_enum.name, LTTNG_UST_SYM_NAME_LEN); + global_type->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + break; + default: + return -EINVAL; + } + + rcu_read_lock(); + cds_lfht_lookup(session->global_types_ht->ht, session->global_types_ht->hash_fct((void *) global_type, lttng_ht_seed), + session->global_types_ht->match_fct, global_type, &iter.iter); + node = lttng_ht_iter_get_node_str(&iter); + if (node != NULL) { + DBG("global type %s already in metadata", global_type->name); + rcu_read_unlock(); + free(global_type); + return ret; + } + cds_lfht_node_init(&global_type->node.node); + rcu_read_unlock(); + switch (global_type_decl->mtype) { case ustctl_mtype_enum: @@ -371,6 +405,17 @@ int _lttng_one_global_type_statedump(struct ust_registry_session *session, return -EINVAL; } + /* Flag this global type as dumped */ + /* + * This is an add unique with a custom match function for global types. + * The node are matched using the category and global type name. + */ + rcu_read_lock(); + nodep = cds_lfht_add_unique(session->global_types_ht->ht, session->global_types_ht->hash_fct(global_type, lttng_ht_seed), + session->global_types_ht->match_fct, global_type, &global_type->node.node); + assert(nodep == &global_type->node.node); + rcu_read_unlock(); + return ret; } @@ -388,6 +433,7 @@ int _lttng_global_type_decl_statedump(struct ust_registry_session *session, const struct ustctl_global_type_decl *global_type_decl = &event->global_type_decl[i]; ret = _lttng_one_global_type_statedump(session, global_type_decl); + DBG("_lttng_global_type_decl_statedump %d", ret); if (ret) return ret; } diff --git a/src/bin/lttng-sessiond/ust-registry.c b/src/bin/lttng-sessiond/ust-registry.c index 281ea7c..80df17a 100644 --- a/src/bin/lttng-sessiond/ust-registry.c +++ b/src/bin/lttng-sessiond/ust-registry.c @@ -73,6 +73,49 @@ static unsigned long ht_hash_event(void *_key, unsigned long seed) } /* + * Hash table match function for global type declarations in the session. + */ +static int ht_match_global_type(struct cds_lfht_node *node, const void *_key) +{ + struct ust_registry_global_type_decl *global_type; + const struct ust_registry_global_type_decl *key; + + assert(node); + assert(_key); + + global_type = caa_container_of(node, struct ust_registry_global_type_decl, node.node); + assert(global_type); + key = _key; + + /* It has to be a perfect match. */ + if (global_type->category != key->category) { + goto no_match; + } + if (strncmp(global_type->name, key->name, strlen(global_type->name) != 0)) { + goto no_match; + } + + /* Match */ + return 1; + +no_match: + return 0; +} + +static unsigned long ht_hash_global_type(void *_key, unsigned long seed) +{ + uint64_t xored_key; + struct ust_registry_global_type_decl *key = _key; + + assert(key); + + xored_key = (uint64_t) (hash_key_ulong((void *)key->category, seed) ^ + hash_key_str(key->name, seed)); + + return hash_key_u64(&xored_key, seed); +} + +/* * Return negative value on error, 0 if OK. * * TODO: we could add stricter verification of more types to catch @@ -570,6 +613,16 @@ int ust_registry_session_init(struct ust_registry_session **sessionp, session->uint64_t_alignment = uint64_t_alignment; session->long_alignment = long_alignment; session->byte_order = byte_order; + session->global_types_ht = 0; + session->global_types_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING); + if (!session->global_types_ht) { + ret = -ENOMEM; + goto error; + } + + /* Set custom match function. */ + session->global_types_ht->match_fct = ht_match_global_type; + session->global_types_ht->hash_fct = ht_hash_global_type; session->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64); if (!session->channels) { @@ -610,6 +663,7 @@ void ust_registry_session_destroy(struct ust_registry_session *reg) int ret; struct lttng_ht_iter iter; struct ust_registry_channel *chan; + struct ust_registry_global_type_decl *global_type; assert(reg); @@ -632,4 +686,19 @@ void ust_registry_session_destroy(struct ust_registry_session *reg) } free(reg->metadata); + + /* Destroy the global type hash table */ + if (reg->global_types_ht) { + rcu_read_lock(); + /* Destroy all global types associated with this registry. */ + cds_lfht_for_each_entry(reg->global_types_ht->ht, &iter.iter, global_type, + node.node) { + /* Delete the node from the ht and free it. */ + ret = lttng_ht_del(reg->global_types_ht, &iter); + assert(!ret); + free(global_type); + } + rcu_read_unlock(); + ht_cleanup_push(reg->global_types_ht); + } } diff --git a/src/bin/lttng-sessiond/ust-registry.h b/src/bin/lttng-sessiond/ust-registry.h index 8b41c2a..29bc120 100644 --- a/src/bin/lttng-sessiond/ust-registry.h +++ b/src/bin/lttng-sessiond/ust-registry.h @@ -31,6 +31,16 @@ struct ust_app; +struct ust_registry_global_type_decl { + uint32_t category; + char name[LTTNG_UST_SYM_NAME_LEN]; + /* + * Node in the ust-session hash table. The global type name and + * category is used to initialize the node and for the match function. + */ + struct lttng_ht_node_u64 node; +}; + struct ust_registry_session { /* * With multiple writers and readers, use this lock to access the registry. @@ -75,6 +85,11 @@ struct ust_registry_session { * deletes its sessions. */ unsigned int metadata_closed; + /* + * Hash table containing global type declarations already dumped into the + * metadata. MUST be accessed with a RCU read side lock acquired. + */ + struct lttng_ht *global_types_ht; }; struct ust_registry_channel { -- 1.8.5.4 _______________________________________________ lttng-dev mailing list [email protected] http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
