SoW-2020-0003: Trace Hit Counters
[lttng-tools.git] / src / common / map.c
diff --git a/src/common/map.c b/src/common/map.c
new file mode 100644 (file)
index 0000000..82b7c25
--- /dev/null
@@ -0,0 +1,1235 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/optional.h>
+#include <common/payload.h>
+
+#include <lttng/lttng.h>
+#include <lttng/map/map-internal.h>
+
+enum lttng_map_status lttng_map_set_name(struct lttng_map *map,
+               const char *name)
+{
+       char *name_copy = NULL;
+       enum lttng_map_status status;
+
+       if (!map || !name || strlen(name) == 0) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       name_copy = strdup(name);
+       if (!name_copy) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       free(map->name);
+
+       map->name = name_copy;
+       name_copy = NULL;
+
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_status lttng_map_get_name(const struct lttng_map *map,
+               const char **name)
+{
+       enum lttng_map_status status;
+
+       if (!map || !name) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!map->name) {
+               status = LTTNG_MAP_STATUS_UNSET;
+       }
+
+       *name = map->name;
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_status lttng_map_create(const char *name,
+               unsigned int dimension_count,
+               uint64_t *dimension_sizes,
+               enum lttng_domain_type domain,
+               enum lttng_buffer_type buffer_type,
+               enum lttng_map_bitness bitness,
+               enum lttng_map_boundary_policy boundary_policy,
+               bool coalesce_hits,
+               struct lttng_map **map_out)
+{
+       enum lttng_map_status status;
+       struct lttng_map *map;
+
+       if (dimension_count != 1) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       map = zmalloc(sizeof(struct lttng_map));
+       if (!map) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       if (name) {
+               status = lttng_map_set_name(map, name);
+               if (status != LTTNG_MAP_STATUS_OK) {
+                       goto free_map;
+               }
+       } else {
+               map->name = NULL;
+       }
+
+       map->dimension_count = dimension_count;
+       map->dimension_sizes = zmalloc(
+                       sizeof(*map->dimension_sizes) * dimension_count);
+       if (!map->dimension_sizes) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto free_name;
+       }
+
+       memcpy(map->dimension_sizes, dimension_sizes,
+                       sizeof(*map->dimension_sizes) * dimension_count);
+
+       map->domain = domain;
+       map->buffer_type = buffer_type;
+       map->bitness = bitness;
+       map->boundary_policy = boundary_policy;
+       map->coalesce_hits = coalesce_hits;
+
+       lttng_map_set_is_enabled(map, true);
+
+       urcu_ref_init(&map->ref);
+
+       *map_out = map;
+
+       status = LTTNG_MAP_STATUS_OK;
+
+       goto end;
+free_name:
+       free(map->name);
+free_map:
+       free(map);
+end:
+       return status;
+}
+
+unsigned int lttng_map_get_dimension_count(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->dimension_count;
+}
+
+enum lttng_map_status lttng_map_get_dimension_length(
+               const struct lttng_map *map, unsigned int dimension,
+               uint64_t *dimension_length)
+{
+       enum lttng_map_status status;
+
+       assert(map);
+
+       if (dimension >= map->dimension_count) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       *dimension_length = map->dimension_sizes[dimension];
+
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_bitness lttng_map_get_bitness(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->bitness;
+}
+
+enum lttng_domain_type lttng_map_get_domain(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->domain;
+}
+
+enum lttng_buffer_type lttng_map_get_buffer_type(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->buffer_type;
+}
+
+enum lttng_map_boundary_policy lttng_map_get_boundary_policy(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->boundary_policy;
+}
+
+bool lttng_map_get_coalesce_hits(const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->coalesce_hits;
+}
+
+LTTNG_HIDDEN
+int lttng_map_serialize(const struct lttng_map *map,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t header_offset, size_before_payload, size_name;
+       struct lttng_map_comm map_comm = {};
+       struct lttng_map_comm *header;
+
+       if (map->name != NULL) {
+               size_name = strlen(map->name) + 1;
+       } else {
+               size_name = 0;
+       }
+
+       map_comm.name_length = size_name;
+       map_comm.is_enabled = LTTNG_OPTIONAL_GET(map->is_enabled);
+       map_comm.bitness = map->bitness;
+       map_comm.domain = map->domain;
+       map_comm.buffer_type = map->buffer_type;
+       map_comm.boundary_policy = map->boundary_policy;
+       map_comm.dimension_count = map->dimension_count;
+       map_comm.coalesce_hits = map->coalesce_hits;
+
+       header_offset = payload->buffer.size;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &map_comm,
+                       sizeof(map_comm));
+       if (ret) {
+               goto end;
+       }
+
+       size_before_payload = payload->buffer.size;
+
+       /* map name */
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, map->name, size_name);
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, map->dimension_sizes,
+                       sizeof(*map->dimension_sizes) * map->dimension_count);
+       if (ret) {
+               goto end;
+       }
+
+       /* Update payload size. */
+       header = (typeof(header)) (payload->buffer.data + header_offset);
+       header->length = payload->buffer.size - size_before_payload;
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map **map)
+{
+       ssize_t ret, offset = 0;
+       const struct lttng_map_comm *map_comm;
+       enum lttng_map_status status;
+       unsigned int dimension_count;
+       uint64_t *dimension_sizes = NULL;
+       bool coalesce_hits;
+       const char *name = NULL;
+       enum lttng_domain_type domain;
+       enum lttng_buffer_type buffer_type;
+       enum lttng_map_bitness bitness;
+       enum lttng_map_boundary_policy boundary_policy;
+
+       if (!src_view || !map) {
+               ret = -1;
+               goto end;
+       }
+
+       map_comm = (typeof(map_comm)) src_view->buffer.data;
+       offset += sizeof(*map_comm);
+
+       domain = map_comm->domain;
+       buffer_type = map_comm->buffer_type;
+       bitness = map_comm->bitness;
+       boundary_policy = map_comm->boundary_policy;
+       dimension_count = map_comm->dimension_count;
+       coalesce_hits = map_comm->coalesce_hits;
+
+       if (map_comm->name_length != 0) {
+               struct lttng_payload_view name_view =
+                               lttng_payload_view_from_view(
+                                               src_view, offset,
+                                               map_comm->name_length);
+
+               name = name_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(&name_view.buffer,
+                                       name, map_comm->name_length)){
+                       ret = -1;
+                       goto end;
+               }
+               offset += map_comm->name_length;
+       }
+
+       size_t map_dim_sizes_len = sizeof(*(*map)->dimension_sizes) * dimension_count;
+
+       struct lttng_payload_view dimension_sizes_view =
+                       lttng_payload_view_from_view(src_view, offset,
+                               map_dim_sizes_len);
+
+       dimension_sizes = zmalloc(map_dim_sizes_len);
+       if (!dimension_sizes) {
+               ret = -1;
+               goto end;
+       }
+
+       memcpy(dimension_sizes, dimension_sizes_view.buffer.data,
+                       map_dim_sizes_len);
+
+       offset += map_dim_sizes_len;
+
+       status = lttng_map_create(name, dimension_count,
+                       dimension_sizes, domain, buffer_type, bitness,
+                       boundary_policy, coalesce_hits, map);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       lttng_map_set_is_enabled(*map, map_comm->is_enabled);
+
+       ret = offset;
+
+end:
+       free(dimension_sizes);
+       return ret;
+}
+
+LTTNG_HIDDEN
+void lttng_map_set_is_enabled(struct lttng_map *map, bool enabled)
+{
+       assert(map);
+
+       LTTNG_OPTIONAL_SET(&map->is_enabled, enabled);
+}
+
+int lttng_map_get_is_enabled(const struct lttng_map *map)
+{
+       assert(map);
+       return (int) LTTNG_OPTIONAL_GET(map->is_enabled);
+}
+
+LTTNG_HIDDEN
+void lttng_map_get(struct lttng_map *map)
+{
+       urcu_ref_get(&map->ref);
+}
+
+static void map_destroy_ref(struct urcu_ref *ref)
+{
+       struct lttng_map *map = container_of(ref, struct lttng_map, ref);
+
+       free(map->dimension_sizes);
+       free(map->name);
+       free(map);
+
+}
+
+LTTNG_HIDDEN
+void lttng_map_put(struct lttng_map *map)
+{
+       if (!map) {
+               return;
+       }
+
+       urcu_ref_put(&map->ref , map_destroy_ref);
+}
+
+
+void lttng_map_destroy(struct lttng_map *map)
+{
+       lttng_map_put(map);
+}
+
+static void delete_map_array_element(void *ptr)
+{
+       struct lttng_map *map = ptr;
+
+       lttng_map_put(map);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_list *lttng_map_list_create(void)
+{
+       struct lttng_map_list *map_list = NULL;
+
+       map_list = zmalloc(sizeof(*map_list));
+       if (!map_list) {
+               goto end;
+       }
+
+       lttng_dynamic_pointer_array_init(&map_list->array,
+                       delete_map_array_element);
+
+end:
+       return map_list;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_list_add(struct lttng_map_list *map_list,
+               struct lttng_map *map)
+{
+       enum lttng_map_status status;
+       int ret;
+
+       assert(map_list);
+       assert(map);
+
+       lttng_map_get(map);
+
+       ret = lttng_dynamic_pointer_array_add_pointer(&map_list->array, map);
+       if (ret) {
+               lttng_map_put(map);
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_list_create_from_payload(struct lttng_payload_view *src_view,
+               struct lttng_map_list **map_list)
+{
+       unsigned int i;
+       ssize_t ret, offset = 0;
+       const struct lttng_map_list_comm *map_list_comm;
+       struct lttng_map_list *local_map_list = NULL;
+
+       map_list_comm = (typeof(map_list_comm)) src_view->buffer.data;
+       offset += sizeof(*map_list_comm);
+
+       local_map_list = lttng_map_list_create();
+       if (!local_map_list) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < map_list_comm->count; i++) {
+               struct lttng_map *map = NULL;
+               struct lttng_payload_view map_view =
+                               lttng_payload_view_from_view(src_view, offset, -1);
+               ssize_t map_size;
+
+               map_size = lttng_map_create_from_payload(&map_view, &map);
+               if (map_size < 0) {
+                       ret = map_size;
+                       goto end;
+               }
+
+               /* Transfer ownership of the map to the collection. */
+               ret = lttng_map_list_add(local_map_list, map);
+               lttng_map_put(map);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               offset += map_size;
+       }
+
+       /* Pass ownership to caller. */
+       *map_list = local_map_list;
+       local_map_list = NULL;
+
+       ret = offset;
+end:
+       lttng_map_list_destroy(local_map_list);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_map_list_serialize(const struct lttng_map_list *map_list,
+               struct lttng_payload *payload)
+{
+       int ret;
+       unsigned int i, count;
+       enum lttng_map_status status;
+       struct lttng_map_list_comm map_list_comm = {};
+
+       status = lttng_map_list_get_count(map_list, &count);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       map_list_comm.count = count;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &map_list_comm,
+                       sizeof(map_list_comm));
+       if (ret) {
+               goto end;
+       }
+       for (i = 0; i < count; i++) {
+               const struct lttng_map *map =
+                               lttng_map_list_get_at_index(map_list, i);
+
+               assert(map);
+
+               ret = lttng_map_serialize(map, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+const struct lttng_map *lttng_map_list_get_at_index(
+               const struct lttng_map_list *map_list, unsigned int index)
+{
+       struct lttng_map *map = NULL;
+
+       assert(map_list);
+       if (index >= lttng_dynamic_pointer_array_get_count(&map_list->array)) {
+               goto end;
+       }
+
+       map = (struct lttng_map *)
+                       lttng_dynamic_pointer_array_get_pointer(
+                                       &map_list->array, index);
+end:
+       return map;
+}
+
+enum lttng_map_status lttng_map_list_get_count(
+               const struct lttng_map_list *map_list, unsigned int *count)
+{
+       enum lttng_map_status status = LTTNG_MAP_STATUS_OK;
+
+       if (!map_list || !count) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(&map_list->array);
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+void lttng_map_list_destroy(struct lttng_map_list *map_list)
+{
+       if (!map_list) {
+               return;
+       }
+
+       lttng_dynamic_pointer_array_reset(&map_list->array);
+       free(map_list);
+}
+
+struct lttng_map_key_value_pair *lttng_map_key_value_pair_create(const char *key,
+               int64_t value)
+{
+       struct lttng_map_key_value_pair *key_value;
+
+       key_value = zmalloc(sizeof(struct lttng_map_key_value_pair));
+       if (!key_value) {
+               goto end;
+       }
+
+       key_value->key = strdup(key);
+       if (!key_value->key) {
+               free(key_value);
+               key_value = NULL;
+               goto end;
+       }
+       key_value->value = value;
+
+end:
+       return key_value;
+}
+
+enum lttng_map_status lttng_map_key_value_pair_get_key(
+               const struct lttng_map_key_value_pair *key_value,
+               const char **key)
+{
+       assert(key_value);
+       assert(key_value->key);
+
+       *key = key_value->key;
+       return LTTNG_MAP_STATUS_OK;
+}
+
+enum lttng_map_status lttng_map_key_value_pair_get_value(
+               const struct lttng_map_key_value_pair *key_value,
+               int64_t *value)
+{
+       assert(key_value);
+       *value = key_value->value;
+       return LTTNG_MAP_STATUS_OK;
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_value_pair_set_has_overflowed(
+               struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       key_value->has_overflowed = true;
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_value_pair_set_has_underflowed(
+               struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       key_value->has_underflowed = true;
+}
+
+bool lttng_map_key_value_pair_get_has_overflowed(
+               const struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       return key_value->has_overflowed;
+}
+
+bool lttng_map_key_value_pair_get_has_underflowed(
+               const struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       return key_value->has_underflowed;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_key_value_pair_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map_key_value_pair **key_value)
+{
+       const struct lttng_map_key_value_pair_comm *kv_pair_comm;
+       struct lttng_map_key_value_pair *kv_pair;
+       ssize_t ret, offset = 0;
+       const char *key;
+       int64_t value;
+
+       if (!src_view || !key_value) {
+               ret = -1;
+               goto end;
+       }
+
+       kv_pair_comm = (typeof(kv_pair_comm)) src_view->buffer.data;
+       offset += sizeof(*kv_pair_comm);
+
+       if (kv_pair_comm->key_length == 0) {
+               ret = -1;
+               goto end;
+       }
+
+       value = kv_pair_comm->value;
+
+       struct lttng_payload_view key_view =
+               lttng_payload_view_from_view(src_view, offset,
+                       kv_pair_comm->key_length);
+       key = key_view.buffer.data;
+       if (!lttng_buffer_view_contains_string(&key_view.buffer,
+                       key, kv_pair_comm->key_length)) {
+               ret = -1;
+               goto end;
+       }
+
+       offset += kv_pair_comm->key_length;
+
+       kv_pair = lttng_map_key_value_pair_create(key, value);
+       if (!kv_pair) {
+               ret = -1;
+               goto end;
+       }
+
+       kv_pair->has_overflowed = kv_pair_comm->has_overflowed;
+       kv_pair->has_underflowed = kv_pair_comm->has_underflowed;
+
+       *key_value = kv_pair;
+
+       ret = offset;
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_map_key_value_pair_serialize(
+               const struct lttng_map_key_value_pair *key_value,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t key_len;
+       struct lttng_map_key_value_pair_comm kv_pair_comm = {0};
+
+       assert(key_value);
+       assert(key_value->key);
+
+       key_len = strlen(key_value->key) + 1;
+
+       kv_pair_comm.key_length = key_len;
+       kv_pair_comm.value = key_value->value;
+       kv_pair_comm.has_overflowed = key_value->has_overflowed;
+       kv_pair_comm.has_underflowed = key_value->has_underflowed;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &kv_pair_comm,
+                       sizeof(kv_pair_comm));
+       if (ret) {
+               goto end;
+       }
+
+       /* Append key.*/
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, key_value->key, key_len);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+void lttng_map_key_value_pair_destroy(struct lttng_map_key_value_pair *key_value)
+{
+       if (!key_value) {
+               return;
+       }
+
+       free(key_value->key);
+       free(key_value);
+}
+
+static void delete_map_key_value_pair_array_element(void *ptr)
+{
+       struct lttng_map_key_value_pair *key_value = ptr;
+       lttng_map_key_value_pair_destroy(key_value);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_key_value_pair_list *lttng_map_key_value_pair_list_create(
+               enum lttng_map_key_value_pair_list_type type,
+               bool summed_all_cpus)
+{
+       struct lttng_map_key_value_pair_list *map_key_values = NULL;
+
+       map_key_values = zmalloc(sizeof(*map_key_values));
+       if (!map_key_values) {
+               goto end;
+       }
+
+       map_key_values->type = type;
+       map_key_values->summed_all_cpus = summed_all_cpus;
+
+       lttng_dynamic_pointer_array_init(&map_key_values->array,
+                       delete_map_key_value_pair_array_element);
+
+end:
+       return map_key_values;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_set_identifier(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               uint64_t identifier)
+{
+       enum lttng_map_status status;
+       assert(kv_pair_list);
+
+       switch (kv_pair_list->type) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               kv_pair_list->id = identifier;
+               status = LTTNG_MAP_STATUS_OK;
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED:
+               ERR("Cannot set an identifier for an UST per-pid aggregation key value pair list");
+               status = LTTNG_MAP_STATUS_INVALID;
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL:
+               ERR("Cannot set an identifier for a kernel key value pair list");
+               status = LTTNG_MAP_STATUS_INVALID;
+               break;
+       default:
+               ERR("Unknown key value par list type %d", kv_pair_list->type);
+               abort();
+       }
+
+       return status;
+}
+
+bool lttng_map_key_value_pair_list_get_summed_all_cpu(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       return kv_pair_list->summed_all_cpus;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_set_cpu(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               uint64_t cpu)
+{
+       assert(kv_pair_list);
+
+       kv_pair_list->cpu = cpu;
+
+       return LTTNG_MAP_STATUS_OK;
+}
+
+uint64_t lttng_map_key_value_pair_list_get_cpu(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       return kv_pair_list->cpu;
+}
+
+enum lttng_map_key_value_pair_list_type lttng_map_key_value_pair_list_get_type(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       return kv_pair_list->type;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_append_key_value(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               struct lttng_map_key_value_pair *key_value)
+{
+       int ret;
+       enum lttng_map_status status;
+
+       assert(kv_pair_list);
+       assert(key_value);
+
+       ret = lttng_dynamic_pointer_array_add_pointer(&kv_pair_list->array,
+                       key_value);
+       if (ret) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_STATUS_OK;
+
+end:
+       return status;
+}
+
+uint64_t lttng_map_key_value_pair_list_get_identifer(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       switch (kv_pair_list->type) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED:
+               ERR("No identifier for UST per-pid aggregation key value pair lists");
+               abort();
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL:
+               ERR("No identifier for kernel key value pair lists");
+               abort();
+               break;
+       default:
+               ERR("Unknown key value par list type %d", kv_pair_list->type);
+               abort();
+       }
+
+       return kv_pair_list->id;
+}
+
+const struct lttng_map_key_value_pair *lttng_map_key_value_pair_list_get_at_index(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               unsigned int index)
+{
+       struct lttng_map_key_value_pair *key_value = NULL;
+
+       assert(kv_pair_list);
+       if (index >= lttng_dynamic_pointer_array_get_count(&kv_pair_list->array)) {
+               goto end;
+       }
+
+       key_value = (struct lttng_map_key_value_pair *)
+                       lttng_dynamic_pointer_array_get_pointer(
+                                       &kv_pair_list->array, index);
+end:
+       return key_value;
+}
+
+enum lttng_map_status lttng_map_key_value_pair_list_get_count(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               unsigned int *count)
+{
+       enum lttng_map_status status;
+
+       if (!kv_pair_list || !count) {
+               status = LTTNG_MAP_STATUS_INVALID;;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(&kv_pair_list->array);
+
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+void lttng_map_key_value_pair_list_destroy(struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       if (!kv_pair_list) {
+               return;
+       }
+
+       lttng_dynamic_pointer_array_reset(&kv_pair_list->array);
+       free(kv_pair_list);
+}
+
+int lttng_map_key_value_pair_list_serialize(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               struct lttng_payload *payload)
+{
+       int ret;
+       unsigned int i, count;
+       enum lttng_map_status status;
+       struct lttng_map_key_value_pair_list_comm kv_pair_list_comm = {};
+
+       kv_pair_list_comm.id = kv_pair_list->id;
+       kv_pair_list_comm.cpu = kv_pair_list->cpu;
+       kv_pair_list_comm.type = (uint8_t) kv_pair_list->type;
+       kv_pair_list_comm.summed_all_cpus = (uint8_t) kv_pair_list->summed_all_cpus;
+
+       status = lttng_map_key_value_pair_list_get_count(kv_pair_list, &count);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       kv_pair_list_comm.count = count;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &kv_pair_list_comm,
+                       sizeof(kv_pair_list_comm));
+       if (ret) {
+               goto end;
+       }
+       for (i = 0; i < count; i++) {
+               const struct lttng_map_key_value_pair *kv_pair =
+                               lttng_map_key_value_pair_list_get_at_index(kv_pair_list, i);
+
+               assert(kv_pair);
+
+               ret = lttng_map_key_value_pair_serialize(kv_pair, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_key_value_pair_list_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map_key_value_pair_list **kv_pair_list)
+{
+       ssize_t ret, offset = 0;
+       unsigned int i;
+       enum lttng_map_status status;
+       const struct lttng_map_key_value_pair_list_comm *kv_pair_list_comm;
+       struct lttng_map_key_value_pair_list *local_key_values = NULL;
+
+       kv_pair_list_comm = (typeof(kv_pair_list_comm)) src_view->buffer.data;
+       offset += sizeof(*kv_pair_list_comm);
+
+       local_key_values = lttng_map_key_value_pair_list_create(
+                       kv_pair_list_comm->type, kv_pair_list_comm->summed_all_cpus);
+       if (!local_key_values) {
+               ret = -1;
+               goto end;
+       }
+
+       local_key_values->cpu = kv_pair_list_comm->cpu;
+
+       switch (lttng_map_key_value_pair_list_get_type(local_key_values)) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               status = lttng_map_key_value_pair_list_set_identifier(local_key_values,
+                       kv_pair_list_comm->id);
+               if (status != LTTNG_MAP_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       default:
+               break;
+       }
+
+       for (i = 0; i < kv_pair_list_comm->count; i++) {
+               struct lttng_map_key_value_pair *kv_pair = NULL;
+               struct lttng_payload_view kv_view =
+                               lttng_payload_view_from_view(src_view, offset, -1);
+               ssize_t kv_size;
+
+               kv_size = lttng_map_key_value_pair_create_from_payload(
+                               &kv_view, &kv_pair);
+               if (kv_size < 0) {
+                       ret = kv_size;
+                       goto end;
+               }
+
+               /* Transfer ownership of the key-value to the collection. */
+               status = lttng_map_key_value_pair_list_append_key_value(local_key_values,
+                               kv_pair);
+               if (status != LTTNG_MAP_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               offset += kv_size;
+       }
+
+       /* Pass ownership to caller. */
+       *kv_pair_list = local_key_values;
+       local_key_values = NULL;
+
+       ret = offset;
+end:
+       lttng_map_key_value_pair_list_destroy(local_key_values);
+       return ret;
+}
+
+static void delete_map_key_value_pair_list_array_element(void *ptr)
+{
+       struct lttng_map_key_value_pair_list *kv_list = ptr;
+       lttng_map_key_value_pair_list_destroy(kv_list);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_content *lttng_map_content_create(
+               enum lttng_buffer_type type)
+{
+       struct lttng_map_content *map_content = NULL;
+
+       map_content = zmalloc(sizeof(*map_content));
+       if (!map_content) {
+               goto end;
+       }
+
+       map_content->type = type;
+
+       lttng_dynamic_pointer_array_init(&map_content->array,
+                       delete_map_key_value_pair_list_array_element);
+
+end:
+       return map_content;
+}
+
+enum lttng_map_status lttng_map_content_get_count(
+               const struct lttng_map_content *map_content,
+               unsigned int *count)
+{
+       enum lttng_map_status status = LTTNG_MAP_STATUS_OK;
+
+       if (!map_content || !count) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(&map_content->array);
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_buffer_type lttng_map_content_get_buffer_type(
+                       const struct lttng_map_content *map_content)
+{
+       assert(map_content);
+
+       return map_content->type;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_content_append_key_value_list(
+               struct lttng_map_content *map_content,
+               struct lttng_map_key_value_pair_list *kv_list)
+{
+       int ret;
+       enum lttng_map_status status;
+
+       assert(map_content);
+       assert(kv_list);
+
+       ret = lttng_dynamic_pointer_array_add_pointer(&map_content->array,
+                       kv_list);
+       if (ret) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_STATUS_OK;
+
+end:
+       return status;
+}
+
+const struct lttng_map_key_value_pair_list *lttng_map_content_get_at_index(
+               const struct lttng_map_content *map_content,
+               unsigned int index)
+{
+       struct lttng_map_key_value_pair_list *kv_pair_list = NULL;
+
+       assert(map_content);
+       if (index >= lttng_dynamic_pointer_array_get_count(&map_content->array)) {
+               goto end;
+       }
+
+       kv_pair_list = (struct lttng_map_key_value_pair_list *)
+                       lttng_dynamic_pointer_array_get_pointer(
+                                       &map_content->array, index);
+end:
+       return kv_pair_list;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_content_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map_content **map_content)
+{
+       ssize_t ret, offset = 0;
+       unsigned int i;
+       struct lttng_map_content_comm *map_content_comm;
+       struct lttng_map_content *local_map_content;
+
+       map_content_comm = (typeof(map_content_comm)) src_view->buffer.data;
+       offset += sizeof(*map_content_comm);
+
+       local_map_content = lttng_map_content_create(map_content_comm->type);
+       if (!local_map_content) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < map_content_comm->count; i++) {
+               struct lttng_map_key_value_pair_list *kv_pair_list = NULL;
+               struct lttng_payload_view kv_list_view =
+                               lttng_payload_view_from_view(src_view, offset, -1);
+               ssize_t kv_list_size;
+
+               kv_list_size = lttng_map_key_value_pair_list_create_from_payload(
+                               &kv_list_view, &kv_pair_list);
+               if (kv_list_size < 0) {
+                       ret = kv_list_size;
+                       goto end;
+               }
+
+               /* Transfer ownership of the key-value to the collection. */
+               ret = lttng_map_content_append_key_value_list(local_map_content,
+                               kv_pair_list);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               offset += kv_list_size;
+       }
+
+       /* Pass ownership to caller. */
+       *map_content = local_map_content;
+       local_map_content = NULL;
+
+       ret = offset;
+end:
+       lttng_map_content_destroy(local_map_content);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_map_content_serialize(
+               const struct lttng_map_content *map_content,
+               struct lttng_payload *payload)
+{
+       int ret;
+       unsigned int i, count;
+       enum lttng_map_status status;
+       struct lttng_map_content_comm map_content_comm = {};
+
+       status = lttng_map_content_get_count(map_content, &count);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       map_content_comm.count = count;
+       map_content_comm.type = lttng_map_content_get_buffer_type(map_content);
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &map_content_comm,
+                       sizeof(map_content_comm));
+       if (ret) {
+               goto end;
+       }
+       for (i = 0; i < count; i++) {
+               const struct lttng_map_key_value_pair_list *kv_pair_list =
+                               lttng_map_content_get_at_index(map_content, i);
+
+               assert(kv_pair_list);
+
+               ret = lttng_map_key_value_pair_list_serialize(kv_pair_list, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+void lttng_map_content_destroy(struct lttng_map_content *map_content)
+{
+       if (!map_content) {
+               return;
+       }
+
+       lttng_dynamic_pointer_array_reset(&map_content->array);
+       free(map_content);
+}
This page took 0.035414 seconds and 5 git commands to generate.