/*
- * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License, version 2 only, as
- * published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
*
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "bin/lttng-sessiond/event-notifier-error-accounting.h"
#define _LGPL_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <common/common.h>
#include <common/hashtable/utils.h>
#include <lttng/lttng.h>
+#include <lttng/map-key.h>
+#include <lttng/map-key-internal.h>
#include "ust-registry.h"
#include "ust-app.h"
+#include "ust-field-utils.h"
#include "utils.h"
+#include "lttng-sessiond.h"
+#include "notification-thread-commands.h"
+
/*
* Hash table match function for event in the registry.
*/
static int ht_match_event(struct cds_lfht_node *node, const void *_key)
{
- struct ust_registry_event *event;
const struct ust_registry_event *key;
+ struct ust_registry_event *event;
+ int i;
assert(node);
assert(_key);
assert(event);
key = _key;
- /* It has to be a perfect match. */
+ /* It has to be a perfect match. First, compare the event names. */
if (strncmp(event->name, key->name, sizeof(event->name))) {
goto no_match;
}
- /* It has to be a perfect match. */
- if (strncmp(event->signature, key->signature,
- strlen(event->signature))) {
+ /* Compare log levels. */
+ if (event->loglevel_value != key->loglevel_value) {
+ goto no_match;
+ }
+
+ /* Compare the number of fields. */
+ if (event->nr_fields != key->nr_fields) {
+ goto no_match;
+ }
+
+ /* Compare each field individually. */
+ for (i = 0; i < event->nr_fields; i++) {
+ if (!match_ustctl_field(&event->fields[i], &key->fields[i])) {
+ goto no_match;
+ }
+ }
+
+ /* Compare model URI. */
+ if (event->model_emf_uri != NULL && key->model_emf_uri == NULL) {
goto no_match;
+ } else if(event->model_emf_uri == NULL && key->model_emf_uri != NULL) {
+ goto no_match;
+ } else if (event->model_emf_uri != NULL && key->model_emf_uri != NULL) {
+ if (strcmp(event->model_emf_uri, key->model_emf_uri)) {
+ goto no_match;
+ }
}
/* Match */
return 0;
}
-static unsigned long ht_hash_event(void *_key, unsigned long seed)
+static unsigned long ht_hash_event(const void *_key, unsigned long seed)
{
- uint64_t xored_key;
- struct ust_registry_event *key = _key;
+ uint64_t hashed_key;
+ const struct ust_registry_event *key = _key;
assert(key);
- xored_key = (uint64_t) (hash_key_str(key->name, seed) ^
- hash_key_str(key->signature, seed));
+ hashed_key = (uint64_t) hash_key_str(key->name, seed);
- return hash_key_u64(&xored_key, seed);
+ return hash_key_u64(&hashed_key, seed);
}
static int compare_enums(const struct ust_registry_enum *reg_enum_a,
entries_a = ®_enum_a->entries[i];
entries_b = ®_enum_b->entries[i];
- if (entries_a->start != entries_b->start) {
+ if (entries_a->start.value != entries_b->start.value) {
ret = -1;
goto end;
}
- if (entries_a->end != entries_b->end) {
+ if (entries_a->end.value != entries_b->end.value) {
ret = -1;
goto end;
}
+ if (entries_a->start.signedness != entries_b->start.signedness) {
+ ret = -1;
+ goto end;
+ }
+ if (entries_a->end.signedness != entries_b->end.signedness) {
+ ret = -1;
+ goto end;
+ }
+
if (strcmp(entries_a->string, entries_b->string)) {
ret = -1;
goto end;
case ustctl_atype_sequence:
case ustctl_atype_string:
case ustctl_atype_variant:
+ case ustctl_atype_array_nestable:
+ case ustctl_atype_sequence_nestable:
+ case ustctl_atype_enum_nestable:
+ case ustctl_atype_variant_nestable:
break;
case ustctl_atype_struct:
- if (field->type.u._struct.nr_fields != 0) {
+ if (field->type.u.legacy._struct.nr_fields != 0) {
+ WARN("Unsupported non-empty struct field.");
+ ret = -EINVAL;
+ goto end;
+ }
+ break;
+ case ustctl_atype_struct_nestable:
+ if (field->type.u.struct_nestable.nr_fields != 0) {
WARN("Unsupported non-empty struct field.");
ret = -EINVAL;
goto end;
break;
case ustctl_atype_float:
- switch (field->type.u.basic._float.mant_dig) {
+ switch (field->type.u._float.mant_dig) {
case 0:
WARN("UST application '%s' (pid: %d) has unknown float mantissa '%u' "
"in field '%s', rejecting event '%s'",
app->name, app->pid,
- field->type.u.basic._float.mant_dig,
+ field->type.u._float.mant_dig,
field->name,
event_name);
ret = -EINVAL;
* registry.
*/
static struct ust_registry_event *alloc_event(int session_objd,
- int channel_objd, char *name, char *sig, size_t nr_fields,
+ int container_objd, char *name, char *sig, size_t nr_fields,
struct ustctl_field *fields, int loglevel_value,
char *model_emf_uri, struct ust_app *app)
{
}
event->session_objd = session_objd;
- event->channel_objd = channel_objd;
+ event->container_objd = container_objd;
/* Allocated by ustctl. */
event->signature = sig;
event->nr_fields = nr_fields;
destroy_event(event);
}
+/*
+ * Destroy ust_registry_map_key_ht_entry function call of the call RCU.
+ */
+static void destroy_ust_registry_map_key_ht_entry(struct rcu_head *head)
+{
+ struct lttng_ht_node_u64 *node =
+ caa_container_of(head, struct lttng_ht_node_u64, head);
+ struct ust_registry_map_key_ht_entry *entry =
+ caa_container_of(node, struct ust_registry_map_key_ht_entry, node);
+
+ lttng_map_key_put(entry->key);
+ free(entry);
+}
+
+/*
+ * Destroy ust_registry_map_index_ht_entry function call of the call RCU.
+ */
+static void destroy_ust_registry_map_index_ht_entry(struct rcu_head *head)
+{
+ struct lttng_ht_node_str *node =
+ caa_container_of(head, struct lttng_ht_node_str, head);
+ struct ust_registry_map_index_ht_entry *entry =
+ caa_container_of(node, struct ust_registry_map_index_ht_entry, node);
+
+ free(entry);
+}
+
/*
* Find an event using the name and signature in the given registry. RCU read
* side lock MUST be acquired before calling this function and as long as the
*
* On success, the event pointer is returned else NULL.
*/
-struct ust_registry_event *ust_registry_find_event(
+struct ust_registry_event *ust_registry_chan_find_event(
struct ust_registry_channel *chan, char *name, char *sig)
{
struct lttng_ht_node_u64 *node;
*
* Should be called with session registry mutex held.
*/
-int ust_registry_create_event(struct ust_registry_session *session,
+int ust_registry_chan_create_event(struct ust_registry_session *session,
uint64_t chan_key, int session_objd, int channel_objd, char *name,
char *sig, size_t nr_fields, struct ustctl_field *fields,
int loglevel_value, char *model_emf_uri, int buffer_type,
DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
"chan_objd: %u, sess_objd: %u, chan_id: %u", event->name,
- event->signature, event->id, event->channel_objd,
+ event->signature, event->id, event->container_objd,
event->session_objd, chan->chan_id);
/*
ERR("UST registry create event add unique failed for event: %s, "
"sig: %s, id: %u, chan_objd: %u, sess_objd: %u",
event->name, event->signature, event->id,
- event->channel_objd, event->session_objd);
+ event->container_objd, event->session_objd);
ret = -EINVAL;
goto error_unlock;
}
} else {
/* Request next event id if the node was successfully added. */
- event_id = event->id = ust_registry_get_next_event_id(chan);
+ event_id = event->id = ust_registry_channel_get_next_event_id(chan);
}
*event_id_p = event_id;
return ret;
}
+static
+int format_event_key(const struct lttng_map_key *key,
+ const char *full_event_name, char **formated_key)
+{
+ int ret;
+ char _key[LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX] = {0};
+ enum lttng_map_key_status key_status;
+ unsigned int i, token_count;
+ char *cloned_full_event_name;
+ const char *provider_name, *event_name;
+
+ assert(key);
+ assert(full_event_name);
+
+ cloned_full_event_name = strdup(full_event_name);
+
+ provider_name = strtok(cloned_full_event_name, ":");
+ event_name = strtok(NULL, ":");
+
+ key_status = lttng_map_key_get_token_count(key, &token_count);
+ if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+ ERR("Error getting map key token count");
+ ret = -1;
+ goto end;
+ }
+
+ if (token_count == 0) {
+ ERR("Map key token number is zero");
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; i < token_count; i++) {
+ const struct lttng_map_key_token *token =
+ lttng_map_key_get_token_at_index(key, i);
+ switch (token->type) {
+ case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+ {
+ struct lttng_map_key_token_string *str_token =
+ (struct lttng_map_key_token_string *) token;
+ DBG("Appending a string type key token: str = '%s'", str_token->string);
+
+ strcat(_key, lttng_map_key_token_string_get_string(str_token));
+
+ break;
+ }
+ case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+ {
+ struct lttng_map_key_token_variable *var_token =
+ (struct lttng_map_key_token_variable *) token;
+
+ switch (var_token->type) {
+ case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
+ DBG("Serializing a event name variable type key token: event_name = '%s'",
+ event_name);
+ strcat(_key, event_name);
+ break;
+ case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
+ DBG("Serializing a provider name variable type key token: provider_name = '%s'",
+ provider_name);
+ strcat(_key, provider_name);
+ break;
+ default:
+ abort();
+ }
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+
+ *formated_key = strdup(_key);
+
+ ret = 0;
+end:
+ free(cloned_full_event_name);
+ return ret;
+}
+
+static
+const struct lttng_map_key *ust_registry_map_find_key_for_token(
+ struct ust_registry_map *map,
+ uint64_t tracer_token)
+{
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_u64 *key_node;
+ struct ust_registry_map_key_ht_entry *key_entry;
+ const struct lttng_map_key *key = NULL;;
+
+ assert(map);
+ lttng_ht_lookup(map->tracer_token_to_map_key_ht,
+ (void *) &tracer_token, &iter);
+
+ key_node = lttng_ht_iter_get_node_u64(&iter);
+ if (!key_node) {
+ goto end;
+ }
+
+ /*
+ * It's already mapped. Return the key we allocated already.
+ */
+ key_entry = caa_container_of(key_node,
+ struct ust_registry_map_key_ht_entry, node);
+ assert(key_entry);
+
+ key = key_entry->key;
+
+ DBG("Returning map key object associated to the tracer token: key = %p, tracer_token = %"PRIu64,
+ key_entry->key, tracer_token);
+
+end:
+ return key;
+}
+
+int ust_registry_map_add_token_key_mapping(struct ust_registry_session *session,
+ uint64_t map_key, uint64_t tracer_token,
+ struct lttng_map_key *key)
+{
+ int ret;
+ struct ust_registry_map_key_ht_entry *key_entry;
+ struct ust_registry_map *map;
+ const struct lttng_map_key *existing_mapping = NULL;
+
+ rcu_read_lock();
+ map = ust_registry_map_find(session, map_key);
+ if (!map) {
+ ret = -EINVAL;
+ goto end;
+ }
+ rcu_read_unlock();
+
+ /* JORAJ check if the mapping already exist, we might want to *move this
+ * to the caller or at least provide more check if for some scenario
+ * (PID) this should never happen
+ */
+ existing_mapping = ust_registry_map_find_key_for_token(map, tracer_token);
+ if (existing_mapping != NULL) {
+ assert(existing_mapping == key);
+ ret = 0;
+ goto end;
+ }
+
+ key_entry = zmalloc(sizeof(struct ust_registry_map_key_ht_entry));
+ if (!key_entry) {
+ ret = -ENOMEM;
+ goto end;
+ }
+ key_entry->key = key;
+
+ /* Ensure the lifetime of the lttng_map_key object. */
+ lttng_map_key_get(key);
+
+ rcu_read_lock();
+
+ lttng_ht_node_init_u64(&key_entry->node, tracer_token);
+ lttng_ht_add_unique_u64(map->tracer_token_to_map_key_ht,
+ &key_entry->node);
+
+ rcu_read_unlock();
+
+
+ ret = 0;
+end:
+ return ret;
+
+}
+
+static
+int ust_registry_map_find_or_create_index_for_key(struct ust_registry_map *map,
+ const char *formated_key, uint64_t *index)
+{
+ int ret;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_str *index_node;
+ struct ust_registry_map_index_ht_entry *index_entry;
+
+ assert(map);
+ assert(formated_key);
+
+ /*
+ * First try to check if we already mapped this formated key to an
+ * index.
+ */
+ lttng_ht_lookup(map->key_string_to_bucket_index_ht,
+ (void *) formated_key, &iter);
+
+ index_node = lttng_ht_iter_get_node_str(&iter);
+ if (index_node) {
+ /*
+ * It's already mapped. Return the index we allocated already.
+ */
+ index_entry = caa_container_of(index_node,
+ struct ust_registry_map_index_ht_entry, node);
+ assert(index_entry);
+
+ *index = index_entry->index;
+
+ DBG("Returning an already allocated index for formated key: key = '%s', index = %"PRIu64,
+ formated_key, *index);
+ } else {
+ /*
+ * It's not mapped. Create a new mapping, add it to the
+ * hashtable and return it.
+ */
+ index_entry = zmalloc(sizeof(struct ust_registry_map_index_ht_entry));
+ if (!index_entry) {
+ ret = -1;
+ goto end;
+ }
+
+ index_entry->index = ust_registry_map_get_next_event_id(map);
+ index_entry->formated_key = strdup(formated_key);
+ lttng_ht_node_init_str(&index_entry->node, index_entry->formated_key);
+
+ lttng_ht_add_unique_str(map->key_string_to_bucket_index_ht,
+ &index_entry->node);
+
+ *index = index_entry->index;
+ DBG("Allocated counter index for new formated_key: key = '%s', index = %"PRIu64,
+ formated_key, *index);
+ }
+
+ ret = 0;
+end:
+ return ret;
+}
+
+/*
+ * Create a ust_registry_event from the given parameters and add it to the
+ * registry hash table. If event_id is valid, it is set with the newly created
+ * event id.
+ *
+ * On success, return 0 else a negative value. The created event MUST be unique
+ * so on duplicate entry -EINVAL is returned. On error, event_id is untouched.
+ *
+ * Should be called with session registry mutex held.
+ */
+int ust_registry_map_create_event(struct ust_registry_session *session,
+ uint64_t map_key, int session_objd, int map_objd, char *name,
+ char *sig, size_t nr_fields, struct ustctl_field *fields,
+ int loglevel_value, char *model_emf_uri, int buffer_type,
+ uint64_t tracer_token, uint64_t *counter_index_p,
+ struct ust_app *app)
+{
+ int ret;
+ uint64_t counter_index;
+ struct ust_registry_map *map;
+ char *formated_key;
+ const struct lttng_map_key *key;
+
+ assert(session);
+ assert(name);
+ assert(sig);
+ assert(counter_index_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 || map_objd < 0) {
+ ret = -EINVAL;
+ goto error_free;
+ }
+
+ map = ust_registry_map_find(session, map_key);
+ if (!map) {
+ ret = -EINVAL;
+ goto error_free;
+ }
+
+ /* Check if we've reached the maximum possible id. */
+ if (ust_registry_is_max_id(map->used_event_id)) {
+ ret = -ENOENT;
+ goto error_free;
+ }
+
+ key = ust_registry_map_find_key_for_token(map, tracer_token);
+ if (!key) {
+ ERR("Tracer token %"PRIu64" not found for map id = %"PRIu32,
+ tracer_token, map->map_id);
+ ret = -EINVAL;
+ goto error_unlock;
+ }
+
+ ret = format_event_key(key, name, &formated_key);
+ if (ret) {
+ ERR("Error formating key");
+ ret = -EINVAL;
+ goto error_unlock;
+ }
+
+ ret = ust_registry_map_find_or_create_index_for_key(map, formated_key,
+ &counter_index);
+ if (ret) {
+ ERR("Error finding or creating index for formated_key = '%s'",
+ formated_key);
+ free(formated_key);
+ ret = -EINVAL;
+ goto error_unlock;
+ }
+
+ DBG3("UST registry allocating counter index %"PRIu64 " to event: %s, "
+ "signature: %s, sess_objd: %u, map_objd: %u, map_id: %u",
+ counter_index, name, sig, session_objd, map_objd, map->map_id);
+
+ *counter_index_p = counter_index;
+
+ rcu_read_unlock();
+ return 0;
+
+error_free:
+ free(sig);
+ free(fields);
+ free(model_emf_uri);
+error_unlock:
+ rcu_read_unlock();
+ return ret;
+}
+
+
/*
* For a given event in a registry, delete the entry and destroy the event.
* This MUST be called within a RCU read side lock section.
*/
-void ust_registry_destroy_event(struct ust_registry_channel *chan,
+void ust_registry_chan_destroy_event(struct ust_registry_channel *chan,
struct ust_registry_event *event)
{
int ret;
return;
}
+/*
+ * This MUST be called within a RCU read side lock section.
+ */
+static void ust_registry_map_key_entry_destroy(struct lttng_ht *ht,
+ struct ust_registry_map_key_ht_entry *entry)
+{
+ int ret;
+ struct lttng_ht_iter iter;
+
+ assert(ht);
+ assert(entry);
+
+ /* Delete the node first. */
+ iter.iter.node = &entry->node.node;
+ ret = lttng_ht_del(ht, &iter);
+ assert(!ret);
+
+ call_rcu(&entry->node.head, destroy_ust_registry_map_key_ht_entry);
+
+ return;
+}
+
+/*
+ * This MUST be called within a RCU read side lock section.
+ */
+static void ust_registry_map_index_ht_entry_destroy(struct lttng_ht *ht,
+ struct ust_registry_map_index_ht_entry *entry)
+{
+ int ret;
+ struct lttng_ht_iter iter;
+
+ assert(ht);
+ assert(entry);
+
+ /* Delete the node first. */
+ iter.iter.node = &entry->node.node;
+ ret = lttng_ht_del(ht, &iter);
+ assert(!ret);
+
+ call_rcu(&entry->node.head, destroy_ust_registry_map_index_ht_entry);
+
+ return;
+}
+
+/*
+ * For a given event in a registry, delete the entry and destroy the event.
+ * This MUST be called within a RCU read side lock section.
+ */
+void ust_registry_map_destroy_event(struct ust_registry_map *map,
+ struct ust_registry_event *event)
+{
+ int ret;
+ struct lttng_ht_iter iter;
+
+ assert(map);
+ assert(event);
+
+ /* Delete the node first. */
+ iter.iter.node = &event->node.node;
+ ret = lttng_ht_del(map->events_ht, &iter);
+ assert(!ret);
+
+ call_rcu(&event->node.head, destroy_event_rcu);
+
+ return;
+}
+
static void destroy_enum(struct ust_registry_enum *reg_enum)
{
if (!reg_enum) {
* Lookup enumeration by name and comparing enumeration entries.
* Needs to be called from RCU read-side critical section.
*/
-struct ust_registry_enum *
- ust_registry_lookup_enum(struct ust_registry_session *session,
+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_iter iter;
cds_lfht_lookup(session->enums->ht,
- ht_hash_enum((void *) ®_enum_lookup, lttng_ht_seed),
- ht_match_enum, ®_enum_lookup, &iter.iter);
+ 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;
* the enumeration.
* This MUST be called within a RCU read side lock section.
*/
-void ust_registry_destroy_enum(struct ust_registry_session *reg_session,
+static void ust_registry_destroy_enum(struct ust_registry_session *reg_session,
struct ust_registry_enum *reg_enum)
{
int ret;
free(chan);
}
+/*
+ * 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 mapge the semantic of
+ * the many callers of delete_ust_app_session().
+ */
+static
+void destroy_map_rcu(struct rcu_head *head)
+{
+ struct ust_registry_map *map =
+ caa_container_of(head, struct ust_registry_map, rcu_head);
+
+ if (map->events_ht) {
+ ht_cleanup_push(map->events_ht);
+ }
+
+ if (map->tracer_token_to_map_key_ht) {
+ ht_cleanup_push(map->tracer_token_to_map_key_ht);
+ }
+
+ if (map->key_string_to_bucket_index_ht) {
+ ht_cleanup_push(map->key_string_to_bucket_index_ht);
+ }
+
+ free(map);
+}
+
/*
* 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)
+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;
assert(chan);
+ if (notif) {
+ cmd_ret = notification_thread_command_remove_channel(
+ 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_chan_destroy_event(chan, event);
+ }
+ rcu_read_unlock();
+ }
+ call_rcu(&chan->rcu_head, destroy_channel_rcu);
+}
+
+/*
+ * 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_map(struct ust_registry_map *map)
+{
+ struct lttng_ht_iter iter;
+ struct ust_registry_event *event;
+ struct ust_registry_map_key_ht_entry *key_entry;
+ struct ust_registry_map_index_ht_entry *index_entry;
+
+ assert(map);
+
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);
+ if (map->events_ht) {
+ /* Destroy all event associated with this registry. */
+ cds_lfht_for_each_entry(map->events_ht->ht, &iter.iter, event, node.node) {
+ /* Delete the node from the ht and free it. */
+ ust_registry_map_destroy_event(map, event);
+ }
+ }
+
+ /* Destroy all map_key entries associated with this registry. */
+ cds_lfht_for_each_entry (map->tracer_token_to_map_key_ht->ht,
+ &iter.iter, key_entry, node.node) {
+ ust_registry_map_key_entry_destroy(
+ map->tracer_token_to_map_key_ht,
+ key_entry);
+ }
+
+ /* Destroy all index entry associated with this registry. */
+ cds_lfht_for_each_entry(map->key_string_to_bucket_index_ht->ht,
+ &iter.iter, index_entry, node.node) {
+ ust_registry_map_index_ht_entry_destroy(
+ map->key_string_to_bucket_index_ht,
+ index_entry);
}
rcu_read_unlock();
- call_rcu(&chan->rcu_head, destroy_channel_rcu);
+ call_rcu(&map->rcu_head, destroy_map_rcu);
}
/*
return 0;
error:
- destroy_channel(chan);
+ destroy_channel(chan, false);
+error_alloc:
+ return ret;
+}
+
+/*
+ * Initialize registry map entry with default values.
+ */
+int ust_registry_map_add(struct ust_registry_session *session,
+ uint64_t key)
+{
+ int ret = 0;
+ struct ust_registry_map *map;
+
+ assert(session);
+
+ map = zmalloc(sizeof(*map));
+ if (!map) {
+ PERROR("zmalloc ust registry map");
+ ret = -ENOMEM;
+ goto error_alloc;
+ }
+
+ map->events_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+ if (!map->events_ht) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Set custom match function. */
+ map->events_ht->match_fct = ht_match_event;
+ map->events_ht->hash_fct = ht_hash_event;
+
+ map->tracer_token_to_map_key_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+ if (!map->tracer_token_to_map_key_ht) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ map->key_string_to_bucket_index_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+ if (!map->key_string_to_bucket_index_ht) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /*
+ * FIXME frdeso: fix this comment
+ * Assign a map ID right now since the event notification comes
+ * *before* the map 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_map_id)) {
+ ret = -1;
+ goto error;
+ }
+ map->map_id = ust_registry_get_next_map_id(session);
+
+ rcu_read_lock();
+ lttng_ht_node_init_u64(&map->node, key);
+ lttng_ht_add_unique_u64(session->maps, &map->node);
+ rcu_read_unlock();
+
+ return 0;
+
+error:
+ destroy_map(map);
error_alloc:
return ret;
}
return chan;
}
+/*
+ * Find a map 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.
+ */
+struct ust_registry_map *ust_registry_map_find(
+ struct ust_registry_session *session, uint64_t key)
+{
+ struct lttng_ht_node_u64 *node;
+ struct lttng_ht_iter iter;
+ struct ust_registry_map *map = NULL;
+
+ assert(session);
+ assert(session->maps);
+
+ DBG3("UST registry map finding key %" PRIu64, key);
+
+ lttng_ht_lookup(session->maps, &key, &iter);
+ node = lttng_ht_iter_get_node_u64(&iter);
+ if (!node) {
+ goto end;
+ }
+ map = caa_container_of(node, struct ust_registry_map, node);
+
+end:
+ return map;
+}
+
/*
* Remove channel using key from registry and free memory.
*/
void ust_registry_channel_del_free(struct ust_registry_session *session,
- uint64_t key)
+ uint64_t key, bool notif)
{
struct lttng_ht_iter iter;
struct ust_registry_channel *chan;
ret = lttng_ht_del(session->channels, &iter);
assert(!ret);
rcu_read_unlock();
- destroy_channel(chan);
+ destroy_channel(chan, notif);
+
+end:
+ return;
+}
+
+/*
+ * Remove map using key from registry and free memory.
+ */
+void ust_registry_map_del_free(struct ust_registry_session *session,
+ uint64_t key)
+{
+ struct lttng_ht_iter iter;
+ struct ust_registry_map *map;
+ int ret;
+
+ assert(session);
+
+ rcu_read_lock();
+ map = ust_registry_map_find(session, key);
+ if (!map) {
+ rcu_read_unlock();
+ goto end;
+ }
+
+ iter.iter.node = &map->node.node;
+ ret = lttng_ht_del(session->maps, &iter);
+ assert(!ret);
+ rcu_read_unlock();
+ destroy_map(map);
end:
return;
const char *root_shm_path,
const char *shm_path,
uid_t euid,
- gid_t egid)
+ gid_t egid,
+ uint64_t tracing_id,
+ uid_t tracing_uid)
{
int ret;
struct ust_registry_session *session;
session->uid = euid;
session->gid = egid;
session->next_enum_id = 0;
+ session->major = major;
+ session->minor = minor;
strncpy(session->root_shm_path, root_shm_path,
sizeof(session->root_shm_path));
session->root_shm_path[sizeof(session->root_shm_path) - 1] = '\0';
session->enums = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
if (!session->enums) {
- ret = -ENOMEM;
+ ERR("Failed to create enums hash table");
goto error;
}
/* hash/match functions are specified at call site. */
goto error;
}
+ session->maps = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+ if (!session->maps) {
+ lttng_ht_destroy(session->channels);
+ goto error;
+ }
+
ret = lttng_uuid_generate(session->uuid);
if (ret) {
ERR("Failed to generate UST uuid (errno = %d)", ret);
goto error;
}
+ session->tracing_id = tracing_id;
+ session->tracing_uid = tracing_uid;
+
pthread_mutex_lock(&session->lock);
ret = ust_metadata_session_statedump(session, app, major, minor);
pthread_mutex_unlock(&session->lock);
/* Delete the node from the ht and free it. */
ret = lttng_ht_del(reg->channels, &iter);
assert(!ret);
- destroy_channel(chan);
+ destroy_channel(chan, true);
}
rcu_read_unlock();
ht_cleanup_push(reg->channels);
/*
* Try deleting the directory hierarchy.
*/
- (void) run_as_recursive_rmdir(reg->root_shm_path,
- reg->uid, reg->gid);
+ (void) run_as_rmdir_recursive(reg->root_shm_path,
+ reg->uid, reg->gid,
+ LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG);
}
/* Destroy the enum hash table */
if (reg->enums) {