lttng-ctl: add event field value API
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 1 May 2020 20:31:01 +0000 (16:31 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 11 Mar 2021 20:31:53 +0000 (15:31 -0500)
This patch adds a new read-only event field value API to liblttng-ctl.
It also adds the internal functions to create such objects.

As of this patch, an event field value is one of:

* An unsigned integer (64-bit).
* A signed integer (64-bit).
* An unsigned enumeration (64-bit).
* A signed enumeration (64-bit).
* A real number (double precision).
* A string (UTF-8).
* An array of zero or more event field values.

The first purpose of this API will be to access the captured field
values of a notification's trigger condition evaluation.

An enumeration event field value conceptually is an integer event field
value, therefore lttng_event_field_value_unsigned_int_get_value() works
for an unsigned enumeration and
lttng_event_field_value_signed_int_get_value() works for a signed
enumeration.

The compound event field values (array only, as of this patch) can
return the `LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE` status when you
access a contained event field value. This indicates that there is no
field at this location. For the captured field value use case, it means
the event did not have any field at that position considering the
condition's capture descriptors. Internally, call
lttng_event_field_value_array_append_unavailable() to append an
unavailable event field value to an array field value.

The lttng_event_field_value_array_get_element_at_index() function can
also return an event field value of which the type, as returned by
lttng_event_field_value_get_type(), is
`LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN`. This is different from the
`LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE` status: the event field
value exists (which is why there's a valid
`struct lttng_event_field_value *`), but its type is unknown by this
version of the library. This makes it possible to add new event field
value types in the future while remaining forward compatible.

Note that enumeration labels will not visible to clients since the
kernel tracer does not make their content accessible to the session
daemon.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I04d327d9f50ff6c6e2ad1f5a1e56c3af25c92c15
Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479

include/Makefile.am
include/lttng/event-field-value-internal.h [new file with mode: 0644]
include/lttng/event-field-value.h [new file with mode: 0644]
include/lttng/lttng.h
src/common/Makefile.am
src/common/event-field-value.c [new file with mode: 0644]

index 54fec49a2ecb1fd0eb3475cc8786df7c06520a9b..b75602b270ab6773677eb24c34d2db397c802bdf 100644 (file)
@@ -104,6 +104,7 @@ lttnginclude_HEADERS = \
        lttng/domain.h \
        lttng/event.h \
        lttng/event-expr.h \
+       lttng/event-field-value.h \
        lttng/handle.h \
        lttng/session.h \
        lttng/lttng-error.h \
@@ -178,6 +179,7 @@ noinst_HEADERS = \
        lttng/domain-internal.h \
        lttng/event-internal.h \
        lttng/event-expr-internal.h \
+       lttng/event-field-value-internal.h \
        lttng/rotate-internal.h \
        lttng/ref-internal.h \
        lttng/location-internal.h \
diff --git a/include/lttng/event-field-value-internal.h b/include/lttng/event-field-value-internal.h
new file mode 100644 (file)
index 0000000..e0b67e9
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_FIELD_VALUE_INTERNAL_H
+#define LTTNG_EVENT_FIELD_VALUE_INTERNAL_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <lttng/event-field-value.h>
+#include <common/dynamic-array.h>
+
+struct lttng_event_field_value {
+       enum lttng_event_field_value_type type;
+};
+
+/*
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT`.
+ */
+struct lttng_event_field_value_uint {
+       struct lttng_event_field_value parent;
+       uint64_t val;
+};
+
+/*
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT`.
+ */
+struct lttng_event_field_value_int {
+       struct lttng_event_field_value parent;
+       int64_t val;
+};
+
+/*
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM` and
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM` (base).
+ */
+struct lttng_event_field_value_enum {
+       struct lttng_event_field_value parent;
+
+       /*
+        * Array of `char *` (owned by this).
+        */
+       struct lttng_dynamic_pointer_array labels;
+};
+
+/*
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM`.
+ */
+struct lttng_event_field_value_enum_uint {
+       struct lttng_event_field_value_enum parent;
+       uint64_t val;
+};
+
+/*
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`.
+ */
+struct lttng_event_field_value_enum_int {
+       struct lttng_event_field_value_enum parent;
+       int64_t val;
+};
+
+/* `LTTNG_EVENT_FIELD_VALUE_TYPE_REAL` */
+struct lttng_event_field_value_real {
+       struct lttng_event_field_value parent;
+       double val;
+};
+
+/* `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING` */
+struct lttng_event_field_value_string {
+       struct lttng_event_field_value parent;
+
+       /* Owned by this */
+       char *val;
+};
+
+/* `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING` */
+struct lttng_event_field_value_array {
+       struct lttng_event_field_value parent;
+
+       /*
+        * Array of `struct lttng_event_field_value *` (owned by this).
+        *
+        * A `NULL` element means it's unavailable
+        * (`LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE` status).
+        */
+       struct lttng_dynamic_pointer_array elems;
+};
+
+/*
+ * This is internal since the session daemon knows nothing about the
+ * enumeration fields produced by the kernel tracer. Indeed, the kernel tracer
+ * manages its own metadata which remains opaque to the rest of the toolchain.
+ *
+ * Enumerations could be supported for the user space tracer, but it is not the
+ * case right now.
+ */
+
+/*
+ * Sets `*count` to the number of labels of the enumeration event field
+ * value `field_val`.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`:
+ *     * `field_val` is `NULL`.
+ *     * The type of `field_val` is not
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM` or
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`.
+ *     * `count` is `NULL`.
+ */
+LTTNG_HIDDEN
+enum lttng_event_field_value_status
+lttng_event_field_value_enum_get_label_count(
+               const struct lttng_event_field_value *field_val,
+               unsigned int *count);
+
+/*
+ * Returns the label at index `index` of the enumeration event field
+ * value `field_val`, or `NULL` if:
+ *
+ * * `field_val` is `NULL`.
+ * * The type of `field_val` is not
+ *   `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM` or
+ *   `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`.
+ * * `index` is greater than or equal to the label count of `field_val`,
+ *   as returned by lttng_event_field_value_enum_get_label_count().
+ */
+LTTNG_HIDDEN
+const char *lttng_event_field_value_enum_get_label_at_index(
+               const struct lttng_event_field_value *field_val,
+               unsigned int index);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_uint_create(
+               uint64_t val);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_int_create(
+               int64_t val);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_enum_uint_create(
+               uint64_t val);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_enum_int_create(
+               int64_t val);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_real_create(double val);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_string_create(
+               const char *val);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_string_create_with_size(
+               const char *val, size_t size);
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_array_create(void);
+
+LTTNG_HIDDEN
+int lttng_event_field_value_enum_append_label(
+               struct lttng_event_field_value *field_val, const char *label);
+
+LTTNG_HIDDEN
+int lttng_event_field_value_enum_append_label_with_size(
+               struct lttng_event_field_value *field_val, const char *label,
+               size_t size);
+
+LTTNG_HIDDEN
+int lttng_event_field_value_array_append(
+               struct lttng_event_field_value *array_field_val,
+               struct lttng_event_field_value *field_val);
+
+LTTNG_HIDDEN
+int lttng_event_field_value_array_append_unavailable(
+               struct lttng_event_field_value *array_field_val);
+
+LTTNG_HIDDEN
+void lttng_event_field_value_destroy(struct lttng_event_field_value *field_val);
+
+#endif /* LTTNG_EVENT_FIELD_VALUE_INTERNAL_H */
diff --git a/include/lttng/event-field-value.h b/include/lttng/event-field-value.h
new file mode 100644 (file)
index 0000000..db4a4fb
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_FIELD_VALUE_H
+#define LTTNG_EVENT_FIELD_VALUE_H
+
+#include <stdint.h>
+
+struct lttng_event_field_value;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Types of a event field value expression.
+ */
+enum lttng_event_field_value_type {
+       /*
+        * Unknown.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN = -2,
+
+       /*
+        * Returned by lttng_event_field_value_get_type() with an
+        * invalid parameter.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID = -1,
+
+       /*
+        * Unsigned integer event field value.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT = 0,
+
+       /*
+        * Signed integer event field value.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT = 1,
+
+       /*
+        * Unsigned enumeration event field value.
+        *
+        * This type conceptually inherits
+        * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT`.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM = 2,
+
+       /*
+        * Signed enumeration event field value.
+        *
+        * This type conceptually inherits
+        * `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT`.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM = 3,
+
+       /*
+        * Real event field value.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_REAL = 4,
+
+       /*
+        * String event field value.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_STRING = 5,
+
+       /*
+        * Array event field value.
+        */
+       LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY = 6,
+};
+
+/*
+ * Event field value API status codes.
+ */
+enum lttng_event_field_value_status {
+       /*
+        * Event field value is not available.
+        */
+       LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE = -2,
+
+       /*
+        * Invalid parameter.
+        */
+       LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID = -1,
+
+       /*
+        * Success.
+        */
+       LTTNG_EVENT_FIELD_VALUE_STATUS_OK = 0,
+};
+
+/*
+ * Returns the type of the event field value `field_val`, or:
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN`:
+ *     The type of `field_val` is unknown as of this version of the
+ *     LTTng control library.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID`:
+ *     `field_val` is `NULL`.
+ */
+extern enum lttng_event_field_value_type lttng_event_field_value_get_type(
+               const struct lttng_event_field_value *field_val);
+
+/*
+ * Sets `*val` to the raw value of the unsigned integer/enumeration
+ * event field value `field_val`.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`:
+ *     * `field_val` is `NULL`.
+ *     * The type of `field_val` is not
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT` or
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM`.
+ *     * `val` is `NULL`.
+ */
+extern enum lttng_event_field_value_status
+lttng_event_field_value_unsigned_int_get_value(
+               const struct lttng_event_field_value *field_val, uint64_t *val);
+
+/*
+ * Sets `*val` to the raw value of the signed integer/enumeration event
+ * field value `field_val`.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`:
+ *     * `field_val` is `NULL`.
+ *     * The type of `field_val` is not
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT` or
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM`.
+ *     * `val` is `NULL`.
+ */
+extern enum lttng_event_field_value_status
+lttng_event_field_value_signed_int_get_value(
+               const struct lttng_event_field_value *field_val, int64_t *val);
+
+/*
+ * Sets `*val` to the raw value of the real event field value
+ * `field_val`.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`:
+ *     * `field_val` is `NULL`.
+ *     * The type of `field_val` is not
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_REAL`.
+ *     * `val` is `NULL`.
+ */
+extern enum lttng_event_field_value_status
+lttng_event_field_value_real_get_value(
+               const struct lttng_event_field_value *field_val, double *val);
+
+/*
+ * Returns the raw value (an UTF-8 C string) of the string event field
+ * value `field_val`, or `NULL` if:
+ *
+ * * `field_val` is `NULL`.
+ * * The type of `field_val` is not
+ *   `LTTNG_EVENT_FIELD_VALUE_TYPE_STRING`.
+ */
+extern const char *lttng_event_field_value_string_get_value(
+               const struct lttng_event_field_value *field_val);
+
+/*
+ * Sets `*length` to the length (the number of contained elements) of
+ * the array event field value `field_val`.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`:
+ *     * `field_val` is `NULL`.
+ *     * The type of `field_val` is not
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY`.
+ *     * `length` is `NULL`.
+ */
+extern enum lttng_event_field_value_status
+lttng_event_field_value_array_get_length(
+               const struct lttng_event_field_value *field_val,
+               unsigned int *length);
+
+/*
+ * Sets `*elem_field_val` to the event field value at index `index` in
+ * the array event field value `field_val`.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID`:
+ *     * `field_val` is `NULL`.
+ *     * The type of `field_val` is not
+ *       `LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY`.
+ *     * `index` is greater than or equal to the length of `field_val`,
+ *       as returned by lttng_event_field_value_array_get_length().
+ *
+ * `LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE`:
+ *     * No event field value exists at index `index` within
+ *       `field_val`.
+ */
+extern enum lttng_event_field_value_status
+lttng_event_field_value_array_get_element_at_index(
+               const struct lttng_event_field_value *field_val,
+               unsigned int index,
+               const struct lttng_event_field_value **elem_field_val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_FIELD_VALUE_H */
index 2b8a56e37d6d06a8ba0942d27098eec2464a1ab4..c665d3c9bcaabb40737d47cceaae841ff04abfdf 100644 (file)
@@ -38,6 +38,7 @@
 #include <lttng/endpoint.h>
 #include <lttng/event.h>
 #include <lttng/event-expr.h>
+#include <lttng/event-field-value.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/event-rule/kprobe.h>
 #include <lttng/event-rule/syscall.h>
index c7220f703999a6b7adc573e74f12236bc31045d8..4b549aa08e2baf06212a9f853a73ab1c8f78af92 100644 (file)
@@ -60,6 +60,7 @@ libcommon_la_SOURCES = \
        evaluation.c \
        event.c \
        event-expr-to-bytecode.c event-expr-to-bytecode.h \
+       event-field-value.c \
        event-rule/event-rule.c \
        event-rule/kprobe.c \
        event-rule/syscall.c \
diff --git a/src/common/event-field-value.c b/src/common/event-field-value.c
new file mode 100644 (file)
index 0000000..d768788
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * event-field-value.c
+ *
+ * Linux Trace Toolkit Control Library
+ *
+ * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <common/error.h>
+#include <common/macros.h>
+#include <lttng/event-field-value-internal.h>
+
+static
+struct lttng_event_field_value *create_empty_field_val(
+               enum lttng_event_field_value_type type, size_t size)
+{
+       struct lttng_event_field_value *field_val;
+
+       field_val = zmalloc(size);
+       if (!field_val) {
+               goto end;
+       }
+
+       field_val->type = type;
+
+end:
+       return field_val;
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_uint_create(
+               uint64_t val)
+{
+       struct lttng_event_field_value_uint *field_val;
+
+       field_val = container_of(create_empty_field_val(
+                       LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT,
+                       sizeof(*field_val)),
+                       struct lttng_event_field_value_uint, parent);
+       if (!field_val) {
+               goto error;
+       }
+
+       field_val->val = val;
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent);
+
+end:
+       return &field_val->parent;
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_int_create(
+               int64_t val)
+{
+       struct lttng_event_field_value_int *field_val;
+
+       field_val = container_of(create_empty_field_val(
+                       LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT,
+                       sizeof(*field_val)),
+                       struct lttng_event_field_value_int, parent);
+       if (!field_val) {
+               goto error;
+       }
+
+       field_val->val = val;
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent);
+
+end:
+       return &field_val->parent;
+}
+
+static
+struct lttng_event_field_value_enum *create_enum_field_val(
+               enum lttng_event_field_value_type type, size_t size)
+{
+       struct lttng_event_field_value_enum *field_val;
+
+       field_val = container_of(create_empty_field_val(type, size),
+                       struct lttng_event_field_value_enum, parent);
+       if (!field_val) {
+               goto error;
+       }
+
+       lttng_dynamic_pointer_array_init(&field_val->labels, free);
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent);
+
+end:
+       return field_val;
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_enum_uint_create(
+               uint64_t val)
+{
+       struct lttng_event_field_value_enum_uint *field_val;
+
+       field_val = container_of(create_enum_field_val(
+                       LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM,
+                       sizeof(*field_val)),
+                       struct lttng_event_field_value_enum_uint, parent);
+       if (!field_val) {
+               goto error;
+       }
+
+       field_val->val = val;
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent.parent);
+
+end:
+       return &field_val->parent.parent;
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_enum_int_create(
+               int64_t val)
+{
+       struct lttng_event_field_value_enum_int *field_val;
+
+       field_val = container_of(create_enum_field_val(
+                       LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM,
+                       sizeof(*field_val)),
+                       struct lttng_event_field_value_enum_int, parent);
+       if (!field_val) {
+               goto error;
+       }
+
+       field_val->val = val;
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent.parent);
+
+end:
+       return &field_val->parent.parent;
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_real_create(double val)
+{
+       struct lttng_event_field_value_real *field_val = container_of(
+                       create_empty_field_val(
+                               LTTNG_EVENT_FIELD_VALUE_TYPE_REAL,
+                               sizeof(*field_val)),
+                       struct lttng_event_field_value_real, parent);
+
+       if (!field_val) {
+               goto error;
+       }
+
+       field_val->val = val;
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent);
+
+end:
+       return &field_val->parent;
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_string_create_with_size(
+               const char *val, size_t size)
+{
+       struct lttng_event_field_value_string *field_val = container_of(
+                       create_empty_field_val(
+                               LTTNG_EVENT_FIELD_VALUE_TYPE_STRING,
+                               sizeof(*field_val)),
+                       struct lttng_event_field_value_string, parent);
+
+       if (!field_val) {
+               goto error;
+       }
+
+       assert(val);
+       field_val->val = strndup(val, size);
+       if (!field_val->val) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent);
+
+end:
+       return &field_val->parent;
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_string_create(
+               const char *val)
+{
+       assert(val);
+       return lttng_event_field_value_string_create_with_size(val,
+                       strlen(val));
+}
+
+static
+void destroy_field_val(void *field_val)
+{
+       lttng_event_field_value_destroy(field_val);
+}
+
+LTTNG_HIDDEN
+struct lttng_event_field_value *lttng_event_field_value_array_create(void)
+{
+       struct lttng_event_field_value_array *field_val = container_of(
+                       create_empty_field_val(
+                               LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY,
+                               sizeof(*field_val)),
+                       struct lttng_event_field_value_array, parent);
+
+       if (!field_val) {
+               goto error;
+       }
+
+       lttng_dynamic_pointer_array_init(&field_val->elems, destroy_field_val);
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(&field_val->parent);
+
+end:
+       return &field_val->parent;
+}
+
+LTTNG_HIDDEN
+void lttng_event_field_value_destroy(struct lttng_event_field_value *field_val)
+{
+       if (!field_val) {
+               goto end;
+       }
+
+       switch (field_val->type) {
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+       {
+               struct lttng_event_field_value_enum *enum_field_val =
+                               container_of(field_val,
+                                       struct lttng_event_field_value_enum, parent);
+
+               lttng_dynamic_pointer_array_reset(&enum_field_val->labels);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
+       {
+               struct lttng_event_field_value_string *str_field_val =
+                               container_of(field_val,
+                                       struct lttng_event_field_value_string, parent);
+
+               free(str_field_val->val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
+       {
+               struct lttng_event_field_value_array *array_field_expr =
+                               container_of(field_val,
+                                       struct lttng_event_field_value_array,
+                                       parent);
+
+               lttng_dynamic_pointer_array_reset(&array_field_expr->elems);
+               break;
+       }
+       default:
+               break;
+       }
+
+       free(field_val);
+
+end:
+       return;
+}
+
+LTTNG_HIDDEN
+int lttng_event_field_value_enum_append_label_with_size(
+               struct lttng_event_field_value *field_val,
+               const char *label, size_t size)
+{
+       int ret;
+       char *new_label;
+
+       assert(field_val);
+       assert(label);
+       new_label = strndup(label, size);
+       if (!new_label) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &container_of(field_val,
+                               struct lttng_event_field_value_enum, parent)->labels,
+                       new_label);
+       if (ret == 0) {
+               new_label = NULL;
+       }
+
+end:
+       free(new_label);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_event_field_value_enum_append_label(
+               struct lttng_event_field_value *field_val,
+               const char *label)
+{
+       assert(label);
+       return lttng_event_field_value_enum_append_label_with_size(field_val,
+                       label, strlen(label));
+}
+
+LTTNG_HIDDEN
+int lttng_event_field_value_array_append(
+               struct lttng_event_field_value *array_field_val,
+               struct lttng_event_field_value *field_val)
+{
+       assert(array_field_val);
+       assert(field_val);
+       return lttng_dynamic_pointer_array_add_pointer(
+                       &container_of(array_field_val,
+                               struct lttng_event_field_value_array, parent)->elems,
+                       field_val);
+}
+
+LTTNG_HIDDEN
+int lttng_event_field_value_array_append_unavailable(
+               struct lttng_event_field_value *array_field_val)
+{
+       assert(array_field_val);
+       return lttng_dynamic_pointer_array_add_pointer(
+                       &container_of(array_field_val,
+                               struct lttng_event_field_value_array, parent)->elems,
+                       NULL);
+}
+
+enum lttng_event_field_value_type lttng_event_field_value_get_type(
+               const struct lttng_event_field_value *field_val)
+{
+       enum lttng_event_field_value_type type;
+
+       if (!field_val) {
+               type = LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID;
+               goto end;
+       }
+
+       type = field_val->type;
+
+end:
+       return type;
+}
+
+enum lttng_event_field_value_status
+lttng_event_field_value_unsigned_int_get_value(
+               const struct lttng_event_field_value *field_val, uint64_t *val)
+{
+       enum lttng_event_field_value_status status;
+
+       if (!field_val || !val) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       switch (field_val->type) {
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
+               *val = container_of(field_val,
+                               const struct lttng_event_field_value_uint,
+                               parent)->val;
+               break;
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+               *val = container_of(
+                               container_of(field_val,
+                                       const struct lttng_event_field_value_enum,
+                                       parent),
+                               const struct lttng_event_field_value_enum_uint,
+                               parent)->val;
+               break;
+       default:
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_event_field_value_status
+lttng_event_field_value_signed_int_get_value(
+               const struct lttng_event_field_value *field_val, int64_t *val)
+{
+       enum lttng_event_field_value_status status;
+
+       if (!field_val || !val) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       switch (field_val->type) {
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
+               *val = container_of(field_val,
+                               const struct lttng_event_field_value_int,
+                               parent)->val;
+               break;
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+               *val = container_of(
+                               container_of(field_val,
+                                       const struct lttng_event_field_value_enum,
+                                       parent),
+                               const struct lttng_event_field_value_enum_int,
+                               parent)->val;
+               break;
+       default:
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_event_field_value_status
+lttng_event_field_value_real_get_value(
+               const struct lttng_event_field_value *field_val, double *val)
+{
+       enum lttng_event_field_value_status status;
+
+       if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_REAL ||
+                       !val) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       *val = container_of(field_val,
+                       const struct lttng_event_field_value_real, parent)->val;
+       status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
+
+end:
+       return status;
+}
+
+static
+bool is_enum_field_val(const struct lttng_event_field_value *field_val)
+{
+       return field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM ||
+               field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM;
+}
+
+enum lttng_event_field_value_status
+lttng_event_field_value_enum_get_label_count(
+               const struct lttng_event_field_value *field_val,
+               unsigned int *count)
+{
+       enum lttng_event_field_value_status status;
+
+       if (!field_val || !is_enum_field_val(field_val) || !count) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = (unsigned int) lttng_dynamic_pointer_array_get_count(
+                       &container_of(field_val,
+                               const struct lttng_event_field_value_enum,
+                               parent)->labels);
+       status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
+
+end:
+       return status;
+}
+
+const char *lttng_event_field_value_enum_get_label_at_index(
+               const struct lttng_event_field_value *field_val,
+               unsigned int index)
+{
+       const char *ret;
+       const struct lttng_event_field_value_enum *enum_field_val;
+
+       if (!field_val || !is_enum_field_val(field_val)) {
+               ret = NULL;
+               goto end;
+       }
+
+       enum_field_val = container_of(field_val,
+                       const struct lttng_event_field_value_enum, parent);
+
+       if (index >= lttng_dynamic_pointer_array_get_count(&enum_field_val->labels)) {
+               ret = NULL;
+               goto end;
+       }
+
+       ret = lttng_dynamic_pointer_array_get_pointer(&enum_field_val->labels,
+                       index);
+
+end:
+       return ret;
+}
+
+const char *lttng_event_field_value_string_get_value(
+               const struct lttng_event_field_value *field_val)
+{
+       const char *ret;
+
+       if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_STRING) {
+               ret = NULL;
+               goto end;
+       }
+
+       ret = container_of(field_val,
+                       const struct lttng_event_field_value_string, parent)->val;
+
+end:
+       return ret;
+}
+
+enum lttng_event_field_value_status lttng_event_field_value_array_get_length(
+               const struct lttng_event_field_value *field_val,
+               unsigned int *length)
+{
+       enum lttng_event_field_value_status status;
+
+       if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY ||
+                       !length) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       *length = (unsigned int) lttng_dynamic_pointer_array_get_count(
+                       &container_of(field_val,
+                               const struct lttng_event_field_value_array,
+                               parent)->elems);
+       status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_event_field_value_status
+lttng_event_field_value_array_get_element_at_index(
+               const struct lttng_event_field_value *field_val,
+               unsigned int index,
+               const struct lttng_event_field_value **elem_field_val)
+{
+       enum lttng_event_field_value_status status;
+       const struct lttng_event_field_value_array *array_field_val;
+
+       if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY ||
+                       !elem_field_val) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       array_field_val = container_of(field_val,
+                       const struct lttng_event_field_value_array, parent);
+
+       if (index >= lttng_dynamic_pointer_array_get_count(&array_field_val->elems)) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
+               goto end;
+       }
+
+       *elem_field_val = lttng_dynamic_pointer_array_get_pointer(
+                       &array_field_val->elems, index);
+       if (*elem_field_val) {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
+       } else {
+               status = LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE;
+       }
+
+end:
+       return status;
+}
This page took 0.054654 seconds and 4 git commands to generate.