Add CTF enum type support to tracepoint event
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sat, 9 Jan 2016 19:44:30 +0000 (14:44 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 14 Jan 2016 16:36:55 +0000 (11:36 -0500)
Derived from initial implementation by:
Geneviève Bastien <gbastien+lttng@versatic.net>

Bump UST communication protocol version to 6.1 (minor version increase)
since we're adding enumeration notification command.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
21 files changed:
configure.ac
doc/man/lttng-ust.3
include/lttng/tracepoint.h
include/lttng/ust-abi.h
include/lttng/ust-ctl.h
include/lttng/ust-events.h
include/lttng/ust-tracepoint-event-nowrite.h
include/lttng/ust-tracepoint-event-reset.h
include/lttng/ust-tracepoint-event-write.h
include/lttng/ust-tracepoint-event.h
include/ust-comm.h
liblttng-ust-comm/lttng-ust-comm.c
liblttng-ust-ctl/ustctl.c
liblttng-ust/lttng-events.c
liblttng-ust/ust-core.c
tests/Makefile.am
tests/ctf-types/Makefile.am [new file with mode: 0644]
tests/ctf-types/README [new file with mode: 0644]
tests/ctf-types/ctf-types.c [new file with mode: 0644]
tests/ctf-types/tp.c [new file with mode: 0644]
tests/ctf-types/ust_tests_ctf_types.h [new file with mode: 0644]

index 26bf5a59c153d731fc30b7293d39f2d35cf71983..c92840bcf73785108e799e42abd081c5d0aca8d6 100644 (file)
@@ -399,6 +399,7 @@ AC_CONFIG_FILES([
        python-lttngust/lttngust/__init__.py
        tools/Makefile
        tests/Makefile
        python-lttngust/lttngust/__init__.py
        tools/Makefile
        tests/Makefile
+       tests/ctf-types/Makefile
        tests/hello/Makefile
        tests/hello.cxx/Makefile
        tests/same_line_tracepoint/Makefile
        tests/hello/Makefile
        tests/hello.cxx/Makefile
        tests/same_line_tracepoint/Makefile
index 398498913f104e6456bb87abedf38b7fc7f12e84..0455eea2810e2178dfe7c244eeeb6800d46e6106 100644 (file)
@@ -224,6 +224,17 @@ TRACEPOINT_EVENT(
                 */
                ctf_float(float, floatfield, floatarg)
                ctf_float(double, doublefield, doublearg)
                 */
                ctf_float(float, floatfield, floatarg)
                ctf_float(double, doublefield, doublearg)
+
+               /*
+                * ctf_enum: a field using a previously declared
+                * enumeration args: (provider, enum name, container
+                * type, field name, argument expression). The
+                * enumeration itself and its values must have been
+                * defined previously with the TRACEPOINT_ENUM macro,
+                * described below.
+                */
+               ctf_enum(sample_component, enumeration_name, int,
+                             enumfield, enumarg)
        )
 )
 
        )
 )
 
@@ -231,6 +242,49 @@ There can be an arbitrary number of tracepoint providers within an
 application, but they must each have their own provider name. Duplicate
 provider names are not allowed.
 
 application, but they must each have their own provider name. Duplicate
 provider names are not allowed.
 
+The CTF specification also supports enumerations that can be declared
+inside a tracepoint provider and used as fields in the tracepoint. This
+shows how to specify enumerations and what they can be used for:
+
+The enumeration is a mapping between an integer, or a range of integers, and a
+string. It can be used to have a more compact trace in cases where the possible
+values for a field are limited:
+
+TRACEPOINT_ENUM(
+       /*
+        * The provider name, as described in the TRACEPOINT_EVENT macro.
+        */
+       sample_component,
+
+       /*
+        * The name of this enumeration, that will be used when using this
+        * global type in tracepoint fields.
+        */
+       enumeration_name,
+
+       /*
+        * TP_ENUM_VALUES describe the values of this enumeration and what they
+        * map to.
+        */
+       TP_ENUM_VALUES(
+               /*
+                * Maps an integer with this string value. By default, enumerations
+                * start at 0 and increment 1 for each entry.
+                */
+               ctf_enum_value(string_value)
+
+               /*
+                * Maps the string value to integers in the range 'start' to 'end'
+                * inclusively. If 'start' == 'end', then the string is mapped to
+                * a specific value.
+                * Enumeration ranges may overlap, but the behavior is
+                * implementation-defined, each trace reader will handle overlapping
+                * as it wishes.
+                */
+               ctf_enum_range(start, end, string_value)
+       )
+)
+
 .fi
 
 .SH "ASSIGNING LOGLEVEL TO EVENTS"
 .fi
 
 .SH "ASSIGNING LOGLEVEL TO EVENTS"
index e88db89242750c591909fb56ae912eb6cc670ff3..16348b86106c98e15abe58cf62b8fc11cdc43a4c 100644 (file)
@@ -430,6 +430,50 @@ __tracepoints__ptrs_destroy(void)
 
 /* The following declarations must be outside re-inclusion protection. */
 
 
 /* The following declarations must be outside re-inclusion protection. */
 
+#ifndef TRACEPOINT_ENUM
+
+/*
+ * Tracepoint Enumerations
+ *
+ * The enumeration is a mapping between an integer, or range of integers, and
+ * a string. It can be used to have a more compact trace in cases where the
+ * possible values for a field are limited:
+ *
+ * An example:
+ *
+ * TRACEPOINT_ENUM(someproject_component, enumname,
+ *     TP_ENUM_VALUES(
+ *             ctf_enum_value("even", 0)
+ *             ctf_enum_value("uneven", 1)
+ *             ctf_enum_range("twoto4", 2, 4)
+ *             ctf_enum_value("five", 5)
+ *     )
+ * )
+ *
+ * Where "someproject_component" is the name of the component this enumeration
+ * belongs to and "enumname" identifies this enumeration. Inside the
+ * TP_ENUM_VALUES macro is the actual mapping. Each string value can map
+ * to either a single value with ctf_enum_value or a range of values
+ * with ctf_enum_range.
+ *
+ * Enumeration ranges may overlap, but the behavior is implementation-defined,
+ * each trace reader will handle overlapping as it wishes.
+ *
+ * That enumeration can then be used in a field inside the TP_FIELD macro using
+ * the following line:
+ *
+ * ctf_enum(someproject_component, enumname, enumtype, enumfield, enumval)
+ *
+ * Where "someproject_component" and "enumname" match those in the
+ * TRACEPOINT_ENUM, "enumtype" is a signed or unsigned integer type
+ * backing the enumeration, "enumfield" is the name of the field and
+ * "enumval" is the value.
+ */
+
+#define TRACEPOINT_ENUM(provider, name, values)
+
+#endif /* #ifndef TRACEPOINT_ENUM */
+
 #ifndef TRACEPOINT_EVENT
 
 /*
 #ifndef TRACEPOINT_EVENT
 
 /*
@@ -453,6 +497,9 @@ __tracepoints__ptrs_destroy(void)
  *         * Integer, printed with 0x base 16 * 
  *         ctf_integer_hex(unsigned long, field_d, arg1)
  *
  *         * Integer, printed with 0x base 16 * 
  *         ctf_integer_hex(unsigned long, field_d, arg1)
  *
+ *         * Enumeration *
+ *         ctf_enum(someproject_component, enum_name, int, field_e, arg0)
+ *
  *         * Array Sequence, printed as UTF8-encoded array of bytes * 
  *         ctf_array_text(char, field_b, string, FIXED_LEN)
  *         ctf_sequence_text(char, field_c, string, size_t, strlen)
  *         * Array Sequence, printed as UTF8-encoded array of bytes * 
  *         ctf_array_text(char, field_b, string, FIXED_LEN)
  *         ctf_sequence_text(char, field_c, string, size_t, strlen)
index 232a9b90069c7af844a3e88b16d5128e37aa4a15..6ea64c8708e6fb2b36e3ee6c99274586c97d18e2 100644 (file)
@@ -43,7 +43,7 @@
 
 /* Version for ABI between liblttng-ust, sessiond, consumerd */
 #define LTTNG_UST_ABI_MAJOR_VERSION            6
 
 /* Version for ABI between liblttng-ust, sessiond, consumerd */
 #define LTTNG_UST_ABI_MAJOR_VERSION            6
-#define LTTNG_UST_ABI_MINOR_VERSION            0
+#define LTTNG_UST_ABI_MINOR_VERSION            1
 
 enum lttng_ust_instrumentation {
        LTTNG_UST_TRACEPOINT            = 0,
 
 enum lttng_ust_instrumentation {
        LTTNG_UST_TRACEPOINT            = 0,
index 78e0cf727feb1a91c150c2a5b308bd8d3750c710..7a5f969eecd4ebd0fe50a0715e5d5e273dbbcbaf 100644 (file)
@@ -255,6 +255,7 @@ enum ustctl_socket_type {
 enum ustctl_notify_cmd {
        USTCTL_NOTIFY_CMD_EVENT = 0,
        USTCTL_NOTIFY_CMD_CHANNEL = 1,
 enum ustctl_notify_cmd {
        USTCTL_NOTIFY_CMD_EVENT = 0,
        USTCTL_NOTIFY_CMD_CHANNEL = 1,
+       USTCTL_NOTIFY_CMD_ENUM = 2,
 };
 
 enum ustctl_channel_header {
 };
 
 enum ustctl_channel_header {
@@ -302,9 +303,21 @@ struct ustctl_float_type {
        char padding[USTCTL_UST_FLOAT_TYPE_PADDING];
 } LTTNG_PACKED;
 
        char padding[USTCTL_UST_FLOAT_TYPE_PADDING];
 } LTTNG_PACKED;
 
+#define USTCTL_UST_ENUM_ENTRY_PADDING  32
+struct ustctl_enum_entry {
+       uint64_t start, end;            /* start and end are inclusive */
+       char string[LTTNG_UST_SYM_NAME_LEN];
+       char padding[USTCTL_UST_ENUM_ENTRY_PADDING];
+};
+
 #define USTCTL_UST_BASIC_TYPE_PADDING  296
 union _ustctl_basic_type {
        struct ustctl_integer_type integer;
 #define USTCTL_UST_BASIC_TYPE_PADDING  296
 union _ustctl_basic_type {
        struct ustctl_integer_type integer;
+       struct {
+               char name[LTTNG_UST_SYM_NAME_LEN];
+               struct ustctl_integer_type container_type;
+               uint64_t id;    /* enum ID in sessiond. */
+       } enumeration;
        struct {
                enum ustctl_string_encodings encoding;
        } string;
        struct {
                enum ustctl_string_encodings encoding;
        } string;
@@ -403,6 +416,22 @@ int ustctl_reply_register_event(int sock,
        uint32_t id,                    /* event id (input) */
        int ret_code);                  /* return code. 0 ok, negative error */
 
        uint32_t id,                    /* event id (input) */
        int ret_code);                  /* return code. 0 ok, negative error */
 
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ */
+int ustctl_recv_register_enum(int sock,
+       int *session_objd,
+       char *enum_name,
+       struct ustctl_enum_entry **entries,
+       size_t *nr_entries);
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_reply_register_enum(int sock,
+       uint64_t id,                    /* enum id (input) */
+       int ret_code);
+
 /*
  * Returns 0 on success, negative UST or system error value on error.
  */
 /*
  * Returns 0 on success, negative UST or system error value on error.
  */
index b34c9d1ba696d19615a366e1e98ebb5273d51124..f7cbc1a6dd27c972f6ec195442c7c0bd8913de08 100644 (file)
@@ -176,7 +176,8 @@ struct lttng_float_type {
 union _lttng_basic_type {
        struct lttng_integer_type integer;
        struct {
 union _lttng_basic_type {
        struct lttng_integer_type integer;
        struct {
-               const char *name;
+               const struct lttng_enum_desc *desc;     /* Enumeration mapping */
+               struct lttng_integer_type container_type;
        } enumeration;
        struct {
                enum lttng_string_encodings encoding;
        } enumeration;
        struct {
                enum lttng_string_encodings encoding;
@@ -210,11 +211,10 @@ struct lttng_type {
 };
 
 #define LTTNG_UST_ENUM_TYPE_PADDING    24
 };
 
 #define LTTNG_UST_ENUM_TYPE_PADDING    24
-struct lttng_enum {
+struct lttng_enum_desc {
        const char *name;
        const char *name;
-       struct lttng_type container_type;
        const struct lttng_enum_entry *entries;
        const struct lttng_enum_entry *entries;
-       unsigned int len;
+       unsigned int nr_entries;
        char padding[LTTNG_UST_ENUM_TYPE_PADDING];
 };
 
        char padding[LTTNG_UST_ENUM_TYPE_PADDING];
 };
 
@@ -422,6 +422,14 @@ struct lttng_event {
        int registered;                 /* has reg'd tracepoint probe */
 };
 
        int registered;                 /* has reg'd tracepoint probe */
 };
 
+struct lttng_enum {
+       const struct lttng_enum_desc *desc;
+       struct lttng_session *session;
+       struct cds_list_head node;      /* Enum list in session */
+       struct cds_hlist_node hlist;    /* Session ht of enums */
+       uint64_t id;                    /* Enumeration ID in sessiond */
+};
+
 struct channel;
 struct lttng_ust_shm_handle;
 
 struct channel;
 struct lttng_ust_shm_handle;
 
@@ -506,6 +514,13 @@ struct lttng_ust_event_ht {
        struct cds_hlist_head table[LTTNG_UST_EVENT_HT_SIZE];
 };
 
        struct cds_hlist_head table[LTTNG_UST_EVENT_HT_SIZE];
 };
 
+#define LTTNG_UST_ENUM_HT_BITS         12
+#define LTTNG_UST_ENUM_HT_SIZE         (1U << LTTNG_UST_ENUM_HT_BITS)
+
+struct lttng_ust_enum_ht {
+       struct cds_hlist_head table[LTTNG_UST_ENUM_HT_SIZE];
+};
+
 /*
  * IMPORTANT: this structure is part of the ABI between the probe and
  * UST. Fields need to be only added at the end, never reordered, never
 /*
  * IMPORTANT: this structure is part of the ABI between the probe and
  * UST. Fields need to be only added at the end, never reordered, never
@@ -532,6 +547,10 @@ struct lttng_session {
 
        /* New UST 2.4 */
        int statedump_pending:1;
 
        /* New UST 2.4 */
        int statedump_pending:1;
+
+       /* New UST 2.8 */
+       struct lttng_ust_enum_ht enums_ht;      /* ht of enumerations */
+       struct cds_list_head enums_head;
 };
 
 struct lttng_transport {
 };
 
 struct lttng_transport {
@@ -657,6 +676,8 @@ int lttng_session_active(void);
 typedef int (*t_statedump_func_ptr)(struct lttng_session *session);
 void lttng_handle_pending_statedump(void *owner);
 struct cds_list_head *_lttng_get_sessions(void);
 typedef int (*t_statedump_func_ptr)(struct lttng_session *session);
 void lttng_handle_pending_statedump(void *owner);
 struct cds_list_head *_lttng_get_sessions(void);
+struct lttng_enum *lttng_ust_enum_get(struct lttng_session *session,
+               const char *enum_name);
 
 #ifdef __cplusplus
 }
 
 #ifdef __cplusplus
 }
index e87f31e31cb33011ebd047ac7c7c81151541676c..8cb142b2e7ed629b7c81cdada445cfff4eeaad3d 100644 (file)
@@ -54,3 +54,7 @@
 #undef ctf_string_nowrite
 #define ctf_string_nowrite(_item, _src)                                \
        _ctf_string(_item, _src, 1)
 #undef ctf_string_nowrite
 #define ctf_string_nowrite(_item, _src)                                \
        _ctf_string(_item, _src, 1)
+
+#undef ctf_enum_nowrite
+#define ctf_enum_nowrite(_provider, _name, _type, _item, _src)         \
+       _ctf_enum(_provider, _name, _type, _item, _src, 1)
index f5981f84468656bbea9bc8a5bf3855eb78c7a592..c187061ca67da80a38ec2e6cfb409a09458a2af2 100644 (file)
@@ -28,6 +28,9 @@
 #undef TRACEPOINT_EVENT_INSTANCE
 #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args)
 
 #undef TRACEPOINT_EVENT_INSTANCE
 #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args)
 
+#undef TRACEPOINT_ENUM
+#define TRACEPOINT_ENUM(_provider, _name, _values)
+
 #undef TP_ARGS
 #define TP_ARGS(...)
 
 #undef TP_ARGS
 #define TP_ARGS(...)
 
@@ -61,6 +64,9 @@
 #undef _ctf_string
 #define _ctf_string(_item, _src, _nowrite)
 
 #undef _ctf_string
 #define _ctf_string(_item, _src, _nowrite)
 
+#undef _ctf_enum
+#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite)
+
 /* "write" */
 #undef ctf_integer
 #define ctf_integer(_type, _item, _src)
 /* "write" */
 #undef ctf_integer
 #define ctf_integer(_type, _item, _src)
@@ -92,6 +98,9 @@
 #undef ctf_string
 #define ctf_string(_item, _src)
 
 #undef ctf_string
 #define ctf_string(_item, _src)
 
+#undef ctf_enum
+#define ctf_enum(_provider, _name, _type, _item, _src)
+
 /* "nowrite" */
 #undef ctf_integer_nowrite
 #define ctf_integer_nowrite(_type, _item, _src)
 /* "nowrite" */
 #undef ctf_integer_nowrite
 #define ctf_integer_nowrite(_type, _item, _src)
 
 #undef ctf_string_nowrite
 #define ctf_string_nowrite(_item, _src)
 
 #undef ctf_string_nowrite
 #define ctf_string_nowrite(_item, _src)
+
+#undef ctf_enum_nowrite
+#define ctf_enum_nowrite(_provider, _name, _type, _item, _src)
index 86c6adc6cea208233686ad1bf4f97a5d702ab037..444702fceab6a61f4edc200d2651240c9110f6c1 100644 (file)
@@ -66,3 +66,7 @@
 #undef ctf_string
 #define ctf_string(_item, _src)                                        \
        _ctf_string(_item, _src, 0)
 #undef ctf_string
 #define ctf_string(_item, _src)                                        \
        _ctf_string(_item, _src, 0)
+
+#undef ctf_enum
+#define ctf_enum(_provider, _name, _type, _item, _src)                 \
+       _ctf_enum(_provider, _name, _type, _item, _src, 0)
index d9aa6ce6bdb8f8496b7b7a1dc41facf20ca6a169..aa8b50f86e5a44aa055a72f3e89e46772efe8c10 100644 (file)
@@ -117,6 +117,35 @@ static const char                                                  \
 
 #include TRACEPOINT_INCLUDE
 
 
 #include TRACEPOINT_INCLUDE
 
+/*
+ * Stage 0.9 of tracepoint event generation
+ *
+ * Unfolding the enums
+ */
+#include <lttng/ust-tracepoint-event-reset.h>
+
+/* Enumeration entry (single value) */
+#undef ctf_enum_value
+#define ctf_enum_value(_string, _value)                                        \
+       { _value, _value, _string },
+
+/* Enumeration entry (range) */
+#undef ctf_enum_range
+#define ctf_enum_range(_string, _range_start, _range_end)              \
+       { _range_start, _range_end, _string },
+
+#undef TP_ENUM_VALUES
+#define TP_ENUM_VALUES(...)                                            \
+       __VA_ARGS__
+
+#undef TRACEPOINT_ENUM
+#define TRACEPOINT_ENUM(_provider, _name, _values)                     \
+       const struct lttng_enum_entry __enum_values__##_provider##_##_name[] = { \
+               _values                                                 \
+       };
+
+#include TRACEPOINT_INCLUDE
+
 /*
  * Stage 1 of tracepoint event generation.
  *
 /*
  * Stage 1 of tracepoint event generation.
  *
@@ -200,6 +229,31 @@ static const char                                                  \
          .nowrite = _nowrite,                                  \
        },
 
          .nowrite = _nowrite,                                  \
        },
 
+#undef _ctf_enum
+#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite) \
+       {                                                       \
+               .name = #_item,                                 \
+               .type = {                                       \
+                       .atype = atype_enum,                    \
+                       .u = {                                  \
+                               .basic = {                      \
+                                       .enumeration = {        \
+                                               .desc = &__enum_##_provider##_##_name, \
+                                               .container_type = { \
+                                                       .size = sizeof(_type) * CHAR_BIT, \
+                                                       .alignment = lttng_alignof(_type) * CHAR_BIT, \
+                                                       .signedness = lttng_is_signed_type(_type), \
+                                                       .reverse_byte_order = 0, \
+                                                       .base = 10, \
+                                                       .encoding = lttng_encode_none, \
+                                               },              \
+                                       },                      \
+                                },                             \
+                       },                                      \
+               },                                              \
+               .nowrite = _nowrite,                            \
+       },
+
 #undef TP_FIELDS
 #define TP_FIELDS(...) __VA_ARGS__     /* Only one used in this phase */
 
 #undef TP_FIELDS
 #define TP_FIELDS(...) __VA_ARGS__     /* Only one used in this phase */
 
@@ -209,6 +263,14 @@ static const char                                                  \
                _fields                                                                      \
        };
 
                _fields                                                                      \
        };
 
+#undef TRACEPOINT_ENUM
+#define TRACEPOINT_ENUM(_provider, _name, _values)                                     \
+       static const struct lttng_enum_desc __enum_##_provider##_##_name = {            \
+               .name = #_provider "_" #_name,                                          \
+               .entries = __enum_values__##_provider##_##_name,                        \
+               .nr_entries = _TP_ARRAY_SIZE(__enum_values__##_provider##_##_name),     \
+       };
+
 #include TRACEPOINT_INCLUDE
 
 /*
 #include TRACEPOINT_INCLUDE
 
 /*
@@ -230,7 +292,7 @@ static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args));
 #include TRACEPOINT_INCLUDE
 
 /*
 #include TRACEPOINT_INCLUDE
 
 /*
- * Stage 3 of tracepoint event generation.
+ * Stage 3.0 of tracepoint event generation.
  *
  * Create static inline function that calculates event size.
  */
  *
  * Create static inline function that calculates event size.
  */
@@ -268,6 +330,10 @@ static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args));
 #define _ctf_string(_item, _src, _nowrite)                                    \
        __event_len += __dynamic_len[__dynamic_len_idx++] = strlen(_src) + 1;
 
 #define _ctf_string(_item, _src, _nowrite)                                    \
        __event_len += __dynamic_len[__dynamic_len_idx++] = strlen(_src) + 1;
 
+#undef _ctf_enum
+#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite)              \
+       _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite)
+
 #undef TP_ARGS
 #define TP_ARGS(...) __VA_ARGS__
 
 #undef TP_ARGS
 #define TP_ARGS(...) __VA_ARGS__
 
@@ -410,6 +476,10 @@ size_t __event_get_size__##_provider##___##_name(size_t *__dynamic_len, _TP_ARGS
                __stack_data += sizeof(void *);                                \
        }
 
                __stack_data += sizeof(void *);                                \
        }
 
+#undef _ctf_enum
+#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite)              \
+       _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite)
+
 #undef TP_ARGS
 #define TP_ARGS(...) __VA_ARGS__
 
 #undef TP_ARGS
 #define TP_ARGS(...) __VA_ARGS__
 
@@ -427,8 +497,6 @@ void __event_prepare_filter_stack__##_provider##___##_name(char *__stack_data,\
 
 #include TRACEPOINT_INCLUDE
 
 
 #include TRACEPOINT_INCLUDE
 
-
-
 /*
  * Stage 4 of tracepoint event generation.
  *
 /*
  * Stage 4 of tracepoint event generation.
  *
@@ -460,6 +528,10 @@ void __event_prepare_filter_stack__##_provider##___##_name(char *__stack_data,\
 #undef _ctf_string
 #define _ctf_string(_item, _src, _nowrite)
 
 #undef _ctf_string
 #define _ctf_string(_item, _src, _nowrite)
 
+#undef _ctf_enum
+#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite)              \
+       _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite)
+
 #undef TP_ARGS
 #define TP_ARGS(...) __VA_ARGS__
 
 #undef TP_ARGS
 #define TP_ARGS(...) __VA_ARGS__
 
@@ -544,6 +616,10 @@ size_t __event_get_align__##_provider##___##_name(_TP_ARGS_PROTO(_args))      \
                __chan->ops->event_write(&__ctx, _src,                  \
                        __get_dynamic_len(dest));
 
                __chan->ops->event_write(&__ctx, _src,                  \
                        __get_dynamic_len(dest));
 
+#undef _ctf_enum
+#define _ctf_enum(_provider, _name, _type, _item, _src, _nowrite)      \
+       _ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10, _nowrite)
+
 /* Beware: this get len actually consumes the len value */
 #undef __get_dynamic_len
 #define __get_dynamic_len(field)       __stackvar.__dynamic_len[__dynamic_len_idx++]
 /* Beware: this get len actually consumes the len value */
 #undef __get_dynamic_len
 #define __get_dynamic_len(field)       __stackvar.__dynamic_len[__dynamic_len_idx++]
@@ -726,7 +802,11 @@ const struct lttng_event_desc __event_desc___##_provider##_##_name = {            \
        .nr_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_template), \
        .loglevel = &__ref_loglevel___##_provider##___##_name,                 \
        .signature = __tp_event_signature___##_provider##___##_template,       \
        .nr_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_template), \
        .loglevel = &__ref_loglevel___##_provider##___##_name,                 \
        .signature = __tp_event_signature___##_provider##___##_template,       \
-       .u = { .ext = { .model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name } }, \
+       .u = {                                                                 \
+           .ext = {                                                           \
+                 .model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name, \
+               },                                                             \
+       },                                                                     \
 };
 
 #include TRACEPOINT_INCLUDE
 };
 
 #include TRACEPOINT_INCLUDE
index b9bbb39bbbeeea702d045e818096b5a188960417..efebbb2a73f830eb5f86adb6c247c528ce89ab19 100644 (file)
@@ -31,6 +31,7 @@
 #include <lttng/ust-abi.h>
 #include <lttng/ust-error.h>
 #include <lttng/ust-compiler.h>
 #include <lttng/ust-abi.h>
 #include <lttng/ust-error.h>
 #include <lttng/ust-compiler.h>
+#include <lttng/ust-ctl.h>
 #include <config.h>
 
 /*
 #include <config.h>
 
 /*
@@ -50,6 +51,9 @@
 
 struct lttng_event_field;
 struct lttng_ctx_field;
 
 struct lttng_event_field;
 struct lttng_ctx_field;
+struct lttng_enum_entry;
+struct lttng_integer_type;
+struct lttng_session;
 
 struct ustctl_reg_msg {
        uint32_t magic;
 
 struct ustctl_reg_msg {
        uint32_t magic;
@@ -147,6 +151,22 @@ struct ustcomm_notify_event_reply {
        char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING];
 } LTTNG_PACKED;
 
        char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING];
 } LTTNG_PACKED;
 
+#define USTCOMM_NOTIFY_ENUM_MSG_PADDING                32
+struct ustcomm_notify_enum_msg {
+       uint32_t session_objd;
+       char enum_name[LTTNG_UST_SYM_NAME_LEN];
+       uint32_t entries_len;
+       char padding[USTCOMM_NOTIFY_ENUM_MSG_PADDING];
+       /* followed by enum entries */
+} LTTNG_PACKED;
+
+#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING     32
+struct ustcomm_notify_enum_reply {
+       int32_t ret_code;       /* 0: ok, negative: error code */
+       uint64_t enum_id;
+       char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING];
+} LTTNG_PACKED;
+
 #define USTCOMM_NOTIFY_CHANNEL_MSG_PADDING     32
 struct ustcomm_notify_channel_msg {
        uint32_t session_objd;
 #define USTCOMM_NOTIFY_CHANNEL_MSG_PADDING     32
 struct ustcomm_notify_channel_msg {
        uint32_t session_objd;
@@ -213,6 +233,7 @@ int ustcomm_send_reg_msg(int sock,
  * Returns -EPIPE or -ECONNRESET if other end has hung up.
  */
 int ustcomm_register_event(int sock,
  * Returns -EPIPE or -ECONNRESET if other end has hung up.
  */
 int ustcomm_register_event(int sock,
+       struct lttng_session *session,
        int session_objd,               /* session descriptor */
        int channel_objd,               /* channel descriptor */
        const char *event_name,         /* event name (input) */
        int session_objd,               /* session descriptor */
        int channel_objd,               /* channel descriptor */
        const char *event_name,         /* event name (input) */
@@ -223,6 +244,17 @@ int ustcomm_register_event(int sock,
        const char *model_emf_uri,
        uint32_t *id);                  /* event id (output) */
 
        const char *model_emf_uri,
        uint32_t *id);                  /* event id (output) */
 
+/*
+ * Returns 0 on success, negative error value on error.
+ * Returns -EPIPE or -ECONNRESET if other end has hung up.
+ */
+int ustcomm_register_enum(int sock,
+       int session_objd,               /* session descriptor */
+       const char *enum_name,          /* enum name (input) */
+       size_t nr_entries,              /* entries */
+       const struct lttng_enum_entry *entries,
+       uint64_t *id);                  /* enum id (output) */
+
 /*
  * Returns 0 on success, negative error value on error.
  * Returns -EPIPE or -ECONNRESET if other end has hung up.
 /*
  * Returns 0 on success, negative error value on error.
  * Returns -EPIPE or -ECONNRESET if other end has hung up.
index d213770f7a25f69059810d14d5f12569636cba2b..42c9ddb2eae152d88acdba3e177ab9482b4426e8 100644 (file)
@@ -697,7 +697,22 @@ int serialize_string_encoding(enum ustctl_string_encodings *ue,
 }
 
 static
 }
 
 static
-int serialize_basic_type(enum ustctl_abstract_types *uatype,
+int serialize_integer_type(struct ustctl_integer_type *uit,
+               const struct lttng_integer_type *lit)
+{
+       uit->size = lit->size;
+       uit->signedness = lit->signedness;
+       uit->reverse_byte_order = lit->reverse_byte_order;
+       uit->base = lit->base;
+       if (serialize_string_encoding(&uit->encoding, lit->encoding))
+               return -EINVAL;
+       uit->alignment = lit->alignment;
+       return 0;
+}
+
+static
+int serialize_basic_type(struct lttng_session *session,
+               enum ustctl_abstract_types *uatype,
                enum lttng_abstract_types atype,
                union _ustctl_basic_type *ubt,
                const union _lttng_basic_type *lbt)
                enum lttng_abstract_types atype,
                union _ustctl_basic_type *ubt,
                const union _lttng_basic_type *lbt)
@@ -705,18 +720,8 @@ int serialize_basic_type(enum ustctl_abstract_types *uatype,
        switch (atype) {
        case atype_integer:
        {
        switch (atype) {
        case atype_integer:
        {
-               struct ustctl_integer_type *uit;
-               const struct lttng_integer_type *lit;
-
-               uit = &ubt->integer;
-               lit = &lbt->integer;
-               uit->size = lit->size;
-               uit->signedness = lit->signedness;
-               uit->reverse_byte_order = lit->reverse_byte_order;
-               uit->base = lit->base;
-               if (serialize_string_encoding(&uit->encoding, lit->encoding))
+               if (serialize_integer_type(&ubt->integer, &lbt->integer))
                        return -EINVAL;
                        return -EINVAL;
-               uit->alignment = lit->alignment;
                *uatype = ustctl_atype_integer;
                break;
        }
                *uatype = ustctl_atype_integer;
                break;
        }
@@ -743,6 +748,27 @@ int serialize_basic_type(enum ustctl_abstract_types *uatype,
                break;
        }
        case atype_enum:
                break;
        }
        case atype_enum:
+       {
+               strncpy(ubt->enumeration.name, lbt->enumeration.desc->name,
+                               LTTNG_UST_SYM_NAME_LEN);
+               ubt->enumeration.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+               if (serialize_integer_type(&ubt->enumeration.container_type,
+                               &lbt->enumeration.container_type))
+                       return -EINVAL;
+               if (session) {
+                       const struct lttng_enum *_enum;
+
+                       _enum = lttng_ust_enum_get(session,
+                                       lbt->enumeration.desc->name);
+                       if (!_enum)
+                               return -EINVAL;
+                       ubt->enumeration.id = _enum->id;
+               } else {
+                       ubt->enumeration.id = -1ULL;
+               }
+               *uatype = ustctl_atype_enum;
+               break;
+       }
        case atype_array:
        case atype_sequence:
        default:
        case atype_array:
        case atype_sequence:
        default:
@@ -752,7 +778,8 @@ int serialize_basic_type(enum ustctl_abstract_types *uatype,
 }
 
 static
 }
 
 static
-int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt)
+int serialize_one_type(struct lttng_session *session,
+               struct ustctl_type *ut, const struct lttng_type *lt)
 {
        int ret;
 
 {
        int ret;
 
@@ -760,7 +787,8 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt)
        case atype_integer:
        case atype_float:
        case atype_string:
        case atype_integer:
        case atype_float:
        case atype_string:
-               ret = serialize_basic_type(&ut->atype, lt->atype,
+       case atype_enum:
+               ret = serialize_basic_type(session, &ut->atype, lt->atype,
                        &ut->u.basic, &lt->u.basic);
                if (ret)
                        return ret;
                        &ut->u.basic, &lt->u.basic);
                if (ret)
                        return ret;
@@ -774,7 +802,7 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt)
                ubt = &ut->u.array.elem_type;
                lbt = &lt->u.array.elem_type;
                ut->u.array.length = lt->u.array.length;
                ubt = &ut->u.array.elem_type;
                lbt = &lt->u.array.elem_type;
                ut->u.array.length = lt->u.array.length;
-               ret = serialize_basic_type(&ubt->atype, lbt->atype,
+               ret = serialize_basic_type(session, &ubt->atype, lbt->atype,
                        &ubt->u.basic, &lbt->u.basic);
                if (ret)
                        return -EINVAL;
                        &ubt->u.basic, &lbt->u.basic);
                if (ret)
                        return -EINVAL;
@@ -789,20 +817,19 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt)
 
                ubt = &ut->u.sequence.length_type;
                lbt = &lt->u.sequence.length_type;
 
                ubt = &ut->u.sequence.length_type;
                lbt = &lt->u.sequence.length_type;
-               ret = serialize_basic_type(&ubt->atype, lbt->atype,
+               ret = serialize_basic_type(session, &ubt->atype, lbt->atype,
                        &ubt->u.basic, &lbt->u.basic);
                if (ret)
                        return -EINVAL;
                ubt = &ut->u.sequence.elem_type;
                lbt = &lt->u.sequence.elem_type;
                        &ubt->u.basic, &lbt->u.basic);
                if (ret)
                        return -EINVAL;
                ubt = &ut->u.sequence.elem_type;
                lbt = &lt->u.sequence.elem_type;
-               ret = serialize_basic_type(&ubt->atype, lbt->atype,
+               ret = serialize_basic_type(session, &ubt->atype, lbt->atype,
                        &ubt->u.basic, &lbt->u.basic);
                if (ret)
                        return -EINVAL;
                ut->atype = ustctl_atype_sequence;
                break;
        }
                        &ubt->u.basic, &lbt->u.basic);
                if (ret)
                        return -EINVAL;
                ut->atype = ustctl_atype_sequence;
                break;
        }
-       case atype_enum:
        default:
                return -EINVAL;
        }
        default:
                return -EINVAL;
        }
@@ -810,7 +837,8 @@ int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt)
 }
 
 static
 }
 
 static
-int serialize_fields(size_t *_nr_write_fields,
+int serialize_fields(struct lttng_session *session,
+               size_t *_nr_write_fields,
                struct ustctl_field **ustctl_fields,
                size_t nr_fields,
                const struct lttng_event_field *lttng_fields)
                struct ustctl_field **ustctl_fields,
                size_t nr_fields,
                const struct lttng_event_field *lttng_fields)
@@ -835,7 +863,7 @@ int serialize_fields(size_t *_nr_write_fields,
                        continue;
                strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
                f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
                        continue;
                strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
                f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
-               ret = serialize_one_type(&f->type, &lf->type);
+               ret = serialize_one_type(session, &f->type, &lf->type);
                if (ret)
                        goto error_type;
                nr_write_fields++;
                if (ret)
                        goto error_type;
                nr_write_fields++;
@@ -850,6 +878,34 @@ error_type:
        return ret;
 }
 
        return ret;
 }
 
+static
+int serialize_entries(struct ustctl_enum_entry **_entries,
+               size_t nr_entries,
+               const struct lttng_enum_entry *lttng_entries)
+{
+       struct ustctl_enum_entry *entries;
+       int i;
+
+       /* Serialize the entries */
+       entries = zmalloc(nr_entries * sizeof(*entries));
+       if (!entries)
+               return -ENOMEM;
+       for (i = 0; i < nr_entries; i++) {
+               struct ustctl_enum_entry *uentry;
+               const struct lttng_enum_entry *lentry;
+
+               uentry = &entries[i];
+               lentry = &lttng_entries[i];
+
+               uentry->start = lentry->start;
+               uentry->end = lentry->end;
+               strncpy(uentry->string, lentry->string, LTTNG_UST_SYM_NAME_LEN);
+               uentry->string[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+       }
+       *_entries = entries;
+       return 0;
+}
+
 static
 int serialize_ctx_fields(size_t *_nr_write_fields,
                struct ustctl_field **ustctl_fields,
 static
 int serialize_ctx_fields(size_t *_nr_write_fields,
                struct ustctl_field **ustctl_fields,
@@ -876,7 +932,7 @@ int serialize_ctx_fields(size_t *_nr_write_fields,
                        continue;
                strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
                f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
                        continue;
                strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN);
                f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
-               ret = serialize_one_type(&f->type, &lf->type);
+               ret = serialize_one_type(NULL, &f->type, &lf->type);
                if (ret)
                        goto error_type;
                nr_write_fields++;
                if (ret)
                        goto error_type;
                nr_write_fields++;
@@ -895,6 +951,7 @@ error_type:
  * Returns 0 on success, negative error value on error.
  */
 int ustcomm_register_event(int sock,
  * Returns 0 on success, negative error value on error.
  */
 int ustcomm_register_event(int sock,
+       struct lttng_session *session,
        int session_objd,               /* session descriptor */
        int channel_objd,               /* channel descriptor */
        const char *event_name,         /* event name (input) */
        int session_objd,               /* session descriptor */
        int channel_objd,               /* channel descriptor */
        const char *event_name,         /* event name (input) */
@@ -931,7 +988,7 @@ int ustcomm_register_event(int sock,
 
        /* Calculate fields len, serialize fields. */
        if (nr_fields > 0) {
 
        /* Calculate fields len, serialize fields. */
        if (nr_fields > 0) {
-               ret = serialize_fields(&nr_write_fields, &fields,
+               ret = serialize_fields(session, &nr_write_fields, &fields,
                                nr_fields, lttng_fields);
                if (ret)
                        return ret;
                                nr_fields, lttng_fields);
                if (ret)
                        return ret;
@@ -945,14 +1002,15 @@ int ustcomm_register_event(int sock,
                model_emf_uri_len = 0;
        }
        msg.m.model_emf_uri_len = model_emf_uri_len;
                model_emf_uri_len = 0;
        }
        msg.m.model_emf_uri_len = model_emf_uri_len;
+
        len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg));
        if (len > 0 && len != sizeof(msg)) {
        len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg));
        if (len > 0 && len != sizeof(msg)) {
-               free(fields);
-               return -EIO;
+               ret = -EIO;
+               goto error_fields;
        }
        if (len < 0) {
        }
        if (len < 0) {
-               free(fields);
-               return len;
+               ret = len;
+               goto error_fields;
        }
 
        /* send signature */
        }
 
        /* send signature */
@@ -971,10 +1029,12 @@ int ustcomm_register_event(int sock,
                len = ustcomm_send_unix_sock(sock, fields, fields_len);
                free(fields);
                if (len > 0 && len != fields_len) {
                len = ustcomm_send_unix_sock(sock, fields, fields_len);
                free(fields);
                if (len > 0 && len != fields_len) {
-                       return -EIO;
+                       ret = -EIO;
+                       goto error_fields;
                }
                if (len < 0) {
                }
                if (len < 0) {
-                       return len;
+                       ret = len;
+                       goto error_fields;
                }
        } else {
                free(fields);
                }
        } else {
                free(fields);
@@ -984,10 +1044,14 @@ int ustcomm_register_event(int sock,
                /* send model_emf_uri */
                len = ustcomm_send_unix_sock(sock, model_emf_uri,
                                model_emf_uri_len);
                /* send model_emf_uri */
                len = ustcomm_send_unix_sock(sock, model_emf_uri,
                                model_emf_uri_len);
-               if (len > 0 && len != model_emf_uri_len)
-                       return -EIO;
-               if (len < 0)
-                       return len;
+               if (len > 0 && len != model_emf_uri_len) {
+                       ret = -EIO;
+                       goto error_fields;
+               }
+               if (len < 0) {
+                       ret = len;
+                       goto error_fields;
+               }
        }
 
        /* receive reply */
        }
 
        /* receive reply */
@@ -1021,6 +1085,114 @@ int ustcomm_register_event(int sock,
                        return len;
                }
        }
                        return len;
                }
        }
+
+error_fields:
+       free(fields);
+       return ret;
+}
+
+/*
+ * Returns 0 on success, negative error value on error.
+ * Returns -EPIPE or -ECONNRESET if other end has hung up.
+ */
+int ustcomm_register_enum(int sock,
+       int session_objd,               /* session descriptor */
+       const char *enum_name,          /* enum name (input) */
+       size_t nr_entries,              /* entries */
+       const struct lttng_enum_entry *lttng_entries,
+       uint64_t *id)
+{
+       ssize_t len;
+       struct {
+               struct ustcomm_notify_hdr header;
+               struct ustcomm_notify_enum_msg m;
+       } msg;
+       struct {
+               struct ustcomm_notify_hdr header;
+               struct ustcomm_notify_enum_reply r;
+       } reply;
+       size_t entries_len;
+       struct ustctl_enum_entry *entries = NULL;
+       int ret;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.header.notify_cmd = USTCTL_NOTIFY_CMD_ENUM;
+       msg.m.session_objd = session_objd;
+       strncpy(msg.m.enum_name, enum_name, LTTNG_UST_SYM_NAME_LEN);
+       msg.m.enum_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+
+       /* Calculate entries len, serialize entries. */
+       if (nr_entries > 0) {
+               ret = serialize_entries(&entries,
+                               nr_entries, lttng_entries);
+               if (ret)
+                       return ret;
+       }
+
+       entries_len = sizeof(*entries) * nr_entries;
+       msg.m.entries_len = entries_len;
+
+       len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg));
+       if (len > 0 && len != sizeof(msg)) {
+               ret = -EIO;
+               goto error_entries;
+       }
+       if (len < 0) {
+               ret = len;
+               goto error_entries;
+       }
+
+       /* send entries */
+       if (entries_len > 0) {
+               len = ustcomm_send_unix_sock(sock, entries, entries_len);
+               if (len > 0 && len != entries_len) {
+                       ret = -EIO;
+                       goto error_entries;
+               }
+               if (len < 0) {
+                       ret = len;
+                       goto error_entries;
+               }
+       }
+       free(entries);
+       entries = NULL;
+
+       /* receive reply */
+       len = ustcomm_recv_unix_sock(sock, &reply, sizeof(reply));
+       switch (len) {
+       case 0: /* orderly shutdown */
+               return -EPIPE;
+       case sizeof(reply):
+               if (reply.header.notify_cmd != msg.header.notify_cmd) {
+                       ERR("Unexpected result message command "
+                               "expected: %u vs received: %u\n",
+                               msg.header.notify_cmd, reply.header.notify_cmd);
+                       return -EINVAL;
+               }
+               if (reply.r.ret_code > 0)
+                       return -EINVAL;
+               if (reply.r.ret_code < 0)
+                       return reply.r.ret_code;
+               *id = reply.r.enum_id;
+               DBG("Sent register enum notification for name \"%s\": ret_code %d\n",
+                       enum_name, reply.r.ret_code);
+               return 0;
+       default:
+               if (len < 0) {
+                       /* Transport level error */
+                       if (errno == EPIPE || errno == ECONNRESET)
+                               len = -errno;
+                       return len;
+               } else {
+                       ERR("incorrect message size: %zd\n", len);
+                       return len;
+               }
+       }
+       return ret;
+
+error_entries:
+       free(entries);
+       return ret;
 }
 
 /*
 }
 
 /*
index 6b6f295b38bd81ff4ce3e26ad47f7ea37c351fc0..75b32fe527c8fa9d32af7c9f0be501ddb892045d 100644 (file)
@@ -1759,6 +1759,9 @@ int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd)
        case 1:
                *notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL;
                break;
        case 1:
                *notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL;
                break;
+       case 2:
+               *notify_cmd = USTCTL_NOTIFY_CMD_ENUM;
+               break;
        default:
                return -EINVAL;
        }
        default:
                return -EINVAL;
        }
@@ -1911,6 +1914,90 @@ int ustctl_reply_register_event(int sock,
        return 0;
 }
 
        return 0;
 }
 
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ */
+int ustctl_recv_register_enum(int sock,
+       int *session_objd,
+       char *enum_name,
+       struct ustctl_enum_entry **entries,
+       size_t *nr_entries)
+{
+       ssize_t len;
+       struct ustcomm_notify_enum_msg msg;
+       size_t entries_len;
+       struct ustctl_enum_entry *a_entries = NULL;
+
+       len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg));
+       if (len > 0 && len != sizeof(msg))
+               return -EIO;
+       if (len == 0)
+               return -EPIPE;
+       if (len < 0)
+               return len;
+
+       *session_objd = msg.session_objd;
+       strncpy(enum_name, msg.enum_name, LTTNG_UST_SYM_NAME_LEN);
+       enum_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+       entries_len = msg.entries_len;
+
+       if (entries_len % sizeof(*a_entries) != 0) {
+               return -EINVAL;
+       }
+
+       /* recv entries */
+       if (entries_len) {
+               a_entries = zmalloc(entries_len);
+               if (!a_entries)
+                       return -ENOMEM;
+               len = ustcomm_recv_unix_sock(sock, a_entries, entries_len);
+               if (len > 0 && len != entries_len) {
+                       len = -EIO;
+                       goto entries_error;
+               }
+               if (len == 0) {
+                       len = -EPIPE;
+                       goto entries_error;
+               }
+               if (len < 0) {
+                       goto entries_error;
+               }
+       }
+       *nr_entries = entries_len / sizeof(*a_entries);
+       *entries = a_entries;
+
+       return 0;
+
+entries_error:
+       free(a_entries);
+       return len;
+}
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_reply_register_enum(int sock,
+       uint64_t id,
+       int ret_code)
+{
+       ssize_t len;
+       struct {
+               struct ustcomm_notify_hdr header;
+               struct ustcomm_notify_enum_reply r;
+       } reply;
+
+       memset(&reply, 0, sizeof(reply));
+       reply.header.notify_cmd = USTCTL_NOTIFY_CMD_ENUM;
+       reply.r.ret_code = ret_code;
+       reply.r.enum_id = id;
+       len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply));
+       if (len > 0 && len != sizeof(reply))
+               return -EIO;
+       if (len < 0)
+               return len;
+       return 0;
+}
+
 /*
  * Returns 0 on success, negative UST or system error value on error.
  */
 /*
  * Returns 0 on success, negative UST or system error value on error.
  */
index 25b4962583a833811014cf50558f46ea4a5aa7e3..eb85b50d24e4e09ec128cf0ebd8f407e8f293623 100644 (file)
@@ -72,6 +72,7 @@ struct cds_list_head *_lttng_get_sessions(void)
 }
 
 static void _lttng_event_destroy(struct lttng_event *event);
 }
 
 static void _lttng_event_destroy(struct lttng_event *event);
+static void _lttng_enum_destroy(struct lttng_enum *_enum);
 
 static
 void lttng_session_lazy_sync_enablers(struct lttng_session *session);
 
 static
 void lttng_session_lazy_sync_enablers(struct lttng_session *session);
@@ -139,9 +140,12 @@ struct lttng_session *lttng_session_create(void)
                return NULL;
        CDS_INIT_LIST_HEAD(&session->chan_head);
        CDS_INIT_LIST_HEAD(&session->events_head);
                return NULL;
        CDS_INIT_LIST_HEAD(&session->chan_head);
        CDS_INIT_LIST_HEAD(&session->events_head);
+       CDS_INIT_LIST_HEAD(&session->enums_head);
        CDS_INIT_LIST_HEAD(&session->enablers_head);
        for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++)
                CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]);
        CDS_INIT_LIST_HEAD(&session->enablers_head);
        for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++)
                CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]);
+       for (i = 0; i < LTTNG_UST_ENUM_HT_SIZE; i++)
+               CDS_INIT_HLIST_HEAD(&session->enums_ht.table[i]);
        cds_list_add(&session->node, &sessions);
        return session;
 }
        cds_list_add(&session->node, &sessions);
        return session;
 }
@@ -212,6 +216,7 @@ void lttng_session_destroy(struct lttng_session *session)
 {
        struct lttng_channel *chan, *tmpchan;
        struct lttng_event *event, *tmpevent;
 {
        struct lttng_channel *chan, *tmpchan;
        struct lttng_event *event, *tmpevent;
+       struct lttng_enum *_enum, *tmp_enum;
        struct lttng_enabler *enabler, *tmpenabler;
 
        CMM_ACCESS_ONCE(session->active) = 0;
        struct lttng_enabler *enabler, *tmpenabler;
 
        CMM_ACCESS_ONCE(session->active) = 0;
@@ -225,6 +230,9 @@ void lttng_session_destroy(struct lttng_session *session)
        cds_list_for_each_entry_safe(event, tmpevent,
                        &session->events_head, node)
                _lttng_event_destroy(event);
        cds_list_for_each_entry_safe(event, tmpevent,
                        &session->events_head, node)
                _lttng_event_destroy(event);
+       cds_list_for_each_entry_safe(_enum, tmp_enum,
+                       &session->enums_head, node)
+               _lttng_enum_destroy(_enum);
        cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node)
                _lttng_channel_unmap(chan);
        cds_list_del(&session->node);
        cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node)
                _lttng_channel_unmap(chan);
        cds_list_del(&session->node);
@@ -350,6 +358,101 @@ end:
        return ret;
 }
 
        return ret;
 }
 
+static
+int lttng_enum_create(const struct lttng_enum_desc *desc,
+               struct lttng_session *session)
+{
+       const char *enum_name = desc->name;
+       struct lttng_enum *_enum;
+       struct cds_hlist_head *head;
+       struct cds_hlist_node *node;
+       int ret = 0;
+       size_t name_len = strlen(enum_name);
+       uint32_t hash;
+       int notify_socket;
+
+       hash = jhash(enum_name, name_len, 0);
+       head = &session->enums_ht.table[hash & (LTTNG_UST_ENUM_HT_SIZE - 1)];
+       cds_hlist_for_each_entry(_enum, node, head, hlist) {
+               assert(_enum->desc);
+               if (!strncmp(_enum->desc->name, desc->name,
+                               LTTNG_UST_SYM_NAME_LEN - 1)) {
+                       ret = -EEXIST;
+                       goto exist;
+               }
+       }
+
+       notify_socket = lttng_get_notify_socket(session->owner);
+       if (notify_socket < 0) {
+               ret = notify_socket;
+               goto socket_error;
+       }
+
+       _enum = zmalloc(sizeof(*_enum));
+       if (!_enum) {
+               ret = -ENOMEM;
+               goto cache_error;
+       }
+       _enum->session = session;
+       _enum->desc = desc;
+
+       ret = ustcomm_register_enum(notify_socket,
+               session->objd,
+               enum_name,
+               desc->nr_entries,
+               desc->entries,
+               &_enum->id);
+       if (ret < 0) {
+               DBG("Error (%d) registering enumeration to sessiond", ret);
+               goto sessiond_register_error;
+       }
+       cds_list_add(&_enum->node, &session->enums_head);
+       cds_hlist_add_head(&_enum->hlist, head);
+       return 0;
+
+sessiond_register_error:
+       free(_enum);
+cache_error:
+socket_error:
+exist:
+       return ret;
+}
+
+static
+int lttng_event_create_all_enums(const struct lttng_event_desc *desc,
+               struct lttng_session *session)
+{
+       unsigned int nr_fields, i;
+       const struct lttng_event_field *fields;
+
+       /* For each field, ensure enum is part of the session. */
+       nr_fields = desc->nr_fields;
+       fields = desc->fields;
+       for (i = 0; i < nr_fields; i++) {
+               const struct lttng_type *type = &fields[i].type;
+
+               switch (type->atype) {
+               case atype_enum:
+               {
+                       const struct lttng_enum_desc *enum_desc;
+                       int ret;
+
+                       enum_desc = type->u.basic.enumeration.desc;
+                       ret = lttng_enum_create(enum_desc, session);
+                       if (ret && ret != -EEXIST) {
+                               DBG("Unable to create enum error: (%d)", ret);
+                               return ret;
+                       }
+                       break;
+               }
+               default:
+                       /* TODO: nested types when they become supported. */
+                       continue;
+               }
+       }
+       return 0;
+}
+
 /*
  * Supports event creation while tracing session is active.
  */
 /*
  * Supports event creation while tracing session is active.
  */
@@ -386,6 +489,12 @@ int lttng_event_create(const struct lttng_event_desc *desc,
                goto socket_error;
        }
 
                goto socket_error;
        }
 
+       ret = lttng_event_create_all_enums(desc, session);
+       if (ret < 0) {
+               DBG("Error (%d) adding enum to session", ret);
+               goto create_enum_error;
+       }
+
        /*
         * Check if loglevel match. Refuse to connect event if not.
         */
        /*
         * Check if loglevel match. Refuse to connect event if not.
         */
@@ -414,6 +523,7 @@ int lttng_event_create(const struct lttng_event_desc *desc,
 
        /* Fetch event ID from sessiond */
        ret = ustcomm_register_event(notify_socket,
 
        /* Fetch event ID from sessiond */
        ret = ustcomm_register_event(notify_socket,
+               session,
                session->objd,
                chan->objd,
                event_name,
                session->objd,
                chan->objd,
                event_name,
@@ -437,6 +547,7 @@ int lttng_event_create(const struct lttng_event_desc *desc,
 sessiond_register_error:
        free(event);
 cache_error:
 sessiond_register_error:
        free(event);
 cache_error:
+create_enum_error:
 socket_error:
 exist:
        return ret;
 socket_error:
 exist:
        return ret;
@@ -719,6 +830,13 @@ void _lttng_event_destroy(struct lttng_event *event)
        free(event);
 }
 
        free(event);
 }
 
+static
+void _lttng_enum_destroy(struct lttng_enum *_enum)
+{
+       cds_list_del(&_enum->node);
+       free(_enum);
+}
+
 void lttng_ust_events_exit(void)
 {
        struct lttng_session *session, *tmpsession;
 void lttng_ust_events_exit(void)
 {
        struct lttng_session *session, *tmpsession;
index 60cdbfa91a2c876f5d5ae05db7a6ceae2a065df6..60751dc32a9aa56058e1452f3e9ddec4a395981b 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <lttng/ust-events.h>
 #include <usterr-signal-safe.h>
 #include <stdlib.h>
 #include <lttng/ust-events.h>
 #include <usterr-signal-safe.h>
+#include "jhash.h"
 
 static CDS_LIST_HEAD(lttng_transport_list);
 
 
 static CDS_LIST_HEAD(lttng_transport_list);
 
@@ -56,3 +57,26 @@ void lttng_transport_unregister(struct lttng_transport *transport)
 {
        cds_list_del(&transport->node);
 }
 {
        cds_list_del(&transport->node);
 }
+
+/*
+ * Needed by comm layer.
+ */
+struct lttng_enum *lttng_ust_enum_get(struct lttng_session *session,
+               const char *enum_name)
+{
+       struct lttng_enum *_enum;
+       struct cds_hlist_head *head;
+       struct cds_hlist_node *node;
+       size_t name_len = strlen(enum_name);
+       uint32_t hash;
+
+       hash = jhash(enum_name, name_len, 0);
+       head = &session->enums_ht.table[hash & (LTTNG_UST_ENUM_HT_SIZE - 1)];
+       cds_hlist_for_each_entry(_enum, node, head, hlist) {
+               assert(_enum->desc);
+               if (!strncmp(_enum->desc->name, enum_name,
+                               LTTNG_UST_SYM_NAME_LEN - 1))
+                       return _enum;
+       }
+       return NULL;
+}
index 3d7ceeb9d9cb874f1f8215a4f355c9af16b9dcf3..be300c86e0443c531754fdd6e44358f79993b655 100644 (file)
@@ -1,4 +1,5 @@
-SUBDIRS = utils hello same_line_tracepoint snprintf benchmark ust-elf
+SUBDIRS = utils hello same_line_tracepoint snprintf benchmark ust-elf \
+               ctf-types
 
 if CXX_WORKS
 SUBDIRS += hello.cxx
 
 if CXX_WORKS
 SUBDIRS += hello.cxx
diff --git a/tests/ctf-types/Makefile.am b/tests/ctf-types/Makefile.am
new file mode 100644 (file)
index 0000000..366870e
--- /dev/null
@@ -0,0 +1,13 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -Wsystem-headers
+
+noinst_PROGRAMS = ctf-types
+ctf_types_SOURCES = ctf-types.c tp.c ust_tests_ctf_types.h
+ctf_types_LDADD = $(top_builddir)/liblttng-ust/liblttng-ust.la
+ctf_types_CFLAGS = -Werror=old-style-definition
+
+if LTTNG_UST_BUILD_WITH_LIBDL
+ctf_types_LDADD += -ldl
+endif
+if LTTNG_UST_BUILD_WITH_LIBC_DL
+ctf_types_LDADD += -lc
+endif
diff --git a/tests/ctf-types/README b/tests/ctf-types/README
new file mode 100644 (file)
index 0000000..0198653
--- /dev/null
@@ -0,0 +1,3 @@
+This is a "hello world" application used to verify that an instrumented program
+with tracepoints using type declarations in CTF metadata can be built
+successfully.
diff --git a/tests/ctf-types/ctf-types.c b/tests/ctf-types/ctf-types.c
new file mode 100644 (file)
index 0000000..006976a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014  Geneviève Bastien <gbastien@versatic.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1 of
+ * the License.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <unistd.h>
+
+#define TRACEPOINT_DEFINE
+#include "ust_tests_ctf_types.h"
+
+int main(int argc, char **argv)
+{
+       int i;
+       int delay = 0;
+
+       if (argc == 2)
+               delay = atoi(argv[1]);
+
+       fprintf(stderr, "Hello, World!\n");
+
+       sleep(delay);
+
+       fprintf(stderr, "Tracing... ");
+       for (i = 0; i < 100; i++) {
+               tracepoint(ust_tests_ctf_types, tptest, i, i % 6,
+                       i % 21);
+       }
+
+       for (i = 0; i < 10; i++) {
+               tracepoint(ust_tests_ctf_types, tptest_bis, i, i % 6);
+       }
+       fprintf(stderr, " done.\n");
+       return 0;
+}
diff --git a/tests/ctf-types/tp.c b/tests/ctf-types/tp.c
new file mode 100644 (file)
index 0000000..6a33fca
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * tp.c
+ *
+ * Copyright (c) 2014 Geneviève Bastien <gbastien@versatic.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define TRACEPOINT_CREATE_PROBES
+#include "ust_tests_ctf_types.h"
diff --git a/tests/ctf-types/ust_tests_ctf_types.h b/tests/ctf-types/ust_tests_ctf_types.h
new file mode 100644 (file)
index 0000000..e789cbe
--- /dev/null
@@ -0,0 +1,83 @@
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER ust_tests_ctf_types
+
+#if !defined(_TRACEPOINT_UST_TESTS_CTF_TYPES_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define _TRACEPOINT_UST_TESTS_CTF_TYPES_H
+
+/*
+ * Copyright (C) 2014 Geneviève Bastien <gbastien@versatic.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <lttng/tracepoint.h>
+
+TRACEPOINT_ENUM(ust_tests_ctf_types, testenum,
+       TP_ENUM_VALUES(
+               ctf_enum_value("even", 0)
+               ctf_enum_value("uneven", 1)
+               ctf_enum_range("twoto4", 2, 4)
+               ctf_enum_value("five\"extra\\test", 5)
+       )
+)
+
+TRACEPOINT_ENUM(ust_tests_ctf_types, testenum2,
+       TP_ENUM_VALUES(
+               ctf_enum_value("zero", 0)
+               ctf_enum_value("five", 5)
+               ctf_enum_range("ten_to_twenty", 10, 20)
+       )
+)
+
+/*
+ * Enumeration field is used twice to make sure the type declaration
+ * is entered only once in the metadata file.
+ */
+TRACEPOINT_EVENT(ust_tests_ctf_types, tptest,
+       TP_ARGS(int, anint, int, enumval, int, enumval2),
+       TP_FIELDS(
+               ctf_integer(int, intfield, anint)
+               ctf_enum(ust_tests_ctf_types, testenum, int, enumfield, enumval)
+               ctf_enum(ust_tests_ctf_types, testenum, long long,
+                               enumfield_bis, enumval)
+               ctf_enum(ust_tests_ctf_types, testenum2, unsigned int,
+                               enumfield_third, enumval2)
+       )
+)
+
+/*
+ * Another tracepoint using the types to make sure each type is entered
+ * only once in the metadata file.
+ */
+TRACEPOINT_EVENT(ust_tests_ctf_types, tptest_bis,
+       TP_ARGS(int, anint, int, enumval),
+       TP_FIELDS(
+               ctf_integer(int, intfield, anint)
+               ctf_enum(ust_tests_ctf_types, testenum, unsigned char,
+                       enumfield, enumval)
+       )
+)
+
+#endif /* _TRACEPOINT_UST_TESTS_CTF_TYPES_H */
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./ust_tests_ctf_types.h"
+
+/* This part must be outside ifdef protection */
+#include <lttng/tracepoint-event.h>
This page took 0.045128 seconds and 4 git commands to generate.