Implement Trace Hit Counters
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 17 May 2021 14:27:53 +0000 (10:27 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 12 Jul 2024 15:39:51 +0000 (11:39 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: If1f29dd64538bc5979d3e89aa5cca3be4e41046f

23 files changed:
configure.ac
include/lttng/ust-abi.h
include/lttng/ust-ctl.h
include/lttng/ust-events.h
include/lttng/ust-tracepoint-event.h
src/common/core.c
src/common/counter-clients/percpu-32-modular.c
src/common/counter-clients/percpu-64-modular.c
src/common/counter/counter-types.h
src/common/counter/counter.c
src/common/counter/counter.h
src/common/events.h
src/common/macros.h
src/common/ringbuffer-clients/template.h
src/common/tracer.h
src/common/ustcomm.c
src/common/ustcomm.h
src/lib/lttng-ust-ctl/ustctl.c
src/lib/lttng-ust/event-notifier-notification.c
src/lib/lttng-ust/events.h
src/lib/lttng-ust/lttng-events.c
src/lib/lttng-ust/lttng-ust-abi.c
src/lib/lttng-ust/lttng-ust-comm.c

index 05c343b7aeb7114f1830bd88b23b701ac43af27c..8076531f3b8399830cadd56904655f7a24a476cc 100644 (file)
@@ -25,7 +25,7 @@ m4_define([ust_lib_version], ust_lib_version_current[:]ust_lib_version_revision[
 # Library version information of "liblttng-ust-ctl"
 # Following the numbering scheme proposed by libtool for the library version
 # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
-m4_define([ust_ctl_lib_version_current], [5])
+m4_define([ust_ctl_lib_version_current], [6])
 m4_define([ust_ctl_lib_version_revision], [0])
 m4_define([ust_ctl_lib_version_age], [0])
 m4_define([ust_ctl_lib_version], ust_ctl_lib_version_current[:]ust_ctl_lib_version_revision[:]ust_ctl_lib_version_age)
index 1fb8d8810788e84e41aeef6a69f2d912016be6ba..936d31c7948f454790dec8431ca49c5016672cc6 100644 (file)
@@ -88,23 +88,30 @@ enum lttng_ust_abi_counter_bitness {
        LTTNG_UST_ABI_COUNTER_BITNESS_64 = 1,
 };
 
+enum lttng_ust_abi_counter_dimension_flags {
+       LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW = (1 << 0),
+       LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW = (1 << 1),
+};
+
 struct lttng_ust_abi_counter_dimension {
-       uint64_t size;
+       uint32_t flags;                         /* enum lttng_ust_abi_counter_dimension_flags */
+       uint64_t size;                          /* dimension size */
        uint64_t underflow_index;
        uint64_t overflow_index;
-       uint8_t has_underflow;
-       uint8_t has_overflow;
 } __attribute__((packed));
 
-#define LTTNG_UST_ABI_COUNTER_CONF_PADDING1 67
+enum lttng_ust_abi_counter_conf_flags {
+       LTTNG_UST_ABI_COUNTER_CONF_FLAG_COALESCE_HITS = (1 << 0),
+};
+
 struct lttng_ust_abi_counter_conf {
-       uint32_t arithmetic;    /* enum lttng_ust_abi_counter_arithmetic */
-       uint32_t bitness;       /* enum lttng_ust_abi_counter_bitness */
-       uint32_t number_dimensions;
+       uint32_t len;                           /* Length of fields before var. len. data. */
+       uint32_t flags;                         /* enum lttng_ust_abi_counter_conf_flags */
+       uint32_t arithmetic;                    /* enum lttng_ust_abi_counter_arithmetic */
+       uint32_t bitness;                       /* enum lttng_ust_abi_counter_bitness */
        int64_t global_sum_step;
-       struct lttng_ust_abi_counter_dimension dimensions[LTTNG_UST_ABI_COUNTER_DIMENSION_MAX];
-       uint8_t coalesce_hits;
-       char padding[LTTNG_UST_ABI_COUNTER_CONF_PADDING1];
+       uint32_t number_dimensions;
+       uint32_t elem_len;                      /* array stride (size of lttng_ust_abi_counter_dimension) */
 } __attribute__((packed));
 
 struct lttng_ust_abi_counter_value {
@@ -144,25 +151,56 @@ struct lttng_ust_abi_event_notifier_notification {
        char padding[LTTNG_UST_ABI_EVENT_NOTIFIER_NOTIFICATION_PADDING];
 } __attribute__((packed));
 
-#define LTTNG_UST_ABI_COUNTER_PADDING1         (LTTNG_UST_ABI_SYM_NAME_LEN + 32)
 #define LTTNG_UST_ABI_COUNTER_DATA_MAX_LEN     4096U
 struct lttng_ust_abi_counter {
        uint64_t len;
-       char padding[LTTNG_UST_ABI_COUNTER_PADDING1];
-       char data[];    /* variable sized data */
+       char data[];            /* variable sized data */
 } __attribute__((packed));
 
-#define LTTNG_UST_ABI_COUNTER_GLOBAL_PADDING1  (LTTNG_UST_ABI_SYM_NAME_LEN + 32)
 struct lttng_ust_abi_counter_global {
-       uint64_t len;           /* shm len */
-       char padding[LTTNG_UST_ABI_COUNTER_GLOBAL_PADDING1];
+       uint32_t len;           /* Length of this structure */
+       uint64_t shm_len;       /* shm len */
 } __attribute__((packed));
 
-#define LTTNG_UST_ABI_COUNTER_CPU_PADDING1     (LTTNG_UST_ABI_SYM_NAME_LEN + 32)
 struct lttng_ust_abi_counter_cpu {
-       uint64_t len;           /* shm len */
+       uint32_t len;           /* Length of this structure */
+       uint64_t shm_len;       /* shm len */
        uint32_t cpu_nr;
-       char padding[LTTNG_UST_ABI_COUNTER_CPU_PADDING1];
+} __attribute__((packed));
+
+enum lttng_ust_abi_key_token_type {
+       LTTNG_UST_ABI_KEY_TOKEN_STRING = 0,             /* arg: strtab_offset. */
+       LTTNG_UST_ABI_KEY_TOKEN_EVENT_NAME = 1,         /* no arg. */
+       LTTNG_UST_ABI_KEY_TOKEN_PROVIDER_NAME = 2,      /* no arg. */
+};
+
+#define LTTNG_UST_ABI_KEY_ARG_PADDING1         256
+#define LTTNG_UST_ABI_KEY_TOKEN_STRING_LEN_MAX 256
+struct lttng_ust_abi_key_token {
+       uint32_t type;  /* enum lttng_ust_key_token_type */
+       union {
+               char string[LTTNG_UST_ABI_KEY_TOKEN_STRING_LEN_MAX];
+               char padding[LTTNG_UST_ABI_KEY_ARG_PADDING1];
+       } arg;
+} __attribute__((packed));
+
+#define LTTNG_UST_ABI_NR_KEY_TOKEN 4
+struct lttng_ust_abi_counter_key_dimension {
+       uint32_t nr_key_tokens;
+       struct lttng_ust_abi_key_token key_tokens[LTTNG_UST_ABI_NR_KEY_TOKEN];
+} __attribute__((packed));
+
+#define LTTNG_UST_ABI_COUNTER_DIMENSION_MAX 4
+struct lttng_ust_abi_counter_key {
+       uint32_t nr_dimensions;
+       struct lttng_ust_abi_counter_key_dimension key_dimensions[LTTNG_UST_ABI_COUNTER_DIMENSION_MAX];
+} __attribute__((packed));
+
+#define LTTNG_UST_ABI_COUNTER_EVENT_PADDING1   16
+struct lttng_ust_abi_counter_event {
+       struct lttng_ust_abi_event event;
+       struct lttng_ust_abi_counter_key key;
+       char padding[LTTNG_UST_ABI_COUNTER_EVENT_PADDING1];
 } __attribute__((packed));
 
 enum lttng_ust_abi_field_type {
@@ -268,6 +306,7 @@ enum lttng_ust_abi_object_type {
        LTTNG_UST_ABI_OBJECT_TYPE_COUNTER = 6,
        LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_GLOBAL = 7,
        LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_CPU = 8,
+       LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_EVENT = 9,
 };
 
 #define LTTNG_UST_ABI_OBJECT_DATA_PADDING1     32
@@ -411,6 +450,8 @@ struct lttng_ust_abi_event_exclusion {
        LTTNG_UST_ABI_CMDW(0xD0, struct lttng_ust_abi_counter_global)
 #define LTTNG_UST_ABI_COUNTER_CPU              \
        LTTNG_UST_ABI_CMDW(0xD1, struct lttng_ust_abi_counter_cpu)
+#define LTTNG_UST_ABI_COUNTER_EVENT            \
+       LTTNG_UST_ABI_CMDW(0xD2, struct lttng_ust_abi_counter_event)
 
 #define LTTNG_UST_ABI_ROOT_HANDLE      0
 
index 86aa6ef7c6b9f49bd7f6f719cb4d6596d279f8bc..e244b997c6bd0c9583f6d3d32e3ad7c2dbfe48dd 100644 (file)
@@ -536,13 +536,15 @@ int lttng_ust_ctl_recv_register_event(int sock,
                                         */
        size_t *nr_fields,
        struct lttng_ust_ctl_field **fields,
-       char **model_emf_uri);
+       char **model_emf_uri,
+       uint64_t *user_token);
 
 /*
  * Returns 0 on success, negative error value on error.
  */
 int lttng_ust_ctl_reply_register_event(int sock,
-       uint32_t id,                    /* event id (input) */
+       uint32_t event_id,              /* event id (input) */
+       uint64_t counter_index,         /* counter index (input) */
        int ret_code);                  /* return code. 0 ok, negative error */
 
 /*
@@ -656,6 +658,11 @@ int lttng_ust_ctl_counter_aggregate(struct lttng_ust_ctl_daemon_counter *counter
 int lttng_ust_ctl_counter_clear(struct lttng_ust_ctl_daemon_counter *counter,
                const size_t *dimension_indexes);
 
+int lttng_ust_ctl_counter_create_event(int sock,
+               struct lttng_ust_abi_counter_event *counter_event,
+               struct lttng_ust_abi_object_data *counter_data,
+               struct lttng_ust_abi_object_data **counter_event_data);
+
 void lttng_ust_ctl_sigbus_handle(void *addr);
 
 int lttng_ust_ctl_get_version(uint32_t *major, uint32_t *minor, uint32_t *patchlevel);
index 4088157f956e8fe87e89f0aa80fd89e41336d5d3..36304bc4e9f2022f0767400cf8b080b4414a3e64 100644 (file)
@@ -360,6 +360,7 @@ struct lttng_ust_event_common_private;
 enum lttng_ust_event_type {
        LTTNG_UST_EVENT_TYPE_RECORDER = 0,
        LTTNG_UST_EVENT_TYPE_NOTIFIER = 1,
+       LTTNG_UST_EVENT_TYPE_COUNTER = 2,
 };
 
 /*
@@ -430,6 +431,33 @@ struct lttng_ust_event_recorder {
        /* End of base ABI. Fields below should be used after checking struct_size. */
 };
 
+struct lttng_ust_event_counter_private;
+
+/*
+ * 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
+ * removed.
+ *
+ * struct lttng_ust_event_recorder is the action for recording events
+ * into a ring buffer. It inherits from struct lttng_ust_event_common
+ * by composition to ensure both parent and child structure are
+ * extensible.
+ *
+ * The field @struct_size should be used to determine the size of the
+ * structure. It should be queried before using additional fields added
+ * at the end of the structure.
+ */
+struct lttng_ust_event_counter {
+       uint32_t struct_size;                           /* Size of this structure. */
+
+       struct lttng_ust_event_common *parent;          /* Inheritance by aggregation. */
+       struct lttng_ust_event_counter_private *priv;   /* Private event counter interface */
+
+       struct lttng_ust_channel_counter *chan;
+
+       /* End of base ABI. Fields below should be used after checking struct_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
@@ -507,6 +535,7 @@ struct lttng_ust_channel_buffer_ops {
 
 enum lttng_ust_channel_type {
        LTTNG_UST_CHANNEL_TYPE_BUFFER = 0,
+       LTTNG_UST_CHANNEL_TYPE_COUNTER = 1,
 };
 
 struct lttng_ust_channel_common_private;
@@ -556,6 +585,48 @@ struct lttng_ust_channel_buffer {
        /* End of base ABI. Fields below should be used after checking struct_size. */
 };
 
+struct lttng_ust_channel_counter;
+struct lttng_ust_channel_counter_ops_private;
+
+/*
+ * 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
+ * removed.
+ *
+ * The field @struct_size should be used to determine the size of the
+ * structure. It should be queried before using additional fields added
+ * at the end of the structure.
+ */
+struct lttng_ust_channel_counter_ops {
+       uint32_t struct_size;
+
+       struct lttng_ust_channel_counter_ops_private *priv;     /* Private channel counter ops interface */
+
+       int (*event_counter_add)(struct lttng_ust_event_counter *event_counter, int64_t v);
+
+       /* End of base ABI. Fields below should be used after checking struct_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
+ * removed.
+ *
+ * The field @struct_size should be used to determine the size of the
+ * structure. It should be queried before using additional fields added
+ * at the end of the structure.
+ */
+struct lttng_ust_channel_counter {
+       uint32_t struct_size;                           /* Size of this structure. */
+
+       struct lttng_ust_channel_common *parent;        /* Inheritance by aggregation. */
+       struct lttng_ust_channel_counter_private *priv; /* Private channel counter interface */
+
+       struct lttng_ust_channel_counter_ops *ops;
+
+       /* End of base ABI. Fields below should be used after checking struct_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
@@ -612,6 +683,30 @@ void lttng_ust_probe_unregister(struct lttng_ust_registered_probe *reg_probe);
  */
 void lttng_ust_context_procname_reset(void);
 
+static inline
+struct lttng_ust_channel_common *lttng_ust_get_chan_common_from_event_common(
+               struct lttng_ust_event_common *event)
+{
+       switch (event->type) {
+       case LTTNG_UST_EVENT_TYPE_RECORDER:
+       {
+               struct lttng_ust_event_recorder *event_recorder = (struct lttng_ust_event_recorder *) event->child;
+               struct lttng_ust_channel_buffer *chan_buf = event_recorder->chan;
+
+               return chan_buf->parent;
+       }
+       case LTTNG_UST_EVENT_TYPE_COUNTER:
+       {
+               struct lttng_ust_event_counter *event_counter = (struct lttng_ust_event_counter *) event->child;
+               struct lttng_ust_channel_counter *chan_counter = event_counter->chan;
+
+               return chan_counter->parent;
+       }
+       default:
+               return NULL;
+       }
+}
+
 #ifdef __cplusplus
 }
 #endif
index 5d845ae1e4bb0246cef8cda5495b89e04aa89c17..1a7ea7448641933c993a8fd6cbf92b6f0fb5047e 100644 (file)
@@ -972,6 +972,7 @@ static                                                                            \
 void lttng_ust__event_probe__##_provider##___##_name(LTTNG_UST__TP_ARGS_DATA_PROTO(_args)) \
 {                                                                            \
        struct lttng_ust_event_common *__event = (struct lttng_ust_event_common *) __tp_data; \
+       struct lttng_ust_channel_common *__chan_common;                       \
        size_t __dynamic_len_idx = 0;                                         \
        const size_t __num_fields = LTTNG_UST__TP_ARRAY_SIZE(lttng_ust__event_fields___##_provider##___##_name) - 1; \
        struct lttng_ust_probe_ctx __probe_ctx;                               \
@@ -984,28 +985,19 @@ void lttng_ust__event_probe__##_provider##___##_name(LTTNG_UST__TP_ARGS_DATA_PRO
                                                                              \
        if (0)                                                                \
                (void) __dynamic_len_idx;       /* don't warn if unused */    \
-       switch (__event->type) {                                              \
-       case LTTNG_UST_EVENT_TYPE_RECORDER:                                   \
-       {                                                                     \
-               struct lttng_ust_event_recorder *__event_recorder = (struct lttng_ust_event_recorder *) __event->child; \
-               struct lttng_ust_channel_buffer *__chan = __event_recorder->chan; \
-               struct lttng_ust_channel_common *__chan_common = __chan->parent; \
-                                                                             \
+       if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled)))                 \
+               return;                                                       \
+       if (caa_unlikely(!LTTNG_UST_TP_RCU_LINK_TEST()))                      \
+               return;                                                       \
+       __chan_common = lttng_ust_get_chan_common_from_event_common(__event); \
+       if (__chan_common) {                                                  \
                if (!LTTNG_UST__TP_SESSION_CHECK(session, __chan_common->session)) \
                        return;                                               \
                if (caa_unlikely(!CMM_ACCESS_ONCE(__chan_common->session->active))) \
                        return;                                               \
                if (caa_unlikely(!CMM_ACCESS_ONCE(__chan_common->enabled)))   \
                        return;                                               \
-               break;                                                        \
        }                                                                     \
-       case LTTNG_UST_EVENT_TYPE_NOTIFIER:                                   \
-               break;                                                        \
-       }                                                                     \
-       if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled)))                 \
-               return;                                                       \
-       if (caa_unlikely(!LTTNG_UST_TP_RCU_LINK_TEST()))                      \
-               return;                                                       \
        __probe_ctx.struct_size = sizeof(struct lttng_ust_probe_ctx);         \
        __probe_ctx.ip = LTTNG_UST__TP_IP_PARAM(LTTNG_UST_TP_IP_PARAM);       \
        if (caa_unlikely(CMM_ACCESS_ONCE(__event->eval_filter))) {            \
@@ -1054,6 +1046,13 @@ void lttng_ust__event_probe__##_provider##___##_name(LTTNG_UST__TP_ARGS_DATA_PRO
                                &__notif_ctx);                                \
                break;                                                        \
        }                                                                     \
+       case LTTNG_UST_EVENT_TYPE_COUNTER:                                    \
+       {                                                                     \
+               struct lttng_ust_event_counter *__event_counter = (struct lttng_ust_event_counter *) __event->child; \
+                                                                             \
+               (void) __event_counter->chan->ops->event_counter_add(__event_counter, 1); \
+               break;                                                        \
+       }                                                                     \
        }                                                                     \
 }
 
index 8ea3e34ad78fffb78a0ce8d2fd82b6452f8c164d..a68f2dd05e1b4f3101fb6181ca183223d6a72d14 100644 (file)
@@ -159,6 +159,41 @@ lttng_chan_buf_error:
        return NULL;
 }
 
+struct lttng_ust_channel_counter *lttng_ust_alloc_channel_counter(void)
+{
+       struct lttng_ust_channel_counter *lttng_chan_counter;
+       struct lttng_ust_channel_common *lttng_chan_common;
+       struct lttng_ust_channel_counter_private *lttng_chan_counter_priv;
+
+       lttng_chan_counter = zmalloc(sizeof(struct lttng_ust_channel_counter));
+       if (!lttng_chan_counter)
+               goto lttng_chan_counter_error;
+       lttng_chan_counter->struct_size = sizeof(struct lttng_ust_channel_counter);
+       lttng_chan_common = zmalloc(sizeof(struct lttng_ust_channel_common));
+       if (!lttng_chan_common)
+               goto lttng_chan_common_error;
+       lttng_chan_common->struct_size = sizeof(struct lttng_ust_channel_common);
+       lttng_chan_counter_priv = zmalloc(sizeof(struct lttng_ust_channel_counter_private));
+       if (!lttng_chan_counter_priv)
+               goto lttng_chan_counter_priv_error;
+       lttng_chan_counter->parent = lttng_chan_common;
+       lttng_chan_common->type = LTTNG_UST_CHANNEL_TYPE_COUNTER;
+       lttng_chan_common->child = lttng_chan_counter;
+       lttng_chan_counter->priv = lttng_chan_counter_priv;
+       lttng_chan_common->priv = &lttng_chan_counter_priv->parent;
+       lttng_chan_counter_priv->pub = lttng_chan_counter;
+       lttng_chan_counter_priv->parent.pub = lttng_chan_common;
+
+       return lttng_chan_counter;
+
+lttng_chan_counter_priv_error:
+       free(lttng_chan_common);
+lttng_chan_common_error:
+       free(lttng_chan_counter);
+lttng_chan_counter_error:
+       return NULL;
+}
+
 void lttng_ust_free_channel_common(struct lttng_ust_channel_common *chan)
 {
        switch (chan->type) {
@@ -172,6 +207,16 @@ void lttng_ust_free_channel_common(struct lttng_ust_channel_common *chan)
                free(chan_buf);
                break;
        }
+       case LTTNG_UST_CHANNEL_TYPE_COUNTER:
+       {
+               struct lttng_ust_channel_counter *chan_counter;
+
+               chan_counter = (struct lttng_ust_channel_counter *)chan->child;
+               free(chan_counter->parent);
+               free(chan_counter->priv);
+               free(chan_counter);
+               break;
+       }
        default:
                abort();
        }
index 3635e5f3af30e7ca9619ca99a2d3bc3d25bfa5cc..9d0add6fda5bd5f92fac181c9d2431b34b49b6e3 100644 (file)
@@ -21,7 +21,7 @@ static const struct lib_counter_config client_config = {
        .counter_size = COUNTER_SIZE_32_BIT,
 };
 
-static struct lib_counter *counter_create(size_t nr_dimensions,
+static struct lttng_ust_channel_counter *counter_create(size_t nr_dimensions,
                                          const struct lttng_counter_dimension *dimensions,
                                          int64_t global_sum_step,
                                          int global_counter_fd,
@@ -30,6 +30,8 @@ static struct lib_counter *counter_create(size_t nr_dimensions,
                                          bool is_daemon)
 {
        size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i;
+       struct lttng_ust_channel_counter *lttng_chan_counter;
+       struct lib_counter *counter;
 
        if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX)
                return NULL;
@@ -38,49 +40,75 @@ static struct lib_counter *counter_create(size_t nr_dimensions,
                        return NULL;
                max_nr_elem[i] = dimensions[i].size;
        }
-       return lttng_counter_create(&client_config, nr_dimensions, max_nr_elem,
+       lttng_chan_counter = lttng_ust_alloc_channel_counter();
+       if (!lttng_chan_counter)
+               return NULL;
+       counter = lttng_counter_create(&client_config, nr_dimensions, max_nr_elem,
                                    global_sum_step, global_counter_fd, nr_counter_cpu_fds,
                                    counter_cpu_fds, is_daemon);
+       if (!counter)
+               goto error;
+       lttng_chan_counter->priv->counter = counter;
+       return lttng_chan_counter;
+
+error:
+       lttng_ust_free_channel_common(lttng_chan_counter->parent);
+       return NULL;
+}
+
+static void counter_destroy(struct lttng_ust_channel_counter *counter)
+{
+       lttng_counter_destroy(counter->priv->counter);
+       lttng_ust_free_channel_common(counter->parent);
 }
 
-static void counter_destroy(struct lib_counter *counter)
+static int counter_add(struct lttng_ust_channel_counter *counter,
+                      const size_t *dimension_indexes, int64_t v)
 {
-       lttng_counter_destroy(counter);
+       return lttng_counter_add(&client_config, counter->priv->counter, dimension_indexes, v);
 }
 
-static int counter_add(struct lib_counter *counter, const size_t *dimension_indexes, int64_t v)
+static int event_counter_add(struct lttng_ust_event_counter *event_counter, int64_t v)
 {
-       return lttng_counter_add(&client_config, counter, dimension_indexes, v);
+       struct lttng_ust_channel_counter *counter = event_counter->chan;
+       size_t index = event_counter->priv->counter_index;
+
+       return counter_add(counter, &index, v);
 }
 
-static int counter_read(struct lib_counter *counter, const size_t *dimension_indexes, int cpu,
+static int counter_read(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes, int cpu,
                        int64_t *value, bool *overflow, bool *underflow)
 {
-       return lttng_counter_read(&client_config, counter, dimension_indexes, cpu, value,
+       return lttng_counter_read(&client_config, counter->priv->counter, dimension_indexes, cpu, value,
                                  overflow, underflow);
 }
 
-static int counter_aggregate(struct lib_counter *counter, const size_t *dimension_indexes,
+static int counter_aggregate(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes,
                             int64_t *value, bool *overflow, bool *underflow)
 {
-       return lttng_counter_aggregate(&client_config, counter, dimension_indexes, value,
+       return lttng_counter_aggregate(&client_config, counter->priv->counter, dimension_indexes, value,
                                       overflow, underflow);
 }
 
-static int counter_clear(struct lib_counter *counter, const size_t *dimension_indexes)
+static int counter_clear(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes)
 {
-       return lttng_counter_clear(&client_config, counter, dimension_indexes);
+       return lttng_counter_clear(&client_config, counter->priv->counter, dimension_indexes);
 }
 
 static struct lttng_counter_transport lttng_counter_transport = {
        .name = "counter-per-cpu-32-modular",
        .ops = {
-               .counter_create = counter_create,
-               .counter_destroy = counter_destroy,
-               .counter_add = counter_add,
-               .counter_read = counter_read,
-               .counter_aggregate = counter_aggregate,
-               .counter_clear = counter_clear,
+               .struct_size = sizeof(struct lttng_ust_channel_counter_ops),
+               .priv = LTTNG_UST_COMPOUND_LITERAL(struct lttng_ust_channel_counter_ops_private, {
+                       .pub = &lttng_counter_transport.ops,
+                       .counter_create = counter_create,
+                       .counter_destroy = counter_destroy,
+                       .counter_add = counter_add,
+                       .counter_read = counter_read,
+                       .counter_aggregate = counter_aggregate,
+                       .counter_clear = counter_clear,
+               }),
+               .event_counter_add = event_counter_add,
        },
        .client_config = &client_config,
 };
index 2aee41978c85b8f5c183cb42c840a2bb25f9f79b..98509b3456503d32136c55d919e8786663b67b2b 100644 (file)
@@ -21,7 +21,7 @@ static const struct lib_counter_config client_config = {
        .counter_size = COUNTER_SIZE_64_BIT,
 };
 
-static struct lib_counter *counter_create(size_t nr_dimensions,
+static struct lttng_ust_channel_counter *counter_create(size_t nr_dimensions,
                                          const struct lttng_counter_dimension *dimensions,
                                          int64_t global_sum_step,
                                          int global_counter_fd,
@@ -30,6 +30,8 @@ static struct lib_counter *counter_create(size_t nr_dimensions,
                                          bool is_daemon)
 {
        size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i;
+       struct lttng_ust_channel_counter *lttng_chan_counter;
+       struct lib_counter *counter;
 
        if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX)
                return NULL;
@@ -38,49 +40,75 @@ static struct lib_counter *counter_create(size_t nr_dimensions,
                        return NULL;
                max_nr_elem[i] = dimensions[i].size;
        }
-       return lttng_counter_create(&client_config, nr_dimensions, max_nr_elem,
+       lttng_chan_counter = lttng_ust_alloc_channel_counter();
+       if (!lttng_chan_counter)
+               return NULL;
+       counter = lttng_counter_create(&client_config, nr_dimensions, max_nr_elem,
                                    global_sum_step, global_counter_fd, nr_counter_cpu_fds,
                                    counter_cpu_fds, is_daemon);
+       if (!counter)
+               goto error;
+       lttng_chan_counter->priv->counter = counter;
+       return lttng_chan_counter;
+
+error:
+       lttng_ust_free_channel_common(lttng_chan_counter->parent);
+       return NULL;
+}
+
+static void counter_destroy(struct lttng_ust_channel_counter *counter)
+{
+       lttng_counter_destroy(counter->priv->counter);
+       lttng_ust_free_channel_common(counter->parent);
 }
 
-static void counter_destroy(struct lib_counter *counter)
+static int counter_add(struct lttng_ust_channel_counter *counter,
+                      const size_t *dimension_indexes, int64_t v)
 {
-       lttng_counter_destroy(counter);
+       return lttng_counter_add(&client_config, counter->priv->counter, dimension_indexes, v);
 }
 
-static int counter_add(struct lib_counter *counter, const size_t *dimension_indexes, int64_t v)
+static int event_counter_add(struct lttng_ust_event_counter *event_counter, int64_t v)
 {
-       return lttng_counter_add(&client_config, counter, dimension_indexes, v);
+       struct lttng_ust_channel_counter *counter = event_counter->chan;
+       size_t index = event_counter->priv->counter_index;
+
+       return counter_add(counter, &index, v);
 }
 
-static int counter_read(struct lib_counter *counter, const size_t *dimension_indexes, int cpu,
+static int counter_read(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes, int cpu,
                        int64_t *value, bool *overflow, bool *underflow)
 {
-       return lttng_counter_read(&client_config, counter, dimension_indexes, cpu, value,
+       return lttng_counter_read(&client_config, counter->priv->counter, dimension_indexes, cpu, value,
                                  overflow, underflow);
 }
 
-static int counter_aggregate(struct lib_counter *counter, const size_t *dimension_indexes,
+static int counter_aggregate(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes,
                             int64_t *value, bool *overflow, bool *underflow)
 {
-       return lttng_counter_aggregate(&client_config, counter, dimension_indexes, value,
+       return lttng_counter_aggregate(&client_config, counter->priv->counter, dimension_indexes, value,
                                       overflow, underflow);
 }
 
-static int counter_clear(struct lib_counter *counter, const size_t *dimension_indexes)
+static int counter_clear(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes)
 {
-       return lttng_counter_clear(&client_config, counter, dimension_indexes);
+       return lttng_counter_clear(&client_config, counter->priv->counter, dimension_indexes);
 }
 
 static struct lttng_counter_transport lttng_counter_transport = {
        .name = "counter-per-cpu-64-modular",
        .ops = {
-               .counter_create = counter_create,
-               .counter_destroy = counter_destroy,
-               .counter_add = counter_add,
-               .counter_read = counter_read,
-               .counter_aggregate = counter_aggregate,
-               .counter_clear = counter_clear,
+               .struct_size = sizeof(struct lttng_ust_channel_counter_ops),
+               .priv = LTTNG_UST_COMPOUND_LITERAL(struct lttng_ust_channel_counter_ops_private, {
+                       .pub = &lttng_counter_transport.ops,
+                       .counter_create = counter_create,
+                       .counter_destroy = counter_destroy,
+                       .counter_add = counter_add,
+                       .counter_read = counter_read,
+                       .counter_aggregate = counter_aggregate,
+                       .counter_clear = counter_clear,
+               }),
+               .event_counter_add = event_counter_add,
        },
        .client_config = &client_config,
 };
index 2b71c93bd2f389ae956d4ffb924fd8ca390fa92e..ce0a319a245aad285a361f64c2d460b1265f5404 100644 (file)
@@ -68,6 +68,9 @@ struct lib_counter {
        struct lib_counter_layout global_counters;
        struct lib_counter_layout *percpu_counters;
 
+       size_t expected_shm;
+       size_t received_shm;
+
        bool is_daemon;
        struct lttng_counter_shm_object_table *object_table;
 };
index 4f2ac4c856726f40257f452833a9be9e8a7f6e98..250701fccbcda26ef81e57ab2569f32cdf46a256 100644 (file)
@@ -106,19 +106,24 @@ int lttng_counter_set_global_shm(struct lib_counter *counter, int fd)
 {
        struct lib_counter_config *config = &counter->config;
        struct lib_counter_layout *layout;
+       int ret;
 
        if (!(config->alloc & COUNTER_ALLOC_GLOBAL))
                return -EINVAL;
        layout = &counter->global_counters;
        if (layout->shm_fd >= 0)
                return -EBUSY;
-       return lttng_counter_layout_init(counter, -1, fd);
+       ret = lttng_counter_layout_init(counter, -1, fd);
+       if (!ret)
+               counter->received_shm++;
+       return ret;
 }
 
 int lttng_counter_set_cpu_shm(struct lib_counter *counter, int cpu, int fd)
 {
        struct lib_counter_config *config = &counter->config;
        struct lib_counter_layout *layout;
+       int ret;
 
        if (cpu < 0 || cpu >= get_possible_cpus_array_len())
                return -EINVAL;
@@ -128,7 +133,10 @@ int lttng_counter_set_cpu_shm(struct lib_counter *counter, int cpu, int fd)
        layout = &counter->percpu_counters[cpu];
        if (layout->shm_fd >= 0)
                return -EBUSY;
-       return lttng_counter_layout_init(counter, cpu, fd);
+       ret = lttng_counter_layout_init(counter, cpu, fd);
+       if (!ret)
+               counter->received_shm++;
+       return ret;
 }
 
 static
@@ -252,6 +260,7 @@ struct lib_counter *lttng_counter_create(const struct lib_counter_config *config
                nr_handles++;
        if (config->alloc & COUNTER_ALLOC_PER_CPU)
                nr_handles += nr_cpus;
+       counter->expected_shm = nr_handles;
        /* Allocate table for global and per-cpu counters. */
        counter->object_table = lttng_counter_shm_object_table_create(nr_handles, populate);
        if (!counter->object_table)
@@ -323,6 +332,13 @@ int lttng_counter_get_cpu_shm(struct lib_counter *counter, int cpu, int *fd, siz
        return 0;
 }
 
+bool lttng_counter_ready(struct lib_counter *counter)
+{
+       if (counter->received_shm == counter->expected_shm)
+               return true;
+       return false;
+}
+
 int lttng_counter_read(const struct lib_counter_config *config,
                       struct lib_counter *counter,
                       const size_t *dimension_indexes,
index aa86f158a80db8fba308f7d734cf1cd05e579014..e4822ffaa72d31e34c76a7fd70f285a5d62b2e79 100644 (file)
@@ -39,6 +39,12 @@ int lttng_counter_get_global_shm(struct lib_counter *counter, int *fd, size_t *l
 int lttng_counter_get_cpu_shm(struct lib_counter *counter, int cpu, int *fd, size_t *len)
        __attribute__((visibility("hidden")));
 
+/*
+ * Has counter received all expected shm ?
+ */
+bool lttng_counter_ready(struct lib_counter *counter)
+       __attribute__((visibility("hidden")));
+
 int lttng_counter_read(const struct lib_counter_config *config,
                       struct lib_counter *counter,
                       const size_t *dimension_indexes,
index 308e97a2cdf5c4cff9c974f754f31cdd17fe869a..bc085ffc0128cc995eead1467d9176ab26f8379c 100644 (file)
@@ -65,11 +65,53 @@ enum lttng_enabler_format_type {
        LTTNG_ENABLER_FORMAT_EVENT,
 };
 
+enum lttng_key_token_type {
+       LTTNG_KEY_TOKEN_STRING = 0,
+       LTTNG_KEY_TOKEN_EVENT_NAME = 1,
+       LTTNG_KEY_TOKEN_PROVIDER_NAME = 2,
+};
+
+#define LTTNG_KEY_TOKEN_STRING_LEN_MAX LTTNG_UST_ABI_KEY_TOKEN_STRING_LEN_MAX
+struct lttng_key_token {
+       enum lttng_key_token_type type;
+       union {
+               char string[LTTNG_KEY_TOKEN_STRING_LEN_MAX];
+       } arg;
+};
+
+#define LTTNG_NR_KEY_TOKEN LTTNG_UST_ABI_NR_KEY_TOKEN
+struct lttng_counter_key_dimension {
+       size_t nr_key_tokens;
+       struct lttng_key_token key_tokens[LTTNG_NR_KEY_TOKEN];
+};
+
+#define LTTNG_COUNTER_DIMENSION_MAX LTTNG_UST_ABI_COUNTER_DIMENSION_MAX
+struct lttng_counter_key {
+       size_t nr_dimensions;
+       struct lttng_counter_key_dimension key_dimensions[LTTNG_COUNTER_DIMENSION_MAX];
+};
+
+struct lttng_counter_dimension {
+       uint64_t size;
+       uint64_t underflow_index;
+       uint64_t overflow_index;
+       uint8_t has_underflow;
+       uint8_t has_overflow;
+};
+
+enum lttng_event_enabler_type {
+       LTTNG_EVENT_ENABLER_TYPE_RECORDER,
+       LTTNG_EVENT_ENABLER_TYPE_NOTIFIER,
+       LTTNG_EVENT_ENABLER_TYPE_COUNTER,
+};
+
 /*
  * Enabler field, within whatever object is enabling an event. Target of
  * backward reference.
  */
-struct lttng_enabler {
+struct lttng_event_enabler_common {
+       enum lttng_event_enabler_type enabler_type;
+
        enum lttng_enabler_format_type format_type;
 
        /* head list of struct lttng_ust_filter_bytecode_node */
@@ -79,12 +121,14 @@ struct lttng_enabler {
 
        struct lttng_ust_abi_event event_param;
        unsigned int enabled:1;
+
+       uint64_t user_token;            /* User-provided token */
 };
 
-struct lttng_event_enabler {
-       struct lttng_enabler base;
+struct lttng_event_enabler_session_common {
+       struct lttng_event_enabler_common parent;
+       struct lttng_ust_channel_common *chan;
        struct cds_list_head node;      /* per-session list of enablers */
-       struct lttng_ust_channel_buffer *chan;
        /*
         * Unused, but kept around to make it explicit that the tracer can do
         * it.
@@ -92,13 +136,23 @@ struct lttng_event_enabler {
        struct lttng_ust_ctx *ctx;
 };
 
+struct lttng_event_recorder_enabler {
+       struct lttng_event_enabler_session_common parent;
+       struct lttng_ust_channel_buffer *chan;
+};
+
+struct lttng_event_counter_enabler {
+       struct lttng_event_enabler_session_common parent;
+       struct lttng_ust_channel_counter *chan;
+       struct lttng_counter_key key;
+};
+
 struct lttng_event_notifier_enabler {
-       struct lttng_enabler base;
+       struct lttng_event_enabler_common parent;
        uint64_t error_counter_index;
        struct cds_list_head node;      /* per-app list of event_notifier enablers */
        struct cds_list_head capture_bytecode_head;
        struct lttng_event_notifier_group *group; /* weak ref */
-       uint64_t user_token;            /* User-provided token */
        uint64_t num_captures;
 };
 
@@ -110,7 +164,7 @@ enum lttng_ust_bytecode_type {
 struct lttng_ust_bytecode_node {
        enum lttng_ust_bytecode_type type;
        struct cds_list_head node;
-       struct lttng_enabler *enabler;
+       struct lttng_event_enabler_common *enabler;
        struct  {
                uint32_t len;
                uint32_t reloc_offset;
@@ -141,7 +195,7 @@ struct lttng_ust_bytecode_filter_ctx {
 
 struct lttng_ust_excluder_node {
        struct cds_list_head node;
-       struct lttng_enabler *enabler;
+       struct lttng_event_enabler_common *enabler;
        /*
         * struct lttng_ust_event_exclusion had variable sized array,
         * must be last field.
@@ -182,44 +236,7 @@ struct lttng_ust_field_list {
  */
 struct lttng_enabler_ref {
        struct cds_list_head node;              /* enabler ref list */
-       struct lttng_enabler *ref;              /* backward ref */
-};
-
-#define LTTNG_COUNTER_DIMENSION_MAX    8
-struct lttng_counter_dimension {
-       uint64_t size;
-       uint64_t underflow_index;
-       uint64_t overflow_index;
-       uint8_t has_underflow;
-       uint8_t has_overflow;
-};
-
-struct lttng_counter_ops {
-       struct lib_counter *(*counter_create)(size_t nr_dimensions,
-                       const struct lttng_counter_dimension *dimensions,
-                       int64_t global_sum_step,
-                       int global_counter_fd,
-                       int nr_counter_cpu_fds,
-                       const int *counter_cpu_fds,
-                       bool is_daemon);
-       void (*counter_destroy)(struct lib_counter *counter);
-       int (*counter_add)(struct lib_counter *counter,
-                       const size_t *dimension_indexes, int64_t v);
-       int (*counter_read)(struct lib_counter *counter,
-                       const size_t *dimension_indexes, int cpu,
-                       int64_t *value, bool *overflow, bool *underflow);
-       int (*counter_aggregate)(struct lib_counter *counter,
-                       const size_t *dimension_indexes, int64_t *value,
-                       bool *overflow, bool *underflow);
-       int (*counter_clear)(struct lib_counter *counter, const size_t *dimension_indexes);
-};
-
-struct lttng_counter {
-       int objd;
-       struct lttng_event_notifier_group *event_notifier_group;    /* owner */
-       struct lttng_counter_transport *transport;
-       struct lib_counter *counter;
-       struct lttng_counter_ops *ops;
+       struct lttng_event_enabler_common *ref;         /* backward ref */
 };
 
 #define LTTNG_UST_EVENT_HT_BITS                12
@@ -252,7 +269,7 @@ struct lttng_event_notifier_group {
        struct lttng_ust_event_notifier_ht event_notifiers_ht; /* hashtable of event_notifiers */
        struct lttng_ust_ctx *ctx;              /* contexts for filters. */
 
-       struct lttng_counter *error_counter;
+       struct lttng_ust_channel_counter *error_counter;
        size_t error_counter_len;
 };
 
@@ -266,7 +283,7 @@ struct lttng_transport {
 struct lttng_counter_transport {
        const char *name;
        struct cds_list_head node;
-       struct lttng_counter_ops ops;
+       struct lttng_ust_channel_counter_ops ops;
        const struct lib_counter_config *client_config;
 };
 
@@ -284,16 +301,31 @@ struct lttng_ust_event_common_private {
        struct cds_list_head filter_bytecode_runtime_head;
 };
 
-struct lttng_ust_event_recorder_private {
+struct lttng_ust_event_session_common_private {
        struct lttng_ust_event_common_private parent;
 
-       struct lttng_ust_event_recorder *pub;   /* Public event interface */
-       struct cds_list_head node;              /* Event recorder list */
-       struct cds_hlist_node hlist;            /* Hash table of event recorders */
+       struct cds_hlist_node name_hlist;       /* Hash table of events, indexed by name */
+       struct cds_list_head node;              /* Event list */
        struct lttng_ust_ctx *ctx;
+
+       struct lttng_ust_channel_common *chan;
+};
+
+struct lttng_ust_event_recorder_private {
+       struct lttng_ust_event_session_common_private parent;
+
+       struct lttng_ust_event_recorder *pub;   /* Public event interface */
        unsigned int id;
 };
 
+struct lttng_ust_event_counter_private {
+       struct lttng_ust_event_session_common_private parent;
+
+       struct lttng_ust_event_counter *pub;    /* Public event interface */
+       char key[LTTNG_KEY_TOKEN_STRING_LEN_MAX];
+       uint64_t counter_index;
+};
+
 struct lttng_ust_event_notifier_private {
        struct lttng_ust_event_common_private parent;
 
@@ -328,21 +360,19 @@ struct lttng_ust_session_private {
        int been_active;                        /* Been active ? */
        int objd;                               /* Object associated */
        struct cds_list_head chan_head;         /* Channel list head */
+       struct cds_list_head counters_head;     /* Counter list head */
        struct cds_list_head events_head;       /* list of events */
-       struct cds_list_head node;              /* Session list */
+       struct cds_list_head enablers_head;     /* List of enablers */
+       struct cds_list_head enums_head;
 
-       /* List of enablers */
-       struct cds_list_head enablers_head;
-       struct lttng_ust_event_ht events_ht;    /* ht of events */
+       struct lttng_ust_event_ht events_name_ht; /* ht of events, indexed by name */
+       struct lttng_ust_enum_ht enums_ht;      /* ht of enumerations */
+
+       struct cds_list_head node;              /* Session list */
        void *owner;                            /* object owner */
        unsigned int tstate:1;                  /* Transient enable state */
-
        unsigned int statedump_pending:1;
-
-       struct lttng_ust_enum_ht enums_ht;      /* ht of enumerations */
-       struct cds_list_head enums_head;
        struct lttng_ust_ctx *ctx;              /* contexts for filters. */
-
        unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
        bool uuid_set;                          /* Is uuid set ? */
 };
@@ -386,6 +416,7 @@ struct lttng_ust_channel_common_private {
 
        int objd;                               /* Object associated with channel. */
        unsigned int tstate:1;                  /* Transient enable state */
+       bool coalesce_hits;
 };
 
 struct lttng_ust_channel_buffer_private {
@@ -401,6 +432,45 @@ struct lttng_ust_channel_buffer_private {
        unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
 };
 
+struct lttng_ust_channel_counter_ops_private {
+       struct lttng_ust_channel_counter_ops *pub;      /* Public channel counter ops interface */
+
+       struct lttng_ust_channel_counter *(*counter_create)(size_t nr_dimensions,
+                       const struct lttng_counter_dimension *dimensions,
+                       int64_t global_sum_step,
+                       int global_counter_fd,
+                       int nr_counter_cpu_fds,
+                       const int *counter_cpu_fds,
+                       bool is_daemon);
+       void (*counter_destroy)(struct lttng_ust_channel_counter *counter);
+       int (*counter_add)(struct lttng_ust_channel_counter *counter,
+                       const size_t *dimension_indexes, int64_t v);
+       int (*counter_read)(struct lttng_ust_channel_counter *counter,
+                       const size_t *dimension_indexes, int cpu,
+                       int64_t *value, bool *overflow, bool *underflow);
+       int (*counter_aggregate)(struct lttng_ust_channel_counter *counter,
+                       const size_t *dimension_indexes, int64_t *value,
+                       bool *overflow, bool *underflow);
+       int (*counter_clear)(struct lttng_ust_channel_counter *counter,
+                       const size_t *dimension_indexes);
+};
+
+struct lttng_ust_channel_counter_private {
+       struct lttng_ust_channel_common_private parent;
+
+       struct lttng_ust_channel_counter *pub;          /* Public channel counter interface */
+       struct lib_counter *counter;
+       struct lttng_ust_channel_counter_ops *ops;
+
+       /* Event notifier group owner. */
+       struct lttng_event_notifier_group *event_notifier_group;
+
+       /* Session owner. */
+       struct lttng_session *session;
+       struct cds_list_head node;                      /* Counter list (in session) */
+       size_t free_index;                              /* Next index to allocate */
+};
+
 /*
  * IMPORTANT: this structure is part of the ABI between the consumer
  * daemon and the UST library within traced applications. Changing it
@@ -566,17 +636,10 @@ const struct lttng_ust_type_struct *lttng_ust_get_type_struct(const struct lttng
        })
 
 static inline
-struct lttng_enabler *lttng_event_enabler_as_enabler(
-               struct lttng_event_enabler *event_enabler)
-{
-       return &event_enabler->base;
-}
-
-static inline
-struct lttng_enabler *lttng_event_notifier_enabler_as_enabler(
+struct lttng_event_enabler_common *lttng_event_notifier_enabler_as_enabler(
                struct lttng_event_notifier_enabler *event_notifier_enabler)
 {
-       return &event_notifier_enabler->base;
+       return &event_notifier_enabler->parent;
 }
 
 
index e8965b383cae3b25d0228d0778f79ca3487c6483..add315ea0deba33f248e61e2877bbcb39f420412 100644 (file)
@@ -74,4 +74,7 @@ void *zmalloc(size_t len)
 #define LTTNG_UST_CALLER_IP()          __builtin_return_address(0)
 #endif
 
+#define lttng_ust_offsetofend(type, field)     \
+       (offsetof(type, field) + sizeof(((type *)NULL)->field))
+
 #endif /* _UST_COMMON_MACROS_H */
index 58a8400d08f808b54db74f1d13f41394e6d60fe7..98cc9ef5860d5ff68e7b61f20a3f361317fc4b4f 100644 (file)
@@ -689,7 +689,7 @@ int lttng_event_reserve(struct lttng_ust_ring_buffer_ctx *ctx)
 
        event_id = event_recorder->priv->id;
        client_ctx.chan_ctx = lttng_ust_rcu_dereference(lttng_chan->priv->ctx);
-       client_ctx.event_ctx = lttng_ust_rcu_dereference(event_recorder->priv->ctx);
+       client_ctx.event_ctx = lttng_ust_rcu_dereference(event_recorder->priv->parent.ctx);
        /* Compute internal size of context structures. */
        ctx_get_struct_size(ctx, client_ctx.chan_ctx, &client_ctx.packet_context_len);
        ctx_get_struct_size(ctx, client_ctx.event_ctx, &client_ctx.event_context_len);
index 8e18c9b5874903243c972103dc878d7f16817028..60d74814824dc5fdc36f2468d21861d5a6686237 100644 (file)
@@ -80,6 +80,9 @@ int lttng_context_is_app(const char *name)
 struct lttng_ust_channel_buffer *lttng_ust_alloc_channel_buffer(void)
        __attribute__((visibility("hidden")));
 
+struct lttng_ust_channel_counter *lttng_ust_alloc_channel_counter(void)
+       __attribute__((visibility("hidden")));
+
 void lttng_ust_free_channel_common(struct lttng_ust_channel_common *chan)
        __attribute__((visibility("hidden")));
 
index 47f228b1de907e7b6ac8e829e4074205fdddc086..335156561cae715ef859f9cb200ccd84000b89c0 100644 (file)
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 
 #include <lttng/ust-ctl.h>
 #include "common/ustcomm.h"
@@ -1368,7 +1369,9 @@ int ustcomm_register_event(int sock,
        size_t nr_fields,               /* fields */
        const struct lttng_ust_event_field * const *lttng_fields,
        const char *model_emf_uri,
-       uint32_t *id)                   /* event id (output) */
+       uint64_t user_token,
+       uint32_t *event_id,             /* event id (output) */
+       uint64_t *counter_index)        /* counter index (output) */
 {
        ssize_t len;
        struct {
@@ -1391,6 +1394,7 @@ int ustcomm_register_event(int sock,
        strncpy(msg.m.event_name, event_name, LTTNG_UST_ABI_SYM_NAME_LEN);
        msg.m.event_name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0';
        msg.m.loglevel = loglevel;
+       msg.m.user_token = user_token;
        signature_len = strlen(signature) + 1;
        msg.m.signature_len = signature_len;
 
@@ -1474,9 +1478,12 @@ int ustcomm_register_event(int sock,
                        return -EINVAL;
                if (reply.r.ret_code < 0)
                        return reply.r.ret_code;
-               *id = reply.r.event_id;
-               DBG("Sent register event notification for name \"%s\": ret_code %d, event_id %u\n",
-                       event_name, reply.r.ret_code, reply.r.event_id);
+               if (event_id)
+                       *event_id = reply.r.event_id;
+               if (counter_index)
+                       *counter_index = reply.r.counter_index;
+               DBG("Sent register event notification for name \"%s\": ret_code %d, event_id %u, counter_index %" PRIu64 "\n",
+                       event_name, reply.r.ret_code, reply.r.event_id, reply.r.counter_index);
                return 0;
        default:
                if (len < 0) {
index d1e9af1354c4f1bf897c66d4df92179ff8aaf175..4bdc8a508c23f0031a9f62b10f9440dedce08a76 100644 (file)
@@ -102,6 +102,15 @@ struct ustcomm_ust_msg {
                        /* Length of struct lttng_ust_abi_event_notifier */
                        uint32_t len;
                } event_notifier;
+               /*
+                * For LTTNG_UST_ABI_COUNTER_EVENT, a struct
+                * lttng_ust_counter_event implicitly follows struct
+                * ustcomm_ust_msg.
+                */
+               struct {
+                       /* Length of struct lttng_ust_abi_counter_event */
+                       uint32_t len;
+               } counter_event;
                char padding[USTCOMM_MSG_PADDING2];
        } u;
 } __attribute__((packed));
@@ -135,7 +144,7 @@ struct ustcomm_notify_hdr {
        uint32_t notify_cmd;
 } __attribute__((packed));
 
-#define USTCOMM_NOTIFY_EVENT_MSG_PADDING       32
+#define USTCOMM_NOTIFY_EVENT_MSG_PADDING       24
 struct ustcomm_notify_event_msg {
        uint32_t session_objd;
        uint32_t channel_objd;
@@ -144,14 +153,16 @@ struct ustcomm_notify_event_msg {
        uint32_t signature_len;
        uint32_t fields_len;
        uint32_t model_emf_uri_len;
+       uint64_t user_token;
        char padding[USTCOMM_NOTIFY_EVENT_MSG_PADDING];
        /* followed by signature, fields, and model_emf_uri */
 } __attribute__((packed));
 
-#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING     32
+#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING     24
 struct ustcomm_notify_event_reply {
        int32_t ret_code;       /* 0: ok, negative: error code */
-       uint32_t event_id;
+       uint32_t event_id;      /* for ring buffer channel events */
+       uint64_t counter_index; /* for counter channel events */
        char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING];
 } __attribute__((packed));
 
@@ -164,11 +175,11 @@ struct ustcomm_notify_enum_msg {
        /* followed by enum entries */
 } __attribute__((packed));
 
-#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING     32
+#define USTCOMM_NOTIFY_ENUM_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];
+       char padding[USTCOMM_NOTIFY_ENUM_REPLY_PADDING];
 } __attribute__((packed));
 
 #define USTCOMM_NOTIFY_CHANNEL_MSG_PADDING     32
@@ -292,7 +303,9 @@ int ustcomm_register_event(int sock,
        size_t nr_fields,               /* fields */
        const struct lttng_ust_event_field * const *fields,
        const char *model_emf_uri,
-       uint32_t *id)                   /* event id (output) */
+       uint64_t user_token,
+       uint32_t *id,                   /* event id (output) */
+       uint64_t *counter_index)        /* counter index (output) */
        __attribute__((visibility("hidden")));
 
 /*
index 7b6798802e0b04f6058103afa73ae8df4abf3860..3a2e58f66e57889e6cc2de08e85681c7dd5c4d43 100644 (file)
@@ -81,8 +81,8 @@ struct lttng_ust_ctl_counter_attr {
  * Counter representation within daemon.
  */
 struct lttng_ust_ctl_daemon_counter {
-       struct lib_counter *counter;
-       const struct lttng_counter_ops *ops;
+       struct lttng_ust_channel_counter *counter;
+       const struct lttng_ust_channel_counter_ops *ops;
        struct lttng_ust_ctl_counter_attr *attr;        /* initial attributes */
 };
 
@@ -206,6 +206,7 @@ int lttng_ust_ctl_release_object(int sock, struct lttng_ust_abi_object_data *dat
        case LTTNG_UST_ABI_OBJECT_TYPE_CONTEXT:
        case LTTNG_UST_ABI_OBJECT_TYPE_EVENT_NOTIFIER_GROUP:
        case LTTNG_UST_ABI_OBJECT_TYPE_EVENT_NOTIFIER:
+       case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_EVENT:
                break;
        case LTTNG_UST_ABI_OBJECT_TYPE_COUNTER:
                free(data->u.counter.data);
@@ -2565,7 +2566,8 @@ int lttng_ust_ctl_recv_register_event(int sock,
        char **signature,
        size_t *nr_fields,
        struct lttng_ust_ctl_field **fields,
-       char **model_emf_uri)
+       char **model_emf_uri,
+       uint64_t *user_token)
 {
        ssize_t len;
        struct ustcomm_notify_event_msg msg;
@@ -2588,6 +2590,7 @@ int lttng_ust_ctl_recv_register_event(int sock,
        *loglevel = msg.loglevel;
        signature_len = msg.signature_len;
        fields_len = msg.fields_len;
+       *user_token = msg.user_token;
 
        if (fields_len % sizeof(*a_fields) != 0) {
                return -EINVAL;
@@ -2679,7 +2682,8 @@ signature_error:
  * Returns 0 on success, negative error value on error.
  */
 int lttng_ust_ctl_reply_register_event(int sock,
-       uint32_t id,
+       uint32_t event_id,
+       uint64_t counter_index,
        int ret_code)
 {
        ssize_t len;
@@ -2691,7 +2695,8 @@ int lttng_ust_ctl_reply_register_event(int sock,
        memset(&reply, 0, sizeof(reply));
        reply.header.notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_EVENT;
        reply.r.ret_code = ret_code;
-       reply.r.event_id = id;
+       reply.r.event_id = event_id;
+       reply.r.counter_index = counter_index;
        len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply));
        if (len > 0 && len != sizeof(reply))
                return -EIO;
@@ -2994,7 +2999,7 @@ struct lttng_ust_ctl_daemon_counter *
                ust_dim[i].has_underflow = dimensions[i].has_underflow;
                ust_dim[i].has_overflow = dimensions[i].has_overflow;
        }
-       counter->counter = transport->ops.counter_create(nr_dimensions,
+       counter->counter = transport->ops.priv->counter_create(nr_dimensions,
                ust_dim, global_sum_step, global_counter_fd,
                nr_counter_cpu_fds, counter_cpu_fds, true);
        if (!counter->counter)
@@ -3012,65 +3017,72 @@ free_counter:
 int lttng_ust_ctl_create_counter_data(struct lttng_ust_ctl_daemon_counter *counter,
                struct lttng_ust_abi_object_data **_counter_data)
 {
+       struct lttng_ust_abi_counter_conf *counter_conf = NULL;
+       struct lttng_ust_abi_counter_dimension *dimension;
+       uint32_t conf_len = sizeof(struct lttng_ust_abi_counter_conf) +
+                               sizeof(struct lttng_ust_abi_counter_dimension);
        struct lttng_ust_abi_object_data *counter_data;
-       struct lttng_ust_abi_counter_conf counter_conf = {0};
-       size_t i;
        int ret;
 
+       if (counter->attr->nr_dimensions != 1) {
+               ret = -EINVAL;
+               goto error;
+       }
+       counter_conf = zmalloc(conf_len);
+       if (!counter_conf) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       counter_conf->len = sizeof(struct lttng_ust_abi_counter_conf);
+       counter_conf->flags |= counter->attr->coalesce_hits ? LTTNG_UST_ABI_COUNTER_CONF_FLAG_COALESCE_HITS : 0;
        switch (counter->attr->arithmetic) {
        case LTTNG_UST_CTL_COUNTER_ARITHMETIC_MODULAR:
-               counter_conf.arithmetic = LTTNG_UST_ABI_COUNTER_ARITHMETIC_MODULAR;
+               counter_conf->arithmetic = LTTNG_UST_ABI_COUNTER_ARITHMETIC_MODULAR;
                break;
        case LTTNG_UST_CTL_COUNTER_ARITHMETIC_SATURATION:
-               counter_conf.arithmetic = LTTNG_UST_ABI_COUNTER_ARITHMETIC_SATURATION;
+               counter_conf->arithmetic = LTTNG_UST_ABI_COUNTER_ARITHMETIC_SATURATION;
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto error;
        }
        switch (counter->attr->bitness) {
        case LTTNG_UST_CTL_COUNTER_BITNESS_32:
-               counter_conf.bitness = LTTNG_UST_ABI_COUNTER_BITNESS_32;
+               counter_conf->bitness = LTTNG_UST_ABI_COUNTER_BITNESS_32;
                break;
        case LTTNG_UST_CTL_COUNTER_BITNESS_64:
-               counter_conf.bitness = LTTNG_UST_ABI_COUNTER_BITNESS_64;
+               counter_conf->bitness = LTTNG_UST_ABI_COUNTER_BITNESS_64;
                break;
        default:
                return -EINVAL;
        }
-       counter_conf.number_dimensions = counter->attr->nr_dimensions;
-       counter_conf.global_sum_step = counter->attr->global_sum_step;
-       counter_conf.coalesce_hits = counter->attr->coalesce_hits;
-       for (i = 0; i < counter->attr->nr_dimensions; i++) {
-               counter_conf.dimensions[i].size = counter->attr->dimensions[i].size;
-               counter_conf.dimensions[i].underflow_index = counter->attr->dimensions[i].underflow_index;
-               counter_conf.dimensions[i].overflow_index = counter->attr->dimensions[i].overflow_index;
-               counter_conf.dimensions[i].has_underflow = counter->attr->dimensions[i].has_underflow;
-               counter_conf.dimensions[i].has_overflow = counter->attr->dimensions[i].has_overflow;
-       }
+       counter_conf->global_sum_step = counter->attr->global_sum_step;
+
+       counter_conf->number_dimensions = 1;
+       counter_conf->elem_len = sizeof(struct lttng_ust_abi_counter_dimension);
+
+       dimension = (struct lttng_ust_abi_counter_dimension *)((char *)counter_conf + sizeof(struct lttng_ust_abi_counter_conf));
+       dimension->flags |= counter->attr->dimensions[0].has_underflow ? LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW : 0;
+       dimension->flags |= counter->attr->dimensions[0].has_overflow ? LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW : 0;
+       dimension->size = counter->attr->dimensions[0].size;
+       dimension->underflow_index = counter->attr->dimensions[0].underflow_index;
+       dimension->overflow_index = counter->attr->dimensions[0].overflow_index;
 
        counter_data = zmalloc(sizeof(*counter_data));
        if (!counter_data) {
                ret = -ENOMEM;
-               goto error_alloc;
+               goto error;
        }
        counter_data->type = LTTNG_UST_ABI_OBJECT_TYPE_COUNTER;
        counter_data->handle = -1;
-
-       counter_data->size = sizeof(counter_conf);
-       counter_data->u.counter.data = zmalloc(sizeof(counter_conf));
-       if (!counter_data->u.counter.data) {
-               ret = -ENOMEM;
-               goto error_alloc_data;
-       }
-
-       memcpy(counter_data->u.counter.data, &counter_conf, sizeof(counter_conf));
+       counter_data->size = conf_len;
+       counter_data->u.counter.data = counter_conf;
        *_counter_data = counter_data;
 
        return 0;
 
-error_alloc_data:
-       free(counter_data);
-error_alloc:
+error:
+       free(counter_conf);
        return ret;
 }
 
@@ -3081,7 +3093,7 @@ int lttng_ust_ctl_create_counter_global_data(struct lttng_ust_ctl_daemon_counter
        int ret, fd;
        size_t len;
 
-       if (lttng_counter_get_global_shm(counter->counter, &fd, &len))
+       if (lttng_counter_get_global_shm(counter->counter->priv->counter, &fd, &len))
                return -EINVAL;
        counter_global_data = zmalloc(sizeof(*counter_global_data));
        if (!counter_global_data) {
@@ -3106,7 +3118,7 @@ int lttng_ust_ctl_create_counter_cpu_data(struct lttng_ust_ctl_daemon_counter *c
        int ret, fd;
        size_t len;
 
-       if (lttng_counter_get_cpu_shm(counter->counter, cpu, &fd, &len))
+       if (lttng_counter_get_cpu_shm(counter->counter->priv->counter, cpu, &fd, &len))
                return -EINVAL;
        counter_cpu_data = zmalloc(sizeof(*counter_cpu_data));
        if (!counter_cpu_data) {
@@ -3127,7 +3139,7 @@ error_alloc:
 
 void lttng_ust_ctl_destroy_counter(struct lttng_ust_ctl_daemon_counter *counter)
 {
-       counter->ops->counter_destroy(counter->counter);
+       counter->ops->priv->counter_destroy(counter->counter);
        free(counter->attr);
        free(counter);
 }
@@ -3202,7 +3214,8 @@ int lttng_ust_ctl_send_counter_global_data_to_ust(int sock,
        memset(&lum, 0, sizeof(lum));
        lum.handle = counter_data->handle;      /* parent handle */
        lum.cmd = LTTNG_UST_ABI_COUNTER_GLOBAL;
-       lum.u.counter_global.len = size;
+       lum.u.counter_global.len = sizeof(struct lttng_ust_abi_counter_global);
+       lum.u.counter_global.shm_len = size;
        ret = ustcomm_send_app_cmd(sock, &lum, &lur);
        if (ret)
                return ret;
@@ -3248,7 +3261,8 @@ int lttng_ust_ctl_send_counter_cpu_data_to_ust(int sock,
        memset(&lum, 0, sizeof(lum));
        lum.handle = counter_data->handle;      /* parent handle */
        lum.cmd = LTTNG_UST_ABI_COUNTER_CPU;
-       lum.u.counter_cpu.len = size;
+       lum.u.counter_cpu.len = sizeof(struct lttng_ust_abi_counter_cpu);
+       lum.u.counter_cpu.shm_len = size;
        lum.u.counter_cpu.cpu_nr = counter_cpu_data->u.counter_cpu.cpu_nr;
        ret = ustcomm_send_app_cmd(sock, &lum, &lur);
        if (ret)
@@ -3275,7 +3289,7 @@ int lttng_ust_ctl_counter_read(struct lttng_ust_ctl_daemon_counter *counter,
                int cpu, int64_t *value,
                bool *overflow, bool *underflow)
 {
-       return counter->ops->counter_read(counter->counter, dimension_indexes, cpu,
+       return counter->ops->priv->counter_read(counter->counter, dimension_indexes, cpu,
                        value, overflow, underflow);
 }
 
@@ -3284,14 +3298,69 @@ int lttng_ust_ctl_counter_aggregate(struct lttng_ust_ctl_daemon_counter *counter
                int64_t *value,
                bool *overflow, bool *underflow)
 {
-       return counter->ops->counter_aggregate(counter->counter, dimension_indexes,
+       return counter->ops->priv->counter_aggregate(counter->counter, dimension_indexes,
                        value, overflow, underflow);
 }
 
 int lttng_ust_ctl_counter_clear(struct lttng_ust_ctl_daemon_counter *counter,
                const size_t *dimension_indexes)
 {
-       return counter->ops->counter_clear(counter->counter, dimension_indexes);
+       return counter->ops->priv->counter_clear(counter->counter, dimension_indexes);
+}
+
+/*
+ * Protocol for LTTNG_UST_COUNTER_EVENT command:
+ *
+ * - send:     struct ustcomm_ust_msg
+ * - receive:  struct ustcomm_ust_reply
+ * - send:     struct lttng_ust_counter_event
+ * - receive:  struct ustcomm_ust_reply (actual command return code)
+ */
+int lttng_ust_ctl_counter_create_event(int sock,
+               struct lttng_ust_abi_counter_event *counter_event,
+               struct lttng_ust_abi_object_data *counter_data,
+               struct lttng_ust_abi_object_data **_counter_event_data)
+{
+       struct ustcomm_ust_msg lum;
+       struct ustcomm_ust_reply lur;
+       struct lttng_ust_abi_object_data *counter_event_data;
+       ssize_t len;
+       int ret;
+
+       if (!counter_data || !_counter_event_data)
+               return -EINVAL;
+
+       counter_event_data = zmalloc(sizeof(*counter_event_data));
+       if (!counter_event_data)
+               return -ENOMEM;
+       counter_event_data->type = LTTNG_UST_ABI_OBJECT_TYPE_COUNTER_EVENT;
+       memset(&lum, 0, sizeof(lum));
+       lum.handle = counter_data->handle;
+       lum.cmd = LTTNG_UST_ABI_COUNTER_EVENT;
+       lum.u.counter_event.len = sizeof(*counter_event);
+       ret = ustcomm_send_app_cmd(sock, &lum, &lur);
+       if (ret) {
+               free(counter_event_data);
+               return ret;
+       }
+       /* Send struct lttng_ust_counter_event */
+       len = ustcomm_send_unix_sock(sock, counter_event, sizeof(*counter_event));
+       if (len != sizeof(*counter_event)) {
+               free(counter_event_data);
+               if (len < 0)
+                       return len;
+               else
+                       return -EIO;
+       }
+       ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
+       if (ret) {
+               free(counter_event_data);
+               return ret;
+       }
+       counter_event_data->handle = lur.ret_val;
+       DBG("received counter event handle %u", counter_event_data->handle);
+       *_counter_event_data = counter_event_data;
+       return 0;
 }
 
 int lttng_ust_ctl_get_version(uint32_t *major, uint32_t *minor,
index 6cb9384823c3751b5dead449b2a8fb0337bbf5ba..9b52e0d96c8f793e6ec6b0eb4488766bed627a35 100644 (file)
@@ -318,7 +318,7 @@ static void record_error(const struct lttng_ust_event_notifier *event_notifier)
 {
        struct lttng_event_notifier_group *event_notifier_group =
                        event_notifier->priv->group;
-       struct lttng_counter *error_counter;
+       struct lttng_ust_channel_counter *error_counter;
        size_t dimension_index[1];
        int ret;
 
@@ -336,8 +336,8 @@ static void record_error(const struct lttng_ust_event_notifier *event_notifier)
                return;
 
        dimension_index[0] = event_notifier->priv->error_counter_index;
-       ret = event_notifier_group->error_counter->ops->counter_add(
-                       error_counter->counter, dimension_index, 1);
+       ret = event_notifier_group->error_counter->ops->priv->counter_add(
+                       error_counter, dimension_index, 1);
        if (ret)
                WARN_ON_ONCE(1);
 }
index cfdbd2e0c7913e6d64ce9aaa9cdda7fd3d0dddbf..093d8d09b25479aef129d13898faf3650d3de767 100644 (file)
 #include "common/events.h"
 
 /*
- * Allocate and initialize a `struct lttng_event_enabler` object.
+ * Allocate and initialize a `struct lttng_event_recorder_enabler` object.
  *
- * On success, returns a `struct lttng_event_enabler`,
+ * On success, returns a `struct lttng_event_recorder_enabler`,
  * On memory error, returns NULL.
  */
-struct lttng_event_enabler *lttng_event_enabler_create(
+struct lttng_event_recorder_enabler *lttng_event_recorder_enabler_create(
                enum lttng_enabler_format_type format_type,
-               struct lttng_ust_abi_event *event_param,
+               const struct lttng_ust_abi_event *event_param,
                struct lttng_ust_channel_buffer *chan)
        __attribute__((visibility("hidden")));
 
 /*
- * Destroy a `struct lttng_event_enabler` object.
+ * Allocate and initialize a `struct lttng_event_counter_enabler` object.
+ *
+ * On success, returns a `struct lttng_event_counter_enabler`,
+ * On memory error, returns NULL.
+ */
+struct lttng_event_counter_enabler *lttng_event_counter_enabler_create(
+               enum lttng_enabler_format_type format_type,
+               const struct lttng_ust_abi_event *event_param,
+               const struct lttng_ust_abi_counter_key *key,
+               struct lttng_ust_channel_counter *chan)
+       __attribute__((visibility("hidden")));
+
+/*
+ * Destroy a `struct lttng_event_enabler_common` object.
  */
-void lttng_event_enabler_destroy(struct lttng_event_enabler *enabler)
+void lttng_event_enabler_destroy(struct lttng_event_enabler_common *event_enabler)
        __attribute__((visibility("hidden")));
 
 /*
  * Enable a `struct lttng_event_enabler` object and all events related to this
  * enabler.
  */
-int lttng_event_enabler_enable(struct lttng_event_enabler *enabler)
+int lttng_event_enabler_enable(struct lttng_event_enabler_session_common *enabler)
        __attribute__((visibility("hidden")));
 
 /*
  * Disable a `struct lttng_event_enabler` object and all events related to this
  * enabler.
  */
-int lttng_event_enabler_disable(struct lttng_event_enabler *enabler)
+int lttng_event_enabler_disable(struct lttng_event_enabler_session_common *enabler)
        __attribute__((visibility("hidden")));
 
 /*
@@ -46,7 +59,7 @@ int lttng_event_enabler_disable(struct lttng_event_enabler *enabler)
  * events related to this enabler.
  */
 int lttng_event_enabler_attach_filter_bytecode(
-               struct lttng_event_enabler *enabler,
+               struct lttng_event_enabler_session_common *enabler,
                struct lttng_ust_bytecode_node **bytecode)
        __attribute__((visibility("hidden")));
 
@@ -55,7 +68,7 @@ int lttng_event_enabler_attach_filter_bytecode(
  *
  * Not implemented.
  */
-int lttng_event_enabler_attach_context(struct lttng_event_enabler *enabler,
+int lttng_event_enabler_attach_context(struct lttng_event_enabler_session_common *enabler,
                struct lttng_ust_abi_context *ctx)
        __attribute__((visibility("hidden")));
 
@@ -63,7 +76,7 @@ int lttng_event_enabler_attach_context(struct lttng_event_enabler *enabler,
  * Attach exclusion list to `struct lttng_event_enabler` and all
  * events related to this enabler.
  */
-int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *enabler,
+int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler_session_common *enabler,
                struct lttng_ust_excluder_node **excluder)
        __attribute__((visibility("hidden")));
 
@@ -108,13 +121,6 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
                struct lttng_ust_abi_event_notifier *event_notifier_param)
        __attribute__((visibility("hidden")));
 
-/*
- * Destroy a `struct lttng_event_notifier_enabler` object.
- */
-void lttng_event_notifier_enabler_destroy(
-               struct lttng_event_notifier_enabler *event_notifier_enabler)
-       __attribute__((visibility("hidden")));
-
 /*
  * Enable a `struct lttng_event_notifier_enabler` object and all event
  * notifiers related to this enabler.
@@ -168,9 +174,12 @@ void lttng_free_event_filter_runtime(struct lttng_ust_event_common *event)
 int lttng_fix_pending_event_notifiers(void)
        __attribute__((visibility("hidden")));
 
-struct lttng_counter *lttng_ust_counter_create(
+struct lttng_ust_channel_counter *lttng_ust_counter_create(
                const char *counter_transport_name,
-               size_t number_dimensions, const struct lttng_counter_dimension *dimensions)
+               size_t number_dimensions,
+               const struct lttng_counter_dimension *dimensions,
+               int64_t global_sum_step,
+               bool coalesce_hits)
        __attribute__((visibility("hidden")));
 
 #ifdef HAVE_LINUX_PERF_EVENT_H
index 320d459e1c4397a1c19bbf03eca448d46c1ba514..69a6c7b4c3e72cbee9ee398265a19ff69e3d0332 100644 (file)
@@ -79,8 +79,6 @@ void lttng_session_sync_event_enablers(struct lttng_ust_session *session);
 static
 void lttng_event_notifier_group_sync_enablers(
                struct lttng_event_notifier_group *event_notifier_group);
-static
-void lttng_enabler_destroy(struct lttng_enabler *enabler);
 
 bool lttng_ust_validate_event_name(const struct lttng_ust_event_desc *desc)
 {
@@ -168,52 +166,48 @@ struct lttng_ust_session *lttng_session_create(void)
        CDS_INIT_LIST_HEAD(&session->priv->events_head);
        CDS_INIT_LIST_HEAD(&session->priv->enums_head);
        CDS_INIT_LIST_HEAD(&session->priv->enablers_head);
+       CDS_INIT_LIST_HEAD(&session->priv->counters_head);
        for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++)
-               CDS_INIT_HLIST_HEAD(&session->priv->events_ht.table[i]);
+               CDS_INIT_HLIST_HEAD(&session->priv->events_name_ht.table[i]);
        for (i = 0; i < LTTNG_UST_ENUM_HT_SIZE; i++)
                CDS_INIT_HLIST_HEAD(&session->priv->enums_ht.table[i]);
        cds_list_add(&session->priv->node, &sessions);
        return session;
 }
 
-struct lttng_counter *lttng_ust_counter_create(
+struct lttng_ust_channel_counter *lttng_ust_counter_create(
                const char *counter_transport_name,
-               size_t number_dimensions, const struct lttng_counter_dimension *dimensions)
+               size_t number_dimensions,
+               const struct lttng_counter_dimension *dimensions,
+               int64_t global_sum_step,
+               bool coalesce_hits)
 {
        struct lttng_counter_transport *counter_transport = NULL;
-       struct lttng_counter *counter = NULL;
+       struct lttng_ust_channel_counter *counter = NULL;
 
        counter_transport = lttng_counter_transport_find(counter_transport_name);
-       if (!counter_transport)
+       if (!counter_transport) {
                goto notransport;
-       counter = zmalloc(sizeof(struct lttng_counter));
-       if (!counter)
-               goto nomem;
-
-       counter->ops = &counter_transport->ops;
-       counter->transport = counter_transport;
-
-       counter->counter = counter->ops->counter_create(
-                       number_dimensions, dimensions, 0,
-                       -1, 0, NULL, false);
-       if (!counter->counter) {
+       }
+       counter = counter_transport->ops.priv->counter_create(number_dimensions, dimensions,
+                       global_sum_step, -1, 0, NULL, false);
+       if (!counter) {
                goto create_error;
        }
+       counter->ops = &counter_transport->ops;
+       counter->priv->parent.coalesce_hits = coalesce_hits;
 
        return counter;
 
 create_error:
-       free(counter);
-nomem:
 notransport:
        return NULL;
 }
 
 static
-void lttng_ust_counter_destroy(struct lttng_counter *counter)
+void lttng_ust_counter_destroy(struct lttng_ust_channel_counter *counter)
 {
-       counter->ops->counter_destroy(counter->counter);
-       free(counter);
+       counter->ops->priv->counter_destroy(counter);
 }
 
 struct lttng_event_notifier_group *lttng_event_notifier_group_create(void)
@@ -303,28 +297,33 @@ void _lttng_event_unregister(struct lttng_ust_event_common *event)
 
 void lttng_session_destroy(struct lttng_ust_session *session)
 {
-       struct lttng_ust_channel_buffer_private *chan, *tmpchan;
-       struct lttng_ust_event_recorder_private *event_recorder_priv, *tmpevent_recorder_priv;
+       struct lttng_ust_channel_buffer_private *chan_buffer, *tmpchan_buffer;
+       struct lttng_ust_channel_counter_private *chan_counter, *tmpchan_counter;
+       struct lttng_ust_event_session_common_private *event_priv, *tmpevent_priv;
        struct lttng_enum *_enum, *tmp_enum;
-       struct lttng_event_enabler *event_enabler, *event_tmpenabler;
+       struct lttng_event_enabler_session_common *event_enabler, *event_tmpenabler;
 
        CMM_ACCESS_ONCE(session->active) = 0;
-       cds_list_for_each_entry(event_recorder_priv, &session->priv->events_head, node) {
-               _lttng_event_unregister(event_recorder_priv->parent.pub);
+       cds_list_for_each_entry(event_priv, &session->priv->events_head, node) {
+               _lttng_event_unregister(event_priv->parent.pub);
        }
        lttng_ust_urcu_synchronize_rcu();       /* Wait for in-flight events to complete */
        lttng_ust_tp_probe_prune_release_queue();
        cds_list_for_each_entry_safe(event_enabler, event_tmpenabler,
                        &session->priv->enablers_head, node)
-               lttng_event_enabler_destroy(event_enabler);
-       cds_list_for_each_entry_safe(event_recorder_priv, tmpevent_recorder_priv,
+               lttng_event_enabler_destroy(&event_enabler->parent);
+       cds_list_for_each_entry_safe(event_priv, tmpevent_priv,
                        &session->priv->events_head, node)
-               _lttng_event_destroy(event_recorder_priv->parent.pub);
+               _lttng_event_destroy(event_priv->parent.pub);
        cds_list_for_each_entry_safe(_enum, tmp_enum,
                        &session->priv->enums_head, node)
                _lttng_enum_destroy(_enum);
-       cds_list_for_each_entry_safe(chan, tmpchan, &session->priv->chan_head, node)
-               _lttng_channel_unmap(chan->pub);
+       cds_list_for_each_entry_safe(chan_buffer, tmpchan_buffer, &session->priv->chan_head, node)
+               _lttng_channel_unmap(chan_buffer->pub);
+       cds_list_for_each_entry_safe(chan_counter, tmpchan_counter, &session->priv->counters_head, node) {
+               cds_list_del(&chan_counter->node);
+               lttng_ust_counter_destroy(chan_counter->pub);
+       }
        cds_list_del(&session->priv->node);
        lttng_destroy_context(session->priv->ctx);
        free(session->priv);
@@ -350,7 +349,7 @@ void lttng_event_notifier_group_destroy(
 
        cds_list_for_each_entry_safe(notifier_enabler, tmpnotifier_enabler,
                        &event_notifier_group->enablers_head, node)
-               lttng_event_notifier_enabler_destroy(notifier_enabler);
+               lttng_event_enabler_destroy(&notifier_enabler->parent);
 
        cds_list_for_each_entry_safe(event_notifier_priv, tmpevent_notifier_priv,
                        &event_notifier_group->event_notifiers_head, node)
@@ -377,42 +376,6 @@ void lttng_event_notifier_group_destroy(
        free(event_notifier_group);
 }
 
-static
-void lttng_enabler_destroy(struct lttng_enabler *enabler)
-{
-       struct lttng_ust_bytecode_node *filter_node, *tmp_filter_node;
-       struct lttng_ust_excluder_node *excluder_node, *tmp_excluder_node;
-
-       if (!enabler) {
-               return;
-       }
-
-       /* Destroy filter bytecode */
-       cds_list_for_each_entry_safe(filter_node, tmp_filter_node,
-                       &enabler->filter_bytecode_head, node) {
-               free(filter_node);
-       }
-
-       /* Destroy excluders */
-       cds_list_for_each_entry_safe(excluder_node, tmp_excluder_node,
-                       &enabler->excluder_head, node) {
-               free(excluder_node);
-       }
-}
-
- void lttng_event_notifier_enabler_destroy(struct lttng_event_notifier_enabler *event_notifier_enabler)
-{
-       if (!event_notifier_enabler) {
-               return;
-       }
-
-       cds_list_del(&event_notifier_enabler->node);
-
-       lttng_enabler_destroy(lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
-
-       free(event_notifier_enabler);
-}
-
 static
 int lttng_enum_create(const struct lttng_ust_enum_desc *desc,
                struct lttng_ust_session *session)
@@ -691,37 +654,122 @@ static inline
 struct cds_hlist_head *borrow_hash_table_bucket(
                struct cds_hlist_head *hash_table,
                unsigned int hash_table_size,
-               const struct lttng_ust_event_desc *desc)
+               const char *name)
 {
-       char name[LTTNG_UST_ABI_SYM_NAME_LEN];
        size_t name_len;
        uint32_t hash;
 
-       lttng_ust_format_event_name(desc, name);
        name_len = strlen(name);
 
        hash = jhash(name, name_len, 0);
        return &hash_table[hash & (hash_table_size - 1)];
 }
 
+static
+int format_event_key(char *key_string, const struct lttng_counter_key *key,
+                    const char *provider_name, const char *event_name)
+{
+       const struct lttng_counter_key_dimension *dim;
+       size_t i, left = LTTNG_KEY_TOKEN_STRING_LEN_MAX;
+
+       key_string[0] = '\0';
+       if (!key || !key->nr_dimensions)
+               return 0;
+       /* Currently event keys can only be specified on a single dimension. */
+       if (key->nr_dimensions != 1)
+               return -EINVAL;
+       dim = &key->key_dimensions[0];
+       for (i = 0; i < dim->nr_key_tokens; i++) {
+               const struct lttng_key_token *token = &dim->key_tokens[i];
+               size_t token_len;
+               const char *str;
+
+               switch (token->type) {
+               case LTTNG_KEY_TOKEN_STRING:
+                       str = token->arg.string;
+                       break;
+               case LTTNG_KEY_TOKEN_EVENT_NAME:
+                       str = event_name;
+                       break;
+               case LTTNG_KEY_TOKEN_PROVIDER_NAME:
+                       str = provider_name;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               token_len = strlen(str);
+               if (token_len >= left)
+                       return -EINVAL;
+               strcat(key_string, str);
+               left -= token_len;
+       }
+       return 0;
+}
+
+static
+bool match_event_recorder_token(struct lttng_ust_event_recorder *event_recorder,
+               uint64_t token)
+{
+       if (event_recorder->chan->priv->parent.coalesce_hits)
+               return true;
+       if (event_recorder->priv->parent.parent.user_token == token)
+               return true;
+       return false;
+}
+
+static
+bool match_event_counter_token(struct lttng_ust_event_counter *event_counter,
+               uint64_t token)
+{
+       if (event_counter->chan->priv->parent.coalesce_hits)
+               return true;
+       if (event_counter->priv->parent.parent.user_token == token)
+               return true;
+       return false;
+}
+
 /*
  * Supports event creation while tracing session is active.
  */
 static
-int lttng_event_recorder_create(const struct lttng_ust_event_desc *desc,
-               struct lttng_ust_channel_buffer *chan)
+int lttng_event_recorder_create(struct lttng_event_recorder_enabler *event_recorder_enabler,
+               const struct lttng_ust_event_desc *desc)
 {
        char name[LTTNG_UST_ABI_SYM_NAME_LEN];
        struct lttng_ust_event_recorder *event_recorder;
+       struct lttng_ust_event_session_common_private *event_session_priv_iter;
        struct lttng_ust_event_recorder_private *event_recorder_priv;
-       struct lttng_ust_session *session = chan->parent->session;
-       struct cds_hlist_head *head;
+       struct lttng_ust_session *session = event_recorder_enabler->chan->parent->session;
+       struct cds_hlist_head *name_head;
        int ret = 0;
        int notify_socket, loglevel;
        const char *uri;
 
-       head = borrow_hash_table_bucket(chan->parent->session->priv->events_ht.table,
-               LTTNG_UST_EVENT_HT_SIZE, desc);
+       lttng_ust_format_event_name(desc, name);
+       name_head = borrow_hash_table_bucket(session->priv->events_name_ht.table,
+               LTTNG_UST_EVENT_HT_SIZE, name);
+       cds_hlist_for_each_entry_2(event_session_priv_iter, name_head, name_hlist) {
+               bool same_event = false, same_channel = false, same_token = false;
+               struct lttng_ust_event_recorder_private *event_recorder_priv_iter;
+
+               if (event_session_priv_iter->parent.pub->type != LTTNG_UST_EVENT_TYPE_RECORDER)
+                       continue;
+               event_recorder_priv_iter = caa_container_of(event_session_priv_iter,
+                       struct lttng_ust_event_recorder_private, parent);
+               WARN_ON_ONCE(!event_recorder_priv_iter->parent.parent.desc);
+               if (event_recorder_priv_iter->parent.parent.desc == desc)
+                       same_event = true;
+               if (event_recorder_enabler->chan == event_recorder_priv_iter->pub->chan) {
+                       same_channel = true;
+                       if (match_event_recorder_token(event_recorder_priv_iter->pub,
+                                       event_recorder_enabler->parent.parent.user_token))
+                               same_token = true;
+               }
+               if (same_event && same_channel && same_token) {
+                       ret = -EEXIST;
+                       goto exist;
+               }
+       }
 
        notify_socket = lttng_get_notify_socket(session->priv->owner);
        if (notify_socket < 0) {
@@ -762,10 +810,10 @@ int lttng_event_recorder_create(const struct lttng_ust_event_desc *desc,
        }
        event_recorder->priv = event_recorder_priv;
        event_recorder_priv->pub = event_recorder;
-       event_recorder->parent->priv = &event_recorder_priv->parent;
-       event_recorder_priv->parent.pub = event_recorder->parent;
+       event_recorder->parent->priv = &event_recorder_priv->parent.parent;
+       event_recorder_priv->parent.parent.pub = event_recorder->parent;
 
-       event_recorder->chan = chan;
+       event_recorder->chan = event_recorder_enabler->chan;
 
        /* Event will be enabled by enabler sync. */
        event_recorder->parent->run_filter = lttng_ust_interpret_event_filter;
@@ -774,6 +822,7 @@ int lttng_event_recorder_create(const struct lttng_ust_event_desc *desc,
        CDS_INIT_LIST_HEAD(&event_recorder->parent->priv->filter_bytecode_runtime_head);
        CDS_INIT_LIST_HEAD(&event_recorder->parent->priv->enablers_ref_head);
        event_recorder->parent->priv->desc = desc;
+       event_recorder_priv->parent.chan = event_recorder_enabler->chan->parent;
 
        if (desc->loglevel)
                loglevel = *(*desc->loglevel);
@@ -784,27 +833,27 @@ int lttng_event_recorder_create(const struct lttng_ust_event_desc *desc,
        else
                uri = NULL;
 
-       lttng_ust_format_event_name(desc, name);
-
        /* Fetch event ID from sessiond */
        ret = ustcomm_register_event(notify_socket,
                session,
                session->priv->objd,
-               chan->priv->parent.objd,
+               event_recorder_enabler->chan->priv->parent.objd,
                name,
                loglevel,
                desc->tp_class->signature,
                desc->tp_class->nr_fields,
                desc->tp_class->fields,
                uri,
-               &event_recorder->priv->id);
+               0,
+               &event_recorder->priv->id,
+               NULL);
        if (ret < 0) {
                DBG("Error (%d) registering event to sessiond", ret);
                goto sessiond_register_error;
        }
 
-       cds_list_add(&event_recorder_priv->node, &chan->parent->session->priv->events_head);
-       cds_hlist_add_head(&event_recorder_priv->hlist, head);
+       cds_list_add(&event_recorder_priv->parent.node, &session->priv->events_head);
+       cds_hlist_add_head(&event_recorder_priv->parent.name_hlist, name_head);
        return 0;
 
 sessiond_register_error:
@@ -816,6 +865,160 @@ parent_error:
 cache_error:
 create_enum_error:
 socket_error:
+exist:
+       return ret;
+}
+
+static
+int lttng_event_counter_create(struct lttng_event_counter_enabler *event_counter_enabler,
+               const struct lttng_ust_event_desc *desc,
+               struct lttng_counter_key *key)
+{
+       char name[LTTNG_UST_ABI_SYM_NAME_LEN];
+       char key_string[LTTNG_KEY_TOKEN_STRING_LEN_MAX];
+       struct lttng_ust_event_counter *event_counter;
+       struct lttng_ust_event_counter_private *event_counter_priv;
+       struct lttng_ust_event_session_common_private *event_session_priv_iter;
+       struct lttng_ust_session *session = event_counter_enabler->chan->parent->session;
+       struct cds_hlist_head *name_head;
+       int ret = 0;
+       int notify_socket, loglevel;
+       const char *uri;
+
+       if (format_event_key(key_string, key, desc->probe_desc->provider_name, desc->event_name)) {
+               ret = -EINVAL;
+               goto type_error;
+       }
+
+       lttng_ust_format_event_name(desc, name);
+       name_head = borrow_hash_table_bucket(session->priv->events_name_ht.table,
+               LTTNG_UST_EVENT_HT_SIZE, name);
+       cds_hlist_for_each_entry_2(event_session_priv_iter, name_head, name_hlist) {
+               struct lttng_ust_event_counter_private *event_counter_priv_iter;
+               bool same_event = false, same_channel = false, same_key = false,
+                               same_token = false;
+
+               if (event_session_priv_iter->parent.pub->type != LTTNG_UST_EVENT_TYPE_COUNTER)
+                       continue;
+               event_counter_priv_iter = caa_container_of(event_session_priv_iter,
+                       struct lttng_ust_event_counter_private, parent);
+               WARN_ON_ONCE(!event_counter_priv_iter->parent.parent.desc);
+               if (event_counter_priv_iter->parent.parent.desc == desc)
+                       same_event = true;
+               if (event_counter_enabler->chan == event_counter_priv_iter->pub->chan) {
+                       same_channel = true;
+                       if (match_event_counter_token(event_counter_priv_iter->pub,
+                                       event_counter_enabler->parent.parent.user_token))
+                               same_token = true;
+               }
+               if (key_string[0] == '\0' || !strcmp(key_string, event_counter_priv_iter->key))
+                       same_key = true;
+               if (same_event && same_channel && same_key && same_token) {
+                       ret = -EEXIST;
+                       goto exist;
+               }
+       }
+
+       notify_socket = lttng_get_notify_socket(session->priv->owner);
+       if (notify_socket < 0) {
+               ret = notify_socket;
+               goto socket_error;
+       }
+
+       ret = lttng_create_all_event_enums(desc->tp_class->nr_fields, desc->tp_class->fields,
+                       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.
+        */
+       event_counter = zmalloc(sizeof(struct lttng_ust_event_counter));
+       if (!event_counter) {
+               ret = -ENOMEM;
+               goto cache_error;
+       }
+       event_counter->struct_size = sizeof(struct lttng_ust_event_counter);
+
+       event_counter->parent = zmalloc(sizeof(struct lttng_ust_event_common));
+       if (!event_counter->parent) {
+               ret = -ENOMEM;
+               goto parent_error;
+       }
+       event_counter->parent->struct_size = sizeof(struct lttng_ust_event_common);
+       event_counter->parent->type = LTTNG_UST_EVENT_TYPE_COUNTER;
+       event_counter->parent->child = event_counter;
+
+       event_counter_priv = zmalloc(sizeof(struct lttng_ust_event_counter_private));
+       if (!event_counter_priv) {
+               ret = -ENOMEM;
+               goto priv_error;
+       }
+       event_counter->priv = event_counter_priv;
+       event_counter_priv->pub = event_counter;
+       event_counter->parent->priv = &event_counter_priv->parent.parent;
+       event_counter_priv->parent.parent.pub = event_counter->parent;
+
+       event_counter->chan = event_counter_enabler->chan;
+
+       /* Event will be enabled by enabler sync. */
+       event_counter->parent->run_filter = lttng_ust_interpret_event_filter;
+       event_counter->parent->enabled = 0;
+       event_counter->parent->priv->registered = 0;
+       CDS_INIT_LIST_HEAD(&event_counter->parent->priv->filter_bytecode_runtime_head);
+       CDS_INIT_LIST_HEAD(&event_counter->parent->priv->enablers_ref_head);
+       event_counter->parent->priv->desc = desc;
+       event_counter_priv->parent.chan = event_counter_enabler->chan->parent;
+       strcpy(event_counter->priv->key, key_string);
+       if (!event_counter->chan->priv->parent.coalesce_hits)
+               event_counter->priv->parent.parent.user_token = event_counter_enabler->parent.parent.user_token;
+
+       if (desc->loglevel)
+               loglevel = *(*desc->loglevel);
+       else
+               loglevel = LTTNG_UST_TRACEPOINT_LOGLEVEL_DEFAULT;
+       if (desc->model_emf_uri)
+               uri = *(desc->model_emf_uri);
+       else
+               uri = NULL;
+
+       /* Fetch event ID from sessiond */
+       ret = ustcomm_register_event(notify_socket,
+               session,
+               session->priv->objd,
+               event_counter_enabler->chan->priv->parent.objd,
+               name,
+               loglevel,
+               desc->tp_class->signature,
+               desc->tp_class->nr_fields,
+               desc->tp_class->fields,
+               uri,
+               event_counter_enabler->parent.parent.user_token,
+               NULL,
+               &event_counter->priv->counter_index);
+       if (ret < 0) {
+               DBG("Error (%d) registering event to sessiond", ret);
+               goto sessiond_register_error;
+       }
+
+       cds_list_add(&event_counter_priv->parent.node,
+               &event_counter_enabler->chan->parent->session->priv->events_head);
+       cds_hlist_add_head(&event_counter_priv->parent.name_hlist, name_head);
+       return 0;
+
+sessiond_register_error:
+       free(event_counter_priv);
+priv_error:
+       free(event_counter->parent);
+parent_error:
+       free(event_counter);
+cache_error:
+create_enum_error:
+socket_error:
+exist:
+type_error:
        return ret;
 }
 
@@ -826,6 +1029,7 @@ int lttng_event_notifier_create(const struct lttng_ust_event_desc *desc,
 {
        struct lttng_ust_event_notifier *event_notifier;
        struct lttng_ust_event_notifier_private *event_notifier_priv;
+       char name[LTTNG_UST_ABI_SYM_NAME_LEN];
        struct cds_hlist_head *head;
        int ret = 0;
 
@@ -833,9 +1037,10 @@ int lttng_event_notifier_create(const struct lttng_ust_event_desc *desc,
         * Get the hashtable bucket the created lttng_event_notifier object
         * should be inserted.
         */
+       lttng_ust_format_event_name(desc, name);
        head = borrow_hash_table_bucket(
                event_notifier_group->event_notifiers_ht.table,
-               LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc);
+               LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, name);
 
        event_notifier = zmalloc(sizeof(struct lttng_ust_event_notifier));
        if (!event_notifier) {
@@ -894,7 +1099,7 @@ error:
 
 static
 int lttng_desc_match_star_glob_enabler(const struct lttng_ust_event_desc *desc,
-               struct lttng_enabler *enabler)
+               struct lttng_event_enabler_common *enabler)
 {
        char name[LTTNG_UST_ABI_SYM_NAME_LEN];
        int loglevel = 0;
@@ -919,7 +1124,7 @@ int lttng_desc_match_star_glob_enabler(const struct lttng_ust_event_desc *desc,
 
 static
 int lttng_desc_match_event_enabler(const struct lttng_ust_event_desc *desc,
-               struct lttng_enabler *enabler)
+               struct lttng_event_enabler_common *enabler)
 {
        char name[LTTNG_UST_ABI_SYM_NAME_LEN];
        int loglevel = 0;
@@ -943,7 +1148,7 @@ int lttng_desc_match_event_enabler(const struct lttng_ust_event_desc *desc,
 
 static
 int lttng_desc_match_enabler(const struct lttng_ust_event_desc *desc,
-               struct lttng_enabler *enabler)
+               struct lttng_event_enabler_common *enabler)
 {
        switch (enabler->format_type) {
        case LTTNG_ENABLER_FORMAT_STAR_GLOB:
@@ -988,12 +1193,25 @@ int lttng_desc_match_enabler(const struct lttng_ust_event_desc *desc,
 }
 
 static
-int lttng_event_enabler_match_event(struct lttng_event_enabler *event_enabler,
+int lttng_event_recorder_enabler_match_event_recorder(struct lttng_event_recorder_enabler *event_recorder_enabler,
                struct lttng_ust_event_recorder *event_recorder)
 {
        if (lttng_desc_match_enabler(event_recorder->parent->priv->desc,
-                       lttng_event_enabler_as_enabler(event_enabler))
-                       && event_recorder->chan == event_enabler->chan)
+                       &event_recorder_enabler->parent.parent)
+                       && event_recorder->chan == event_recorder_enabler->chan)
+               return 1;
+       else
+               return 0;
+}
+
+static
+int lttng_event_counter_enabler_match_event_counter(struct lttng_event_counter_enabler *event_counter_enabler,
+               struct lttng_ust_event_counter *event_counter)
+{
+       if (lttng_desc_match_enabler(event_counter->parent->priv->desc,
+                       &event_counter_enabler->parent.parent)
+                       && event_counter->chan == event_counter_enabler->chan
+                       && match_event_counter_token(event_counter, event_counter_enabler->parent.parent.user_token))
                return 1;
        else
                return 0;
@@ -1008,16 +1226,50 @@ int lttng_event_notifier_enabler_match_event_notifier(
                lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
 
        if (desc_matches && event_notifier->priv->group == event_notifier_enabler->group &&
-                       event_notifier->priv->parent.user_token == event_notifier_enabler->user_token)
+                       event_notifier->priv->parent.user_token == event_notifier_enabler->parent.user_token)
                return 1;
        else
                return 0;
 }
 
+static
+int lttng_event_enabler_match_event(
+               struct lttng_event_enabler_common *event_enabler,
+               struct lttng_ust_event_common *event)
+{
+       switch (event_enabler->enabler_type) {
+       case LTTNG_EVENT_ENABLER_TYPE_RECORDER:
+       {
+               struct lttng_event_recorder_enabler *event_recorder_enabler =
+                       caa_container_of(event_enabler, struct lttng_event_recorder_enabler, parent.parent);
+               struct lttng_ust_event_recorder *event_recorder =
+                       (struct lttng_ust_event_recorder *) event->child;
+               return lttng_event_recorder_enabler_match_event_recorder(event_recorder_enabler, event_recorder);
+       }
+       case LTTNG_EVENT_ENABLER_TYPE_NOTIFIER:
+       {
+               struct lttng_event_notifier_enabler *event_notifier_enabler =
+                       caa_container_of(event_enabler, struct lttng_event_notifier_enabler, parent);
+               struct lttng_ust_event_notifier *event_notifier =
+                       (struct lttng_ust_event_notifier *) event->child;
+               return lttng_event_notifier_enabler_match_event_notifier(event_notifier_enabler, event_notifier);
+       }
+       case LTTNG_EVENT_ENABLER_TYPE_COUNTER:
+       {
+               struct lttng_event_counter_enabler *event_counter_enabler =
+                       caa_container_of(event_enabler, struct lttng_event_counter_enabler, parent.parent);
+               struct lttng_ust_event_counter *event_counter =
+                       (struct lttng_ust_event_counter *) event->child;
+               return lttng_event_counter_enabler_match_event_counter(event_counter_enabler, event_counter);
+       }
+       }
+       return 0;
+}
+
 static
 struct lttng_enabler_ref *lttng_enabler_ref(
                struct cds_list_head *enabler_ref_list,
-               struct lttng_enabler *enabler)
+               struct lttng_event_enabler_common *enabler)
 {
        struct lttng_enabler_ref *enabler_ref;
 
@@ -1033,12 +1285,10 @@ struct lttng_enabler_ref *lttng_enabler_ref(
  * tracepoint probes.
  */
 static
-void lttng_create_event_recorder_if_missing(struct lttng_event_enabler *event_enabler)
+void lttng_create_event_if_missing(struct lttng_event_enabler_session_common *event_enabler)
 {
-       struct lttng_ust_session *session = event_enabler->chan->parent->session;
        struct lttng_ust_registered_probe *reg_probe;
        const struct lttng_ust_event_desc *desc;
-       struct lttng_ust_event_recorder_private *event_recorder_priv;
        int i;
        struct cds_list_head *probe_list;
 
@@ -1053,39 +1303,61 @@ void lttng_create_event_recorder_if_missing(struct lttng_event_enabler *event_en
 
                for (i = 0; i < probe_desc->nr_events; i++) {
                        int ret;
-                       bool found = false;
-                       struct cds_hlist_head *head;
-                       struct cds_hlist_node *node;
 
                        desc = probe_desc->event_desc[i];
-                       if (!lttng_desc_match_enabler(desc,
-                                       lttng_event_enabler_as_enabler(event_enabler)))
+                       if (!lttng_desc_match_enabler(desc, &event_enabler->parent))
                                continue;
+                       switch (event_enabler->parent.enabler_type) {
+                       case LTTNG_EVENT_ENABLER_TYPE_RECORDER:
+                       {
+                               struct lttng_event_recorder_enabler *event_recorder_enabler =
+                                       caa_container_of(event_enabler,
+                                               struct lttng_event_recorder_enabler,
+                                               parent);
 
-                       head = borrow_hash_table_bucket(
-                               session->priv->events_ht.table,
-                               LTTNG_UST_EVENT_HT_SIZE, desc);
+                               /*
+                                * We need to create an event for this
+                                * event probe.
+                                */
+                               ret = lttng_event_recorder_create(event_recorder_enabler,
+                                               probe_desc->event_desc[i]);
+                               /* Skip if already found. */
+                               if (ret == -EEXIST)
+                                       continue;
+                               if (ret) {
+                                       DBG("Unable to create event \"%s:%s\", error %d\n",
+                                               probe_desc->provider_name,
+                                               probe_desc->event_desc[i]->event_name, ret);
+                               }
+                               break;
+                       }
+                       case LTTNG_EVENT_ENABLER_TYPE_COUNTER:
+                       {
+                               struct lttng_event_counter_enabler *event_counter_enabler =
+                                       caa_container_of(event_enabler,
+                                               struct lttng_event_counter_enabler,
+                                               parent);
 
-                       cds_hlist_for_each_entry(event_recorder_priv, node, head, hlist) {
-                               if (event_recorder_priv->parent.desc == desc
-                                               && event_recorder_priv->pub->chan == event_enabler->chan) {
-                                       found = true;
-                                       break;
+                               /*
+                                * We need to create an event for this
+                                * event probe.
+                                */
+                               ret = lttng_event_counter_create(event_counter_enabler,
+                                               probe_desc->event_desc[i],
+                                               &event_counter_enabler->key);
+                               /* Skip if already found. */
+                               if (ret == -EEXIST)
+                                       continue;
+                               if (ret) {
+                                       DBG("Unable to create event \"%s:%s\", error %d\n",
+                                               probe_desc->provider_name,
+                                               probe_desc->event_desc[i]->event_name, ret);
                                }
+                               break;
                        }
-                       if (found)
+                       default:
+                               abort();        /* Unexpected */
                                continue;
-
-                       /*
-                        * We need to create an event for this
-                        * event probe.
-                        */
-                       ret = lttng_event_recorder_create(probe_desc->event_desc[i],
-                                       event_enabler->chan);
-                       if (ret) {
-                               DBG("Unable to create event \"%s:%s\", error %d\n",
-                                       probe_desc->provider_name,
-                                       probe_desc->event_desc[i]->event_name, ret);
                        }
                }
        }
@@ -1109,7 +1381,6 @@ void probe_provider_event_for_each(const struct lttng_ust_probe_desc *provider_d
        for (i = 0; i < provider_desc->nr_events; i++) {
                const struct lttng_ust_event_desc *event_desc;
                struct lttng_event_notifier_group *event_notifier_group;
-               struct lttng_ust_event_recorder_private *event_recorder_priv;
                struct lttng_ust_event_notifier_private *event_notifier_priv;
                struct lttng_ust_session_private *session_priv;
                struct cds_hlist_head *head;
@@ -1121,17 +1392,21 @@ void probe_provider_event_for_each(const struct lttng_ust_probe_desc *provider_d
                 * description.
                 */
                cds_list_for_each_entry(session_priv, sessionsp, node) {
+                       struct lttng_ust_event_session_common_private *event_session_priv;
+                       char name[LTTNG_UST_ABI_SYM_NAME_LEN];
+
                        /*
                         * Get the list of events in the hashtable bucket and
                         * iterate to find the event matching this descriptor.
                         */
+                       lttng_ust_format_event_name(event_desc, name);
                        head = borrow_hash_table_bucket(
-                               session_priv->events_ht.table,
-                               LTTNG_UST_EVENT_HT_SIZE, event_desc);
+                               session_priv->events_name_ht.table,
+                               LTTNG_UST_EVENT_HT_SIZE, name);
 
-                       cds_hlist_for_each_entry_safe(event_recorder_priv, node, tmp_node, head, hlist) {
-                               if (event_desc == event_recorder_priv->parent.desc) {
-                                       event_func(event_recorder_priv->parent.pub);
+                       cds_hlist_for_each_entry_safe(event_session_priv, node, tmp_node, head, name_hlist) {
+                               if (event_desc == event_session_priv->parent.desc) {
+                                       event_func(event_session_priv->parent.pub);
                                        break;
                                }
                        }
@@ -1142,14 +1417,17 @@ void probe_provider_event_for_each(const struct lttng_ust_probe_desc *provider_d
                 * description.
                 */
                cds_list_for_each_entry(event_notifier_group, &event_notifier_groups, node) {
+                       char name[LTTNG_UST_ABI_SYM_NAME_LEN];
+
                        /*
                         * Get the list of event_notifiers in the hashtable bucket and
                         * iterate to find the event_notifier matching this
                         * descriptor.
                         */
+                       lttng_ust_format_event_name(event_desc, name);
                        head = borrow_hash_table_bucket(
                                event_notifier_group->event_notifiers_ht.table,
-                               LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, event_desc);
+                               LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, name);
 
                        cds_hlist_for_each_entry_safe(event_notifier_priv, node, tmp_node, head, hlist) {
                                if (event_desc == event_notifier_priv->parent.desc) {
@@ -1166,19 +1444,22 @@ void _event_enum_destroy(struct lttng_ust_event_common *event)
 {
 
        switch (event->type) {
-       case LTTNG_UST_EVENT_TYPE_RECORDER:
+       case LTTNG_UST_EVENT_TYPE_RECORDER:     /* Fall-through */
+       case LTTNG_UST_EVENT_TYPE_COUNTER:
        {
-               struct lttng_ust_event_recorder *event_recorder = event->child;
-               struct lttng_ust_session *session = event_recorder->chan->parent->session;
+               struct lttng_ust_event_common_private *event_priv = event->priv;
+               struct lttng_ust_event_session_common_private *event_session_priv =
+                       caa_container_of(event_priv, struct lttng_ust_event_session_common_private, parent);
+               struct lttng_ust_session *session = event_session_priv->chan->session;
                unsigned int i;
 
                /* Destroy enums of the current event. */
-               for (i = 0; i < event_recorder->parent->priv->desc->tp_class->nr_fields; i++) {
+               for (i = 0; i < event_session_priv->parent.desc->tp_class->nr_fields; i++) {
                        const struct lttng_ust_enum_desc *enum_desc;
                        const struct lttng_ust_event_field *field;
                        struct lttng_enum *curr_enum;
 
-                       field = event_recorder->parent->priv->desc->tp_class->fields[i];
+                       field = event_session_priv->parent.desc->tp_class->fields[i];
                        switch (field->type->type) {
                        case lttng_ust_type_enum:
                                enum_desc = lttng_ust_get_type_enum(field->type)->desc;
@@ -1234,26 +1515,26 @@ void lttng_probe_provider_unregister_events(
  * and add backward reference from the event to the enabler.
  */
 static
-int lttng_event_enabler_ref_event_recorders(struct lttng_event_enabler *event_enabler)
+int lttng_event_enabler_ref_events(struct lttng_event_enabler_session_common *event_enabler)
 {
-       struct lttng_ust_session *session = event_enabler->chan->parent->session;
-       struct lttng_ust_event_recorder_private *event_recorder_priv;
+       struct lttng_ust_session *session = event_enabler->chan->session;
+       struct lttng_ust_event_session_common_private *event_priv;
 
-       if (!lttng_event_enabler_as_enabler(event_enabler)->enabled)
+       if (!event_enabler->parent.enabled)
                goto end;
 
        /* First ensure that probe events are created for this enabler. */
-       lttng_create_event_recorder_if_missing(event_enabler);
+       lttng_create_event_if_missing(event_enabler);
 
        /* For each event matching enabler in session event list. */
-       cds_list_for_each_entry(event_recorder_priv, &session->priv->events_head, node) {
+       cds_list_for_each_entry(event_priv, &session->priv->events_head, node) {
                struct lttng_enabler_ref *enabler_ref;
 
-               if (!lttng_event_enabler_match_event(event_enabler, event_recorder_priv->pub))
+               if (!lttng_event_enabler_match_event(&event_enabler->parent, event_priv->parent.pub))
                        continue;
 
-               enabler_ref = lttng_enabler_ref(&event_recorder_priv->parent.enablers_ref_head,
-                       lttng_event_enabler_as_enabler(event_enabler));
+               enabler_ref = lttng_enabler_ref(&event_priv->parent.enablers_ref_head,
+                       &event_enabler->parent);
                if (!enabler_ref) {
                        /*
                         * If no backward ref, create it.
@@ -1262,19 +1543,18 @@ int lttng_event_enabler_ref_event_recorders(struct lttng_event_enabler *event_en
                        enabler_ref = zmalloc(sizeof(*enabler_ref));
                        if (!enabler_ref)
                                return -ENOMEM;
-                       enabler_ref->ref = lttng_event_enabler_as_enabler(
-                               event_enabler);
+                       enabler_ref->ref = &event_enabler->parent;
                        cds_list_add(&enabler_ref->node,
-                               &event_recorder_priv->parent.enablers_ref_head);
+                               &event_priv->parent.enablers_ref_head);
                }
 
                /*
                 * Link filter bytecodes if not linked yet.
                 */
-               lttng_enabler_link_bytecode(event_recorder_priv->parent.desc,
+               lttng_enabler_link_bytecode(event_priv->parent.desc,
                        &session->priv->ctx,
-                       &event_recorder_priv->parent.filter_bytecode_runtime_head,
-                       &lttng_event_enabler_as_enabler(event_enabler)->filter_bytecode_head);
+                       &event_priv->parent.filter_bytecode_runtime_head,
+                       &event_enabler->parent.filter_bytecode_head);
 
                /* TODO: merge event context. */
        }
@@ -1352,11 +1632,11 @@ void _lttng_event_destroy(struct lttng_ust_event_common *event)
                struct lttng_ust_event_recorder *event_recorder = event->child;
 
                /* Remove from event list. */
-               cds_list_del(&event_recorder->priv->node);
+               cds_list_del(&event_recorder->priv->parent.node);
                /* Remove from event hash table. */
-               cds_hlist_del(&event_recorder->priv->hlist);
+               cds_hlist_del(&event_recorder->priv->parent.name_hlist);
 
-               lttng_destroy_context(event_recorder->priv->ctx);
+               lttng_destroy_context(event_recorder->priv->parent.ctx);
                free(event_recorder->parent);
                free(event_recorder->priv);
                free(event_recorder);
@@ -1376,6 +1656,21 @@ void _lttng_event_destroy(struct lttng_ust_event_common *event)
                free(event_notifier);
                break;
        }
+       case LTTNG_UST_EVENT_TYPE_COUNTER:
+       {
+               struct lttng_ust_event_counter *event_counter = event->child;
+
+               /* Remove from event list. */
+               cds_list_del(&event_counter->priv->parent.node);
+               /* Remove from event hash table. */
+               cds_hlist_del(&event_counter->priv->parent.name_hlist);
+
+               lttng_destroy_context(event_counter->priv->parent.ctx);
+               free(event_counter->parent);
+               free(event_counter->priv);
+               free(event_counter);
+               break;
+       }
        default:
                abort();
        }
@@ -1397,28 +1692,118 @@ void lttng_ust_abi_events_exit(void)
                lttng_session_destroy(session_priv->pub);
 }
 
+static
+int copy_counter_key(struct lttng_counter_key *key,
+                    const struct lttng_ust_abi_counter_key *key_param)
+{
+       size_t i, j, nr_dimensions;
+
+       nr_dimensions = key_param->nr_dimensions;
+       if (nr_dimensions > LTTNG_UST_ABI_COUNTER_DIMENSION_MAX)
+               return -EINVAL;
+       key->nr_dimensions = nr_dimensions;
+       for (i = 0; i < nr_dimensions; i++) {
+               const struct lttng_ust_abi_counter_key_dimension *udim =
+                       &key_param->key_dimensions[i];
+               struct lttng_counter_key_dimension *dim =
+                       &key->key_dimensions[i];
+               size_t nr_key_tokens;
+
+               nr_key_tokens = udim->nr_key_tokens;
+               if (!nr_key_tokens || nr_key_tokens > LTTNG_UST_ABI_NR_KEY_TOKEN)
+                       return -EINVAL;
+               dim->nr_key_tokens = nr_key_tokens;
+               for (j = 0; j < nr_key_tokens; j++) {
+                       const struct lttng_ust_abi_key_token *utoken =
+                               &udim->key_tokens[j];
+                       struct lttng_key_token *token =
+                               &dim->key_tokens[j];
+
+                       switch (utoken->type) {
+                       case LTTNG_UST_ABI_KEY_TOKEN_STRING:
+                       {
+                               size_t len;
+
+                               token->type = LTTNG_UST_ABI_KEY_TOKEN_STRING;
+                               len = strnlen(utoken->arg.string, LTTNG_UST_ABI_KEY_TOKEN_STRING_LEN_MAX);
+                               if (!len || len >= LTTNG_UST_ABI_KEY_TOKEN_STRING_LEN_MAX)
+                                       return -EINVAL;
+                               strcpy(token->arg.string, utoken->arg.string);
+                               break;
+                       }
+                       case LTTNG_UST_ABI_KEY_TOKEN_EVENT_NAME:
+                               token->type = LTTNG_UST_ABI_KEY_TOKEN_EVENT_NAME;
+                               break;
+                       case LTTNG_UST_ABI_KEY_TOKEN_PROVIDER_NAME:
+                               token->type = LTTNG_UST_ABI_KEY_TOKEN_PROVIDER_NAME;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+       }
+       return 0;
+}
+
 /*
  * Enabler management.
  */
-struct lttng_event_enabler *lttng_event_enabler_create(
+struct lttng_event_recorder_enabler *lttng_event_recorder_enabler_create(
                enum lttng_enabler_format_type format_type,
-               struct lttng_ust_abi_event *event_param,
+               const struct lttng_ust_abi_event *event_param,
                struct lttng_ust_channel_buffer *chan)
 {
-       struct lttng_event_enabler *event_enabler;
+       struct lttng_event_recorder_enabler *event_enabler;
 
        event_enabler = zmalloc(sizeof(*event_enabler));
        if (!event_enabler)
                return NULL;
-       event_enabler->base.format_type = format_type;
-       CDS_INIT_LIST_HEAD(&event_enabler->base.filter_bytecode_head);
-       CDS_INIT_LIST_HEAD(&event_enabler->base.excluder_head);
-       memcpy(&event_enabler->base.event_param, event_param,
-               sizeof(event_enabler->base.event_param));
+       event_enabler->parent.parent.enabler_type = LTTNG_EVENT_ENABLER_TYPE_RECORDER;
+       event_enabler->parent.parent.format_type = format_type;
+       CDS_INIT_LIST_HEAD(&event_enabler->parent.parent.filter_bytecode_head);
+       CDS_INIT_LIST_HEAD(&event_enabler->parent.parent.excluder_head);
+       memcpy(&event_enabler->parent.parent.event_param, event_param,
+               sizeof(event_enabler->parent.parent.event_param));
        event_enabler->chan = chan;
        /* ctx left NULL */
-       event_enabler->base.enabled = 0;
-       cds_list_add(&event_enabler->node, &event_enabler->chan->parent->session->priv->enablers_head);
+       event_enabler->parent.parent.enabled = 0;
+       event_enabler->parent.parent.user_token = event_param->token;
+       event_enabler->parent.chan = chan->parent;
+       cds_list_add(&event_enabler->parent.node, &event_enabler->chan->parent->session->priv->enablers_head);
+       lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session);
+
+       return event_enabler;
+}
+
+struct lttng_event_counter_enabler *lttng_event_counter_enabler_create(
+               enum lttng_enabler_format_type format_type,
+               const struct lttng_ust_abi_event *event_param,
+               const struct lttng_ust_abi_counter_key *key,
+               struct lttng_ust_channel_counter *chan)
+{
+       struct lttng_event_counter_enabler *event_enabler;
+
+       event_enabler = zmalloc(sizeof(*event_enabler));
+       if (!event_enabler)
+               return NULL;
+       event_enabler->parent.parent.enabler_type = LTTNG_EVENT_ENABLER_TYPE_COUNTER;
+       event_enabler->parent.parent.format_type = format_type;
+       CDS_INIT_LIST_HEAD(&event_enabler->parent.parent.filter_bytecode_head);
+       CDS_INIT_LIST_HEAD(&event_enabler->parent.parent.excluder_head);
+       memcpy(&event_enabler->parent.parent.event_param, event_param,
+               sizeof(event_enabler->parent.parent.event_param));
+       event_enabler->chan = chan;
+       if (key) {
+               if (copy_counter_key(&event_enabler->key, key)) {
+                       free(event_enabler);
+                       return NULL;
+               }
+       }
+       /* ctx left NULL */
+       event_enabler->parent.parent.enabled = 0;
+       event_enabler->parent.parent.user_token = event_param->token;
+       event_enabler->parent.chan = chan->parent;
+       cds_list_add(&event_enabler->parent.node, &event_enabler->chan->parent->session->priv->enablers_head);
        lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session);
 
        return event_enabler;
@@ -1434,26 +1819,27 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
        event_notifier_enabler = zmalloc(sizeof(*event_notifier_enabler));
        if (!event_notifier_enabler)
                return NULL;
-       event_notifier_enabler->base.format_type = format_type;
-       CDS_INIT_LIST_HEAD(&event_notifier_enabler->base.filter_bytecode_head);
+       event_notifier_enabler->parent.enabler_type = LTTNG_EVENT_ENABLER_TYPE_NOTIFIER;
+       event_notifier_enabler->parent.format_type = format_type;
+       CDS_INIT_LIST_HEAD(&event_notifier_enabler->parent.filter_bytecode_head);
+       CDS_INIT_LIST_HEAD(&event_notifier_enabler->parent.excluder_head);
        CDS_INIT_LIST_HEAD(&event_notifier_enabler->capture_bytecode_head);
-       CDS_INIT_LIST_HEAD(&event_notifier_enabler->base.excluder_head);
 
-       event_notifier_enabler->user_token = event_notifier_param->event.token;
+       event_notifier_enabler->parent.user_token = event_notifier_param->event.token;
        event_notifier_enabler->error_counter_index = event_notifier_param->error_counter_index;
        event_notifier_enabler->num_captures = 0;
 
-       memcpy(&event_notifier_enabler->base.event_param.name,
+       memcpy(&event_notifier_enabler->parent.event_param.name,
                event_notifier_param->event.name,
-               sizeof(event_notifier_enabler->base.event_param.name));
-       event_notifier_enabler->base.event_param.instrumentation =
+               sizeof(event_notifier_enabler->parent.event_param.name));
+       event_notifier_enabler->parent.event_param.instrumentation =
                event_notifier_param->event.instrumentation;
-       event_notifier_enabler->base.event_param.loglevel =
+       event_notifier_enabler->parent.event_param.loglevel =
                event_notifier_param->event.loglevel;
-       event_notifier_enabler->base.event_param.loglevel_type =
+       event_notifier_enabler->parent.event_param.loglevel_type =
                event_notifier_param->event.loglevel_type;
 
-       event_notifier_enabler->base.enabled = 0;
+       event_notifier_enabler->parent.enabled = 0;
        event_notifier_enabler->group = event_notifier_group;
 
        cds_list_add(&event_notifier_enabler->node,
@@ -1464,24 +1850,24 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
        return event_notifier_enabler;
 }
 
-int lttng_event_enabler_enable(struct lttng_event_enabler *event_enabler)
+int lttng_event_enabler_enable(struct lttng_event_enabler_session_common *event_enabler)
 {
-       lttng_event_enabler_as_enabler(event_enabler)->enabled = 1;
-       lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session);
+       event_enabler->parent.enabled = 1;
+       lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
 
        return 0;
 }
 
-int lttng_event_enabler_disable(struct lttng_event_enabler *event_enabler)
+int lttng_event_enabler_disable(struct lttng_event_enabler_session_common *event_enabler)
 {
-       lttng_event_enabler_as_enabler(event_enabler)->enabled = 0;
-       lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session);
+       event_enabler->parent.enabled = 0;
+       lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
 
        return 0;
 }
 
 static
-void _lttng_enabler_attach_filter_bytecode(struct lttng_enabler *enabler,
+void _lttng_enabler_attach_filter_bytecode(struct lttng_event_enabler_common *enabler,
                struct lttng_ust_bytecode_node **bytecode)
 {
        (*bytecode)->enabler = enabler;
@@ -1490,18 +1876,17 @@ void _lttng_enabler_attach_filter_bytecode(struct lttng_enabler *enabler,
        *bytecode = NULL;
 }
 
-int lttng_event_enabler_attach_filter_bytecode(struct lttng_event_enabler *event_enabler,
+int lttng_event_enabler_attach_filter_bytecode(struct lttng_event_enabler_session_common *event_enabler,
                struct lttng_ust_bytecode_node **bytecode)
 {
-       _lttng_enabler_attach_filter_bytecode(
-               lttng_event_enabler_as_enabler(event_enabler), bytecode);
+       _lttng_enabler_attach_filter_bytecode(&event_enabler->parent, bytecode);
 
-       lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session);
+       lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
        return 0;
 }
 
 static
-void _lttng_enabler_attach_exclusion(struct lttng_enabler *enabler,
+void _lttng_enabler_attach_exclusion(struct lttng_event_enabler_common *enabler,
                struct lttng_ust_excluder_node **excluder)
 {
        (*excluder)->enabler = enabler;
@@ -1510,13 +1895,12 @@ void _lttng_enabler_attach_exclusion(struct lttng_enabler *enabler,
        *excluder = NULL;
 }
 
-int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *event_enabler,
+int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler_session_common *event_enabler,
                struct lttng_ust_excluder_node **excluder)
 {
-       _lttng_enabler_attach_exclusion(
-               lttng_event_enabler_as_enabler(event_enabler), excluder);
+       _lttng_enabler_attach_exclusion(&event_enabler->parent, excluder);
 
-       lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session);
+       lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
        return 0;
 }
 
@@ -1651,23 +2035,73 @@ int lttng_attach_context(struct lttng_ust_abi_context *context_param,
 }
 
 int lttng_event_enabler_attach_context(
-               struct lttng_event_enabler *enabler __attribute__((unused)),
+               struct lttng_event_enabler_session_common *enabler __attribute__((unused)),
                struct lttng_ust_abi_context *context_param __attribute__((unused)))
 {
        return -ENOSYS;
 }
 
-void lttng_event_enabler_destroy(struct lttng_event_enabler *event_enabler)
+void lttng_event_enabler_destroy(struct lttng_event_enabler_common *event_enabler)
 {
+       struct lttng_ust_bytecode_node *filter_node, *tmp_filter_node;
+       struct lttng_ust_excluder_node *excluder_node, *tmp_excluder_node;
+
        if (!event_enabler) {
                return;
        }
-       cds_list_del(&event_enabler->node);
 
-       lttng_enabler_destroy(lttng_event_enabler_as_enabler(event_enabler));
+       /* Destroy filter bytecode */
+       cds_list_for_each_entry_safe(filter_node, tmp_filter_node,
+                       &event_enabler->filter_bytecode_head, node) {
+               free(filter_node);
+       }
+
+       /* Destroy excluders */
+       cds_list_for_each_entry_safe(excluder_node, tmp_excluder_node,
+                       &event_enabler->excluder_head, node) {
+               free(excluder_node);
+       }
+
+       switch (event_enabler->enabler_type) {
+       case LTTNG_EVENT_ENABLER_TYPE_RECORDER: /* Fall-through */
+       case LTTNG_EVENT_ENABLER_TYPE_COUNTER:
+       {
+               struct lttng_event_enabler_session_common *enabler_session =
+                       caa_container_of(event_enabler, struct lttng_event_enabler_session_common, parent);
+
+               cds_list_del(&enabler_session->node);
+               lttng_destroy_context(enabler_session->ctx);
+               break;
+       }
+       case LTTNG_EVENT_ENABLER_TYPE_NOTIFIER:
+               break;
+       }
+
+       switch (event_enabler->enabler_type) {
+       case LTTNG_EVENT_ENABLER_TYPE_RECORDER:
+       {
+               struct lttng_event_recorder_enabler *recorder_enabler =
+                       caa_container_of(event_enabler, struct lttng_event_recorder_enabler, parent.parent);
+               free(recorder_enabler);
+               break;
+       }
+       case LTTNG_EVENT_ENABLER_TYPE_NOTIFIER:
+       {
+               struct lttng_event_notifier_enabler *notifier_enabler =
+                       caa_container_of(event_enabler, struct lttng_event_notifier_enabler, parent);
 
-       lttng_destroy_context(event_enabler->ctx);
-       free(event_enabler);
+               cds_list_del(&notifier_enabler->node);
+               free(notifier_enabler);
+               break;
+       }
+       case LTTNG_EVENT_ENABLER_TYPE_COUNTER:
+       {
+               struct lttng_event_counter_enabler *counter_enabler =
+                       caa_container_of(event_enabler, struct lttng_event_counter_enabler, parent.parent);
+               free(counter_enabler);
+               break;
+       }
+       }
 }
 
 /*
@@ -1677,17 +2111,17 @@ void lttng_event_enabler_destroy(struct lttng_event_enabler *event_enabler)
 static
 void lttng_session_sync_event_enablers(struct lttng_ust_session *session)
 {
-       struct lttng_event_enabler *event_enabler;
-       struct lttng_ust_event_recorder_private *event_recorder_priv;
+       struct lttng_event_enabler_session_common *event_enabler;
+       struct lttng_ust_event_session_common_private *event_priv;
 
        cds_list_for_each_entry(event_enabler, &session->priv->enablers_head, node)
-               lttng_event_enabler_ref_event_recorders(event_enabler);
+               lttng_event_enabler_ref_events(event_enabler);
        /*
         * For each event, if at least one of its enablers is enabled,
         * and its channel and session transient states are enabled, we
         * enable the event, else we disable it.
         */
-       cds_list_for_each_entry(event_recorder_priv, &session->priv->events_head, node) {
+       cds_list_for_each_entry(event_priv, &session->priv->events_head, node) {
                struct lttng_enabler_ref *enabler_ref;
                struct lttng_ust_bytecode_runtime *runtime;
                int enabled = 0, has_enablers_without_filter_bytecode = 0;
@@ -1695,7 +2129,7 @@ void lttng_session_sync_event_enablers(struct lttng_ust_session *session)
 
                /* Enable events */
                cds_list_for_each_entry(enabler_ref,
-                               &event_recorder_priv->parent.enablers_ref_head, node) {
+                               &event_priv->parent.enablers_ref_head, node) {
                        if (enabler_ref->ref->enabled) {
                                enabled = 1;
                                break;
@@ -1706,40 +2140,40 @@ void lttng_session_sync_event_enablers(struct lttng_ust_session *session)
                 * intesection of session and channel transient enable
                 * states.
                 */
-               enabled = enabled && session->priv->tstate && event_recorder_priv->pub->chan->priv->parent.tstate;
+               enabled = enabled && session->priv->tstate && event_priv->chan->priv->tstate;
 
-               CMM_STORE_SHARED(event_recorder_priv->pub->parent->enabled, enabled);
+               CMM_STORE_SHARED(event_priv->parent.pub->enabled, enabled);
                /*
                 * Sync tracepoint registration with event enabled
                 * state.
                 */
                if (enabled) {
-                       if (!event_recorder_priv->parent.registered)
-                               register_event(event_recorder_priv->parent.pub);
+                       if (!event_priv->parent.registered)
+                               register_event(event_priv->parent.pub);
                } else {
-                       if (event_recorder_priv->parent.registered)
-                               unregister_event(event_recorder_priv->parent.pub);
+                       if (event_priv->parent.registered)
+                               unregister_event(event_priv->parent.pub);
                }
 
                /* Check if has enablers without bytecode enabled */
                cds_list_for_each_entry(enabler_ref,
-                               &event_recorder_priv->parent.enablers_ref_head, node) {
+                               &event_priv->parent.enablers_ref_head, node) {
                        if (enabler_ref->ref->enabled
                                        && cds_list_empty(&enabler_ref->ref->filter_bytecode_head)) {
                                has_enablers_without_filter_bytecode = 1;
                                break;
                        }
                }
-               event_recorder_priv->parent.has_enablers_without_filter_bytecode =
+               event_priv->parent.has_enablers_without_filter_bytecode =
                        has_enablers_without_filter_bytecode;
 
                /* Enable filters */
                cds_list_for_each_entry(runtime,
-                               &event_recorder_priv->parent.filter_bytecode_runtime_head, node) {
+                               &event_priv->parent.filter_bytecode_runtime_head, node) {
                        lttng_bytecode_sync_state(runtime);
                        nr_filters++;
                }
-               CMM_STORE_SHARED(event_recorder_priv->parent.pub->eval_filter,
+               CMM_STORE_SHARED(event_priv->parent.pub->eval_filter,
                        !(has_enablers_without_filter_bytecode || !nr_filters));
        }
        lttng_ust_tp_probe_prune_release_queue();
@@ -1763,6 +2197,7 @@ void lttng_create_event_notifier_if_missing(
                        int ret;
                        bool found = false;
                        const struct lttng_ust_event_desc *desc;
+                       char name[LTTNG_UST_ABI_SYM_NAME_LEN];
                        struct lttng_ust_event_notifier_private *event_notifier_priv;
                        struct cds_hlist_head *head;
                        struct cds_hlist_node *node;
@@ -1778,9 +2213,10 @@ void lttng_create_event_notifier_if_missing(
                         * the target event_notifier would be if it was already
                         * created.
                         */
+                       lttng_ust_format_event_name(desc, name);
                        head = borrow_hash_table_bucket(
                                event_notifier_group->event_notifiers_ht.table,
-                               LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc);
+                               LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, name);
 
                        cds_hlist_for_each_entry(event_notifier_priv, node, head, hlist) {
                                /*
@@ -1789,7 +2225,7 @@ void lttng_create_event_notifier_if_missing(
                                 * description and id.
                                 */
                                if (event_notifier_priv->parent.desc == desc &&
-                                               event_notifier_priv->parent.user_token == event_notifier_enabler->user_token) {
+                                               event_notifier_priv->parent.user_token == event_notifier_enabler->parent.user_token) {
                                        found = true;
                                        break;
                                }
@@ -1802,7 +2238,7 @@ void lttng_create_event_notifier_if_missing(
                         * We need to create a event_notifier for this event probe.
                         */
                        ret = lttng_event_notifier_create(desc,
-                               event_notifier_enabler->user_token,
+                               event_notifier_enabler->parent.user_token,
                                event_notifier_enabler->error_counter_index,
                                event_notifier_group);
                        if (ret) {
@@ -1989,7 +2425,7 @@ void lttng_ust_context_set_session_provider(const char *name,
 
        cds_list_for_each_entry(session_priv, &sessions, node) {
                struct lttng_ust_channel_buffer_private *chan;
-               struct lttng_ust_event_recorder_private *event_recorder_priv;
+               struct lttng_ust_event_session_common_private *event_priv;
                int ret;
 
                ret = lttng_ust_context_set_provider_rcu(&session_priv->ctx,
@@ -2002,8 +2438,8 @@ void lttng_ust_context_set_session_provider(const char *name,
                        if (ret)
                                abort();
                }
-               cds_list_for_each_entry(event_recorder_priv, &session_priv->events_head, node) {
-                       ret = lttng_ust_context_set_provider_rcu(&event_recorder_priv->ctx,
+               cds_list_for_each_entry(event_priv, &session_priv->events_head, node) {
+                       ret = lttng_ust_context_set_provider_rcu(&event_priv->ctx,
                                        name, get_size, record, get_value);
                        if (ret)
                                abort();
index 2a8b8c09c8c17bc7a03b9adbd1c79ea6a948be03..d71a818d0313668cd9b3f6b5dbb6aa4a9e4d44bb 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "common/ust-fd.h"
 #include "common/logging.h"
+#include "common/align.h"
 
 #include "common/ringbuffer/frontend_types.h"
 #include "common/ringbuffer/frontend.h"
@@ -275,6 +276,7 @@ static const struct lttng_ust_abi_objd_ops lttng_ops;
 static const struct lttng_ust_abi_objd_ops lttng_event_notifier_group_ops;
 static const struct lttng_ust_abi_objd_ops lttng_session_ops;
 static const struct lttng_ust_abi_objd_ops lttng_channel_ops;
+static const struct lttng_ust_abi_objd_ops lttng_counter_ops;
 static const struct lttng_ust_abi_objd_ops lttng_event_enabler_ops;
 static const struct lttng_ust_abi_objd_ops lttng_event_notifier_enabler_ops;
 static const struct lttng_ust_abi_objd_ops lttng_tracepoint_list_ops;
@@ -599,6 +601,143 @@ invalid:
        return ret;
 }
 
+static
+bool check_zero(const char *p, size_t len)
+{
+       size_t i;
+
+       for (i = 0; i < len; i++) {
+               if (p[i] != 0)
+                       return false;
+       }
+       return true;
+}
+
+static
+int copy_abi_struct(void *dst_struct, size_t dst_struct_len,
+               const void *src_struct, size_t src_struct_len)
+{
+       if (dst_struct_len >= src_struct_len) {
+               memcpy(dst_struct, src_struct, src_struct_len);
+               if (dst_struct_len > src_struct_len)
+                       memset(dst_struct + src_struct_len, 0, dst_struct_len - src_struct_len);
+       } else {        /* dst_struct_len < src_struct_len */
+               /* Validate zero-padding. */
+               if (!check_zero(src_struct + dst_struct_len, src_struct_len - dst_struct_len))
+                       return -E2BIG;
+               memcpy(dst_struct, src_struct, dst_struct_len);
+       }
+       return 0;
+}
+
+static
+long lttng_session_create_counter(
+               int session_objd,
+               struct lttng_ust_abi_counter *ust_counter,
+               union lttng_ust_abi_args *uargs,
+               void *owner)
+{
+       struct lttng_ust_session *session = objd_private(session_objd);
+       int counter_objd, ret;
+       const char *counter_transport_name;
+       struct lttng_ust_channel_counter *counter = NULL;
+       struct lttng_counter_dimension dimensions[1] = {};
+       size_t number_dimensions = 1;
+       const struct lttng_ust_abi_counter_conf *abi_counter_conf;
+       struct lttng_ust_abi_counter_conf counter_conf;
+       uint32_t min_expected_len = lttng_ust_offsetofend(struct lttng_ust_abi_counter_conf, elem_len);
+       const struct lttng_ust_abi_counter_dimension *abi_dimension;
+       struct lttng_ust_abi_counter_dimension dimension;
+
+       if (ust_counter->len < min_expected_len) {
+               ERR("LTTng: Map: Counter configuration of wrong size.");
+               return -EINVAL;
+       }
+       abi_counter_conf = uargs->counter.counter_data;
+       if (abi_counter_conf->len > ust_counter->len || abi_counter_conf->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_conf, elem_len)) {
+               return -EINVAL;
+       }
+       ret = copy_abi_struct(&counter_conf, sizeof(counter_conf), abi_counter_conf, abi_counter_conf->len);
+       if (ret) {
+               ERR("Unexpected counter configuration structure content");
+               return ret;
+       }
+       if (counter_conf.number_dimensions != 1) {
+               ERR("LTTng: Map: Unsupprted number of dimensions %u.", counter_conf.number_dimensions);
+               return -EINVAL;
+       }
+       if (counter_conf.elem_len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_dimension, overflow_index)) {
+               ERR("Unexpected dimension array element length %u.", counter_conf.elem_len);
+               return -EINVAL;
+       }
+       if (counter_conf.len + counter_conf.elem_len > ust_counter->len) {
+               return -EINVAL;
+       }
+       abi_dimension = (const struct lttng_ust_abi_counter_dimension *)(((char *)abi_counter_conf) + counter_conf.len);
+       ret = copy_abi_struct(&dimension, sizeof(dimension), abi_dimension, counter_conf.elem_len);
+       if (ret) {
+               ERR("Unexpected dimension structure content");
+               return ret;
+       }
+       if (counter_conf.arithmetic != LTTNG_UST_ABI_COUNTER_ARITHMETIC_MODULAR) {
+               ERR("LTTng: Map: Counter of the wrong type.");
+               return -EINVAL;
+       }
+       if (counter_conf.global_sum_step) {
+               /* Unsupported. */
+               return -EINVAL;
+       }
+       switch (counter_conf.bitness) {
+       case LTTNG_UST_ABI_COUNTER_BITNESS_64:
+               counter_transport_name = "counter-per-cpu-64-modular";
+               break;
+       case LTTNG_UST_ABI_COUNTER_BITNESS_32:
+               counter_transport_name = "counter-per-cpu-32-modular";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dimensions[0].size = dimension.size;
+       dimensions[0].underflow_index = dimension.underflow_index;
+       dimensions[0].overflow_index = dimension.overflow_index;
+       dimensions[0].has_underflow = dimension.flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW;
+       dimensions[0].has_overflow = dimension.flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW;
+
+       counter_objd = objd_alloc(NULL, &lttng_counter_ops, owner, "counter");
+       if (counter_objd < 0) {
+               ret = counter_objd;
+               goto objd_error;
+       }
+
+       counter = lttng_ust_counter_create(counter_transport_name,
+                       number_dimensions, dimensions,
+                       0, counter_conf.flags & LTTNG_UST_ABI_COUNTER_CONF_FLAG_COALESCE_HITS);
+       if (!counter) {
+               ret = -EINVAL;
+               goto counter_error;
+       }
+       counter->parent->session = session;
+       cds_list_add(&counter->priv->node, &session->priv->counters_head);
+       objd_set_private(counter_objd, counter);
+       counter->priv->parent.objd = counter_objd;
+       counter->priv->parent.tstate = 1;
+       counter->parent->enabled = 1;
+       /* The channel created holds a reference on the session */
+       objd_ref(session_objd);
+       return counter_objd;
+
+counter_error:
+       {
+               int err;
+
+               err = lttng_ust_abi_objd_unref(counter_objd, 1);
+               assert(!err);
+       }
+objd_error:
+       return ret;
+}
+
 /**
  *     lttng_session_cmd - lttng session object command
  *
@@ -638,10 +777,9 @@ long lttng_session_cmd(int objd, unsigned int cmd, unsigned long arg,
        case LTTNG_UST_ABI_SESSION_STATEDUMP:
                return lttng_session_statedump(session);
        case LTTNG_UST_ABI_COUNTER:
-       case LTTNG_UST_ABI_COUNTER_GLOBAL:
-       case LTTNG_UST_ABI_COUNTER_CPU:
-               /* Not implemented yet. */
-               return -EINVAL;
+               return lttng_session_create_counter(objd,
+                       (struct lttng_ust_abi_counter *) arg,
+                       uargs, owner);
        default:
                return -EINVAL;
        }
@@ -761,7 +899,7 @@ long lttng_event_notifier_group_error_counter_cmd(int objd, unsigned int cmd, un
        union lttng_ust_abi_args *uargs, void *owner __attribute__((unused)))
 {
        int ret;
-       struct lttng_counter *counter = objd_private(objd);
+       struct lttng_ust_channel_counter *counter = objd_private(objd);
 
        switch (cmd) {
        case LTTNG_UST_ABI_COUNTER_GLOBAL:
@@ -769,11 +907,19 @@ long lttng_event_notifier_group_error_counter_cmd(int objd, unsigned int cmd, un
                break;
        case LTTNG_UST_ABI_COUNTER_CPU:
        {
-               struct lttng_ust_abi_counter_cpu *counter_cpu =
-                       (struct lttng_ust_abi_counter_cpu *)arg;
+               struct lttng_ust_abi_counter_cpu *abi_counter_cpu =
+                       (struct lttng_ust_abi_counter_cpu *) arg;
+               struct lttng_ust_abi_counter_cpu counter_cpu;
 
-               ret = lttng_counter_set_cpu_shm(counter->counter,
-                       counter_cpu->cpu_nr, uargs->counter_shm.shm_fd);
+               if (abi_counter_cpu->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_cpu, cpu_nr)) {
+                       return -EINVAL;
+               }
+               ret = copy_abi_struct(&counter_cpu, sizeof(counter_cpu),
+                               abi_counter_cpu, abi_counter_cpu->len);
+               if (ret)
+                       return ret;
+               ret = lttng_counter_set_cpu_shm(counter->priv->counter,
+                       counter_cpu.cpu_nr, uargs->counter_shm.shm_fd);
                if (!ret) {
                        /* Take ownership of the shm_fd. */
                        uargs->counter_shm.shm_fd = -1;
@@ -792,10 +938,10 @@ int lttng_release_event_notifier_group_error_counter(int objd)
        __attribute__((visibility("hidden")));
 int lttng_release_event_notifier_group_error_counter(int objd)
 {
-       struct lttng_counter *counter = objd_private(objd);
+       struct lttng_ust_channel_counter *counter = objd_private(objd);
 
        if (counter) {
-               return lttng_ust_abi_objd_unref(counter->event_notifier_group->objd, 0);
+               return lttng_ust_abi_objd_unref(counter->priv->event_notifier_group->objd, 0);
        } else {
                return -EINVAL;
        }
@@ -807,27 +953,66 @@ static const struct lttng_ust_abi_objd_ops lttng_event_notifier_group_error_coun
 };
 
 static
-int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group_objd, void *owner,
-               struct lttng_ust_abi_counter_conf *error_counter_conf)
+int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group_objd,
+               struct lttng_ust_abi_counter *ust_counter,
+               union lttng_ust_abi_args *uargs,
+               void *owner)
 {
        const char *counter_transport_name;
        struct lttng_event_notifier_group *event_notifier_group =
                objd_private(event_notifier_group_objd);
-       struct lttng_counter *counter;
+       struct lttng_ust_channel_counter *counter;
        int counter_objd, ret;
-       struct lttng_counter_dimension dimensions[1];
        size_t counter_len;
+       struct lttng_counter_dimension dimensions[1] = {};
+       const struct lttng_ust_abi_counter_conf *abi_counter_conf;
+       struct lttng_ust_abi_counter_conf counter_conf;
+       uint32_t min_expected_len = lttng_ust_offsetofend(struct lttng_ust_abi_counter_conf, elem_len);
+       const struct lttng_ust_abi_counter_dimension *abi_dimension;
+       struct lttng_ust_abi_counter_dimension dimension;
 
        if (event_notifier_group->error_counter)
                return -EBUSY;
 
-       if (error_counter_conf->arithmetic != LTTNG_UST_ABI_COUNTER_ARITHMETIC_MODULAR)
+       if (ust_counter->len < min_expected_len) {
+               ERR("LTTng: Counter configuration of wrong size.");
                return -EINVAL;
-
-       if (error_counter_conf->number_dimensions != 1)
+       }
+       abi_counter_conf = uargs->counter.counter_data;
+       if (abi_counter_conf->len > ust_counter->len || abi_counter_conf->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_conf, elem_len)) {
                return -EINVAL;
-
-       switch (error_counter_conf->bitness) {
+       }
+       ret = copy_abi_struct(&counter_conf, sizeof(counter_conf), abi_counter_conf, abi_counter_conf->len);
+       if (ret) {
+               ERR("Unexpected counter configuration structure content");
+               return ret;
+       }
+       if (counter_conf.number_dimensions != 1) {
+               ERR("LTTng: Map: Unsupprted number of dimensions %u.", counter_conf.number_dimensions);
+               return -EINVAL;
+       }
+       if (counter_conf.elem_len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_dimension, overflow_index)) {
+               ERR("Unexpected dimension array element length %u.", counter_conf.elem_len);
+               return -EINVAL;
+       }
+       if (counter_conf.len + counter_conf.elem_len > ust_counter->len) {
+               return -EINVAL;
+       }
+       abi_dimension = (const struct lttng_ust_abi_counter_dimension *)(((char *)abi_counter_conf) + counter_conf.len);
+       ret = copy_abi_struct(&dimension, sizeof(dimension), abi_dimension, counter_conf.elem_len);
+       if (ret) {
+               ERR("Unexpected dimension structure content");
+               return ret;
+       }
+       if (counter_conf.arithmetic != LTTNG_UST_ABI_COUNTER_ARITHMETIC_MODULAR) {
+               ERR("LTTng: Counter of the wrong type.");
+               return -EINVAL;
+       }
+       if (counter_conf.global_sum_step) {
+               /* Unsupported. */
+               return -EINVAL;
+       }
+       switch (counter_conf.bitness) {
        case LTTNG_UST_ABI_COUNTER_BITNESS_64:
                counter_transport_name = "counter-per-cpu-64-modular";
                break;
@@ -838,6 +1023,13 @@ int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group
                return -EINVAL;
        }
 
+       counter_len = dimension.size;
+       dimensions[0].size = counter_len;
+       dimensions[0].underflow_index = dimension.underflow_index;
+       dimensions[0].overflow_index = dimension.overflow_index;
+       dimensions[0].has_underflow = dimension.flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW;
+       dimensions[0].has_overflow = dimension.flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW;
+
        counter_objd = objd_alloc(NULL, &lttng_event_notifier_group_error_counter_ops, owner,
                "event_notifier group error counter");
        if (counter_objd < 0) {
@@ -845,14 +1037,7 @@ int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group
                goto objd_error;
        }
 
-       counter_len = error_counter_conf->dimensions[0].size;
-       dimensions[0].size = counter_len;
-       dimensions[0].underflow_index = 0;
-       dimensions[0].overflow_index = 0;
-       dimensions[0].has_underflow = 0;
-       dimensions[0].has_overflow = 0;
-
-       counter = lttng_ust_counter_create(counter_transport_name, 1, dimensions);
+       counter = lttng_ust_counter_create(counter_transport_name, 1, dimensions, 0, false);
        if (!counter) {
                ret = -EINVAL;
                goto create_error;
@@ -869,8 +1054,8 @@ int lttng_ust_event_notifier_group_create_error_counter(int event_notifier_group
        cmm_smp_mb();
        CMM_STORE_SHARED(event_notifier_group->error_counter, counter);
 
-       counter->objd = counter_objd;
-       counter->event_notifier_group = event_notifier_group;   /* owner */
+       counter->priv->parent.objd = counter_objd;
+       counter->priv->event_notifier_group = event_notifier_group;     /* owner */
 
        objd_set_private(counter_objd, counter);
        /* The error counter holds a reference on the event_notifier group. */
@@ -914,10 +1099,8 @@ long lttng_event_notifier_group_cmd(int objd, unsigned int cmd, unsigned long ar
        }
        case LTTNG_UST_ABI_COUNTER:
        {
-               struct lttng_ust_abi_counter_conf *counter_conf =
-                       (struct lttng_ust_abi_counter_conf *) uargs->counter.counter_data;
                return lttng_ust_event_notifier_group_create_error_counter(
-                               objd, owner, counter_conf);
+                               objd, (struct lttng_ust_abi_counter *) arg, uargs, owner);
        }
        default:
                return -EINVAL;
@@ -1142,13 +1325,57 @@ error_add_stream:
 }
 
 static
-int lttng_abi_create_event_enabler(int channel_objd,
-                          struct lttng_ust_abi_event *event_param,
-                          void *owner,
-                          enum lttng_enabler_format_type format_type)
+int lttng_abi_create_event_recorder_enabler(int channel_objd,
+                       struct lttng_ust_channel_buffer *channel,
+                       struct lttng_ust_abi_event *event_param,
+                       void *owner,
+                       enum lttng_enabler_format_type format_type)
+{
+       struct lttng_event_recorder_enabler *enabler;
+       int event_objd, ret;
+
+       event_param->name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0';
+       event_objd = objd_alloc(NULL, &lttng_event_enabler_ops, owner,
+               "event recorder enabler");
+       if (event_objd < 0) {
+               ret = event_objd;
+               goto objd_error;
+       }
+       /*
+        * We tolerate no failure path after event creation. It will stay
+        * invariant for the rest of the session.
+        */
+       enabler = lttng_event_recorder_enabler_create(format_type, event_param,
+                       channel);
+       if (!enabler) {
+               ret = -ENOMEM;
+               goto event_error;
+       }
+       objd_set_private(event_objd, &enabler->parent);
+       /* The event holds a reference on the channel */
+       objd_ref(channel_objd);
+       return event_objd;
+
+event_error:
+       {
+               int err;
+
+               err = lttng_ust_abi_objd_unref(event_objd, 1);
+               assert(!err);
+       }
+objd_error:
+       return ret;
+}
+
+static
+int lttng_abi_create_event_counter_enabler(int channel_objd,
+                       struct lttng_ust_channel_counter *channel,
+                       struct lttng_ust_abi_event *event_param,
+                       const struct lttng_ust_abi_counter_key *key_param,
+                       void *owner,
+                       enum lttng_enabler_format_type format_type)
 {
-       struct lttng_ust_channel_buffer *channel = objd_private(channel_objd);
-       struct lttng_event_enabler *enabler;
+       struct lttng_event_counter_enabler *enabler;
        int event_objd, ret;
 
        event_param->name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0';
@@ -1162,12 +1389,13 @@ int lttng_abi_create_event_enabler(int channel_objd,
         * We tolerate no failure path after event creation. It will stay
         * invariant for the rest of the session.
         */
-       enabler = lttng_event_enabler_create(format_type, event_param, channel);
+       enabler = lttng_event_counter_enabler_create(format_type, event_param,
+                       key_param, channel);
        if (!enabler) {
                ret = -ENOMEM;
                goto event_error;
        }
-       objd_set_private(event_objd, enabler);
+       objd_set_private(event_objd, &enabler->parent);
        /* The event holds a reference on the channel */
        objd_ref(channel_objd);
        return event_objd;
@@ -1240,11 +1468,13 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg,
                         * If the event name is a star globbing pattern,
                         * we create the special star globbing enabler.
                         */
-                       return lttng_abi_create_event_enabler(objd, event_param,
-                                       owner, LTTNG_ENABLER_FORMAT_STAR_GLOB);
+                       return lttng_abi_create_event_recorder_enabler(objd, lttng_chan_buf,
+                                       event_param, owner,
+                                       LTTNG_ENABLER_FORMAT_STAR_GLOB);
                } else {
-                       return lttng_abi_create_event_enabler(objd, event_param,
-                                       owner, LTTNG_ENABLER_FORMAT_EVENT);
+                       return lttng_abi_create_event_recorder_enabler(objd, lttng_chan_buf,
+                                       event_param, owner,
+                                       LTTNG_ENABLER_FORMAT_EVENT);
                }
        }
        case LTTNG_UST_ABI_CONTEXT:
@@ -1278,6 +1508,137 @@ static const struct lttng_ust_abi_objd_ops lttng_channel_ops = {
        .cmd = lttng_channel_cmd,
 };
 
+/**
+ *     lttng_counter_cmd - lttng control through object descriptors
+ *
+ *     @objd: the object descriptor
+ *     @cmd: the command
+ *     @arg: command arg
+ *     @uargs: UST arguments (internal)
+ *     @owner: objd owner
+ *
+ *     This object descriptor implements lttng commands:
+ *      LTTNG_UST_ABI_COUNTER_GLOBAL:
+ *              Returns a global counter object descriptor or failure.
+ *      LTTNG_UST_ABI_COUNTER_CPU:
+ *              Returns a per-cpu counter object descriptor or failure.
+ *     LTTNG_UST_ABI_COUNTER_EVENT
+ *             Returns an event object descriptor or failure.
+ *     LTTNG_UST_ABI_ENABLE
+ *             Enable recording for events in this channel (weak enable)
+ *     LTTNG_UST_ABI_DISABLE
+ *             Disable recording for events in this channel (strong disable)
+ *
+ * Counter and event object descriptors also hold a reference on the session.
+ */
+static
+long lttng_counter_cmd(int objd, unsigned int cmd, unsigned long arg,
+       union lttng_ust_abi_args *uargs, void *owner)
+{
+       struct lttng_ust_channel_counter *counter = objd_private(objd);
+
+       if (cmd != LTTNG_UST_ABI_COUNTER_GLOBAL && cmd != LTTNG_UST_ABI_COUNTER_CPU) {
+               /*
+                * Check if counter received all global/per-cpu objects.
+                */
+               if (!lttng_counter_ready(counter->priv->counter))
+                       return -EPERM;
+       }
+
+       switch (cmd) {
+       case LTTNG_UST_ABI_COUNTER_GLOBAL:
+       {
+               struct lttng_ust_abi_counter_global *abi_counter_global =
+                       (struct lttng_ust_abi_counter_global *) arg;
+               struct lttng_ust_abi_counter_global counter_global;
+               long ret;
+               int shm_fd;
+
+               if (abi_counter_global->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_global, shm_len)) {
+                       return -EINVAL;
+               }
+               ret = copy_abi_struct(&counter_global, sizeof(counter_global),
+                               abi_counter_global, abi_counter_global->len);
+               if (ret)
+                       return ret;
+               shm_fd = uargs->counter_shm.shm_fd;
+               ret = lttng_counter_set_global_shm(counter->priv->counter, shm_fd);
+               if (!ret) {
+                       /* Take ownership of shm_fd. */
+                       uargs->counter_shm.shm_fd = -1;
+               }
+               return ret;
+       }
+       case LTTNG_UST_ABI_COUNTER_CPU:
+       {
+               struct lttng_ust_abi_counter_cpu *abi_counter_cpu =
+                       (struct lttng_ust_abi_counter_cpu *) arg;
+               struct lttng_ust_abi_counter_cpu counter_cpu;
+               long ret;
+               int shm_fd;
+
+               if (abi_counter_cpu->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_cpu, cpu_nr)) {
+                       return -EINVAL;
+               }
+               ret = copy_abi_struct(&counter_cpu, sizeof(counter_cpu),
+                               abi_counter_cpu, abi_counter_cpu->len);
+               if (ret)
+                       return ret;
+               shm_fd = uargs->counter_shm.shm_fd;
+               ret = lttng_counter_set_cpu_shm(counter->priv->counter,
+                               counter_cpu.cpu_nr, shm_fd);
+               if (!ret) {
+                       /* Take ownership of shm_fd. */
+                       uargs->counter_shm.shm_fd = -1;
+               }
+               return ret;
+       }
+       case LTTNG_UST_ABI_COUNTER_EVENT:
+       {
+               struct lttng_ust_abi_counter_event *counter_event_param =
+                       (struct lttng_ust_abi_counter_event *) arg;
+               struct lttng_ust_abi_event *event_param = &counter_event_param->event;
+               struct lttng_ust_abi_counter_key *key_param = &counter_event_param->key;
+
+               if (strutils_is_star_glob_pattern(event_param->name)) {
+                       /*
+                        * If the event name is a star globbing pattern,
+                        * we create the special star globbing enabler.
+                        */
+                       return lttng_abi_create_event_counter_enabler(objd, counter,
+                                       event_param, key_param, owner,
+                                       LTTNG_ENABLER_FORMAT_STAR_GLOB);
+               } else {
+                       return lttng_abi_create_event_counter_enabler(objd, counter,
+                                       event_param, key_param, owner,
+                                       LTTNG_ENABLER_FORMAT_EVENT);
+               }
+       }
+       case LTTNG_UST_ABI_ENABLE:
+               return lttng_channel_enable(counter->parent);
+       case LTTNG_UST_ABI_DISABLE:
+               return lttng_channel_disable(counter->parent);
+       default:
+               return -EINVAL;
+       }
+}
+
+static
+int lttng_counter_release(int objd)
+{
+       struct lttng_ust_channel_counter *counter = objd_private(objd);
+
+       if (counter) {
+               return lttng_ust_abi_objd_unref(counter->parent->session->priv->objd, 0);
+       }
+       return 0;
+}
+
+static const struct lttng_ust_abi_objd_ops lttng_counter_ops = {
+       .release = lttng_counter_release,
+       .cmd = lttng_counter_cmd,
+};
+
 /**
  *     lttng_enabler_cmd - lttng control through object descriptors
  *
@@ -1305,7 +1666,7 @@ long lttng_event_enabler_cmd(int objd, unsigned int cmd, unsigned long arg,
        union lttng_ust_abi_args *uargs __attribute__((unused)),
        void *owner __attribute__((unused)))
 {
-       struct lttng_event_enabler *enabler = objd_private(objd);
+       struct lttng_event_enabler_session_common *enabler = objd_private(objd);
 
        switch (cmd) {
        case LTTNG_UST_ABI_CONTEXT:
@@ -1338,7 +1699,7 @@ long lttng_event_enabler_cmd(int objd, unsigned int cmd, unsigned long arg,
 static
 int lttng_event_enabler_release(int objd)
 {
-       struct lttng_event_enabler *event_enabler = objd_private(objd);
+       struct lttng_event_recorder_enabler *event_enabler = objd_private(objd);
 
        if (event_enabler)
                return lttng_ust_abi_objd_unref(event_enabler->chan->priv->parent.objd, 0);
index 9745c18246690b35e778cb19b5e593452cb5e141..423cedbcd7104602a47b63404cf451c75bf48476 100644 (file)
@@ -388,6 +388,7 @@ static const char *cmd_name_mapping[] = {
        /* Counter commands */
        [ LTTNG_UST_ABI_COUNTER_GLOBAL ] = "Create Counter Global",
        [ LTTNG_UST_ABI_COUNTER_CPU ] = "Create Counter CPU",
+       [ LTTNG_UST_ABI_COUNTER_EVENT ] = "Create Counter Event",
 };
 
 static const char *str_timeout;
@@ -1094,6 +1095,7 @@ int handle_message(struct sock_info *sock_info,
        case LTTNG_UST_ABI_COUNTER:
        case LTTNG_UST_ABI_COUNTER_GLOBAL:
        case LTTNG_UST_ABI_COUNTER_CPU:
+       case LTTNG_UST_ABI_COUNTER_EVENT:
        case LTTNG_UST_ABI_EVENT_NOTIFIER_CREATE:
        case LTTNG_UST_ABI_EVENT_NOTIFIER_GROUP_CREATE:
                /*
@@ -1481,6 +1483,48 @@ int handle_message(struct sock_info *sock_info,
                }
                break;
        }
+       case LTTNG_UST_ABI_COUNTER_EVENT:
+       {
+               /* Receive struct lttng_ust_abi_counter_event */
+               struct lttng_ust_abi_counter_event counter_event;
+
+               if (sizeof(counter_event) != lum->u.counter_event.len) {
+                       DBG("incorrect counter event data message size: %u", lum->u.counter_event.len);
+                       ret = -EINVAL;
+                       goto error;
+               }
+               len = ustcomm_recv_unix_sock(sock, &counter_event, sizeof(counter_event));
+               switch (len) {
+               case 0: /* orderly shutdown */
+                       ret = 0;
+                       goto error;
+               default:
+                       if (len == sizeof(counter_event)) {
+                               DBG("counter event data received");
+                               break;
+                       } else if (len < 0) {
+                               DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+                               if (len == -ECONNRESET) {
+                                       ERR("%s remote end closed connection", sock_info->name);
+                                       ret = len;
+                                       goto error;
+                               }
+                               ret = len;
+                               goto error;
+                       } else {
+                               DBG("incorrect event notifier data message size: %zd", len);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
+               if (ops->cmd)
+                       ret = ops->cmd(lum->handle, lum->cmd,
+                                       (unsigned long) &counter_event,
+                                       &args, sock_info);
+               else
+                       ret = -ENOSYS;
+               break;
+       }
        case LTTNG_UST_ABI_EVENT_NOTIFIER_CREATE:
        {
                /* Receive struct lttng_ust_event_notifier */
This page took 0.076809 seconds and 4 git commands to generate.