+static unsigned long ht_hash_event(const void *_key, unsigned long seed)
+{
+ uint64_t xored_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));
+
+ return hash_key_u64(&xored_key, seed);
+}
+
+static int compare_enums(const struct ust_registry_enum *reg_enum_a,
+ const struct ust_registry_enum *reg_enum_b)
+{
+ int ret = 0;
+ size_t i;
+
+ assert(strcmp(reg_enum_a->name, reg_enum_b->name) == 0);
+ if (reg_enum_a->nr_entries != reg_enum_b->nr_entries) {
+ ret = -1;
+ goto end;
+ }
+ for (i = 0; i < reg_enum_a->nr_entries; i++) {
+ const struct ustctl_enum_entry *entries_a, *entries_b;
+
+ entries_a = ®_enum_a->entries[i];
+ entries_b = ®_enum_b->entries[i];
+ if (entries_a->start.value != entries_b->start.value) {
+ ret = -1;
+ goto 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;
+ }
+ }
+end:
+ return ret;
+}
+
+/*
+ * Hash table match function for enumerations in the session. Match is
+ * performed on enumeration name, and confirmed by comparing the enum
+ * entries.
+ */
+static int ht_match_enum(struct cds_lfht_node *node, const void *_key)
+{
+ struct ust_registry_enum *_enum;
+ const struct ust_registry_enum *key;
+
+ assert(node);
+ assert(_key);
+
+ _enum = caa_container_of(node, struct ust_registry_enum,
+ node.node);
+ assert(_enum);
+ key = _key;
+
+ if (strncmp(_enum->name, key->name, LTTNG_UST_SYM_NAME_LEN)) {
+ goto no_match;
+ }
+ if (compare_enums(_enum, key)) {
+ goto no_match;
+ }
+
+ /* Match. */
+ return 1;
+
+no_match:
+ return 0;
+}
+
+/*
+ * Hash table match function for enumerations in the session. Match is
+ * performed by enumeration ID.
+ */
+static int ht_match_enum_id(struct cds_lfht_node *node, const void *_key)
+{
+ struct ust_registry_enum *_enum;
+ const struct ust_registry_enum *key = _key;
+
+ assert(node);
+ assert(_key);
+
+ _enum = caa_container_of(node, struct ust_registry_enum, node.node);
+ assert(_enum);
+
+ if (_enum->id != key->id) {
+ goto no_match;
+ }
+
+ /* Match. */
+ return 1;
+
+no_match:
+ return 0;
+}
+
+/*
+ * Hash table hash function for enumerations in the session. The
+ * enumeration name is used for hashing.
+ */
+static unsigned long ht_hash_enum(void *_key, unsigned long seed)
+{
+ struct ust_registry_enum *key = _key;
+
+ assert(key);
+ return hash_key_str(key->name, seed);
+}
+
+/*
+ * Return negative value on error, 0 if OK.
+ *
+ * TODO: we could add stricter verification of more types to catch
+ * errors in liblttng-ust implementation earlier than consumption by the
+ * trace reader.
+ */
+static
+int validate_event_field(struct ustctl_field *field,
+ const char *event_name,
+ struct ust_app *app)
+{
+ int ret = 0;
+
+ switch(field->type.atype) {
+ case ustctl_atype_integer:
+ case ustctl_atype_enum:
+ case ustctl_atype_array:
+ case ustctl_atype_sequence:
+ case ustctl_atype_string:
+ case ustctl_atype_variant:
+ break;
+ case ustctl_atype_struct:
+ if (field->type.u._struct.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) {
+ 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->name,
+ event_name);
+ ret = -EINVAL;
+ goto end;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ ret = -ENOENT;
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static
+int validate_event_fields(size_t nr_fields, struct ustctl_field *fields,
+ const char *event_name, struct ust_app *app)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr_fields; i++) {
+ if (validate_event_field(&fields[i], event_name, app) < 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+