From b187bcd5d99cde54dececee0e5028524d55aa314 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 17 May 2021 10:27:53 -0400 Subject: [PATCH] Implement Trace Hit Counters Signed-off-by: Mathieu Desnoyers Change-Id: If1f29dd64538bc5979d3e89aa5cca3be4e41046f --- configure.ac | 2 +- include/lttng/ust-abi.h | 79 +- include/lttng/ust-ctl.h | 11 +- include/lttng/ust-events.h | 95 ++ include/lttng/ust-tracepoint-event.h | 29 +- src/common/core.c | 45 + .../counter-clients/percpu-32-modular.c | 64 +- .../counter-clients/percpu-64-modular.c | 64 +- src/common/counter/counter-types.h | 3 + src/common/counter/counter.c | 20 +- src/common/counter/counter.h | 6 + src/common/events.h | 203 ++-- src/common/macros.h | 3 + src/common/ringbuffer-clients/template.h | 2 +- src/common/tracer.h | 3 + src/common/ustcomm.c | 15 +- src/common/ustcomm.h | 25 +- src/lib/lttng-ust-ctl/ustctl.c | 157 +++- .../lttng-ust/event-notifier-notification.c | 6 +- src/lib/lttng-ust/events.h | 49 +- src/lib/lttng-ust/lttng-events.c | 872 +++++++++++++----- src/lib/lttng-ust/lttng-ust-abi.c | 455 ++++++++- src/lib/lttng-ust/lttng-ust-comm.c | 44 + 23 files changed, 1764 insertions(+), 488 deletions(-) diff --git a/configure.ac b/configure.ac index 05c343b7..8076531f 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 1fb8d881..936d31c7 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -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 diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 86aa6ef7..e244b997 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -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); diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 4088157f..36304bc4 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -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 diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index 5d845ae1..1a7ea744 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -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; \ + } \ } \ } diff --git a/src/common/core.c b/src/common/core.c index 8ea3e34a..a68f2dd0 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -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 = <tng_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(); } diff --git a/src/common/counter-clients/percpu-32-modular.c b/src/common/counter-clients/percpu-32-modular.c index 3635e5f3..9d0add6f 100644 --- a/src/common/counter-clients/percpu-32-modular.c +++ b/src/common/counter-clients/percpu-32-modular.c @@ -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 = <tng_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, }; diff --git a/src/common/counter-clients/percpu-64-modular.c b/src/common/counter-clients/percpu-64-modular.c index 2aee4197..98509b34 100644 --- a/src/common/counter-clients/percpu-64-modular.c +++ b/src/common/counter-clients/percpu-64-modular.c @@ -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 = <tng_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, }; diff --git a/src/common/counter/counter-types.h b/src/common/counter/counter-types.h index 2b71c93b..ce0a319a 100644 --- a/src/common/counter/counter-types.h +++ b/src/common/counter/counter-types.h @@ -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; }; diff --git a/src/common/counter/counter.c b/src/common/counter/counter.c index 4f2ac4c8..250701fc 100644 --- a/src/common/counter/counter.c +++ b/src/common/counter/counter.c @@ -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, diff --git a/src/common/counter/counter.h b/src/common/counter/counter.h index aa86f158..e4822ffa 100644 --- a/src/common/counter/counter.h +++ b/src/common/counter/counter.h @@ -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, diff --git a/src/common/events.h b/src/common/events.h index 308e97a2..bc085ffc 100644 --- a/src/common/events.h +++ b/src/common/events.h @@ -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; } diff --git a/src/common/macros.h b/src/common/macros.h index e8965b38..add315ea 100644 --- a/src/common/macros.h +++ b/src/common/macros.h @@ -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 */ diff --git a/src/common/ringbuffer-clients/template.h b/src/common/ringbuffer-clients/template.h index 58a8400d..98cc9ef5 100644 --- a/src/common/ringbuffer-clients/template.h +++ b/src/common/ringbuffer-clients/template.h @@ -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); diff --git a/src/common/tracer.h b/src/common/tracer.h index 8e18c9b5..60d74814 100644 --- a/src/common/tracer.h +++ b/src/common/tracer.h @@ -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"))); diff --git a/src/common/ustcomm.c b/src/common/ustcomm.c index 47f228b1..33515656 100644 --- a/src/common/ustcomm.c +++ b/src/common/ustcomm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #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) { diff --git a/src/common/ustcomm.h b/src/common/ustcomm.h index d1e9af13..4bdc8a50 100644 --- a/src/common/ustcomm.h +++ b/src/common/ustcomm.h @@ -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"))); /* diff --git a/src/lib/lttng-ust-ctl/ustctl.c b/src/lib/lttng-ust-ctl/ustctl.c index 7b679880..3a2e58f6 100644 --- a/src/lib/lttng-ust-ctl/ustctl.c +++ b/src/lib/lttng-ust-ctl/ustctl.c @@ -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, diff --git a/src/lib/lttng-ust/event-notifier-notification.c b/src/lib/lttng-ust/event-notifier-notification.c index 6cb93848..9b52e0d9 100644 --- a/src/lib/lttng-ust/event-notifier-notification.c +++ b/src/lib/lttng-ust/event-notifier-notification.c @@ -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); } diff --git a/src/lib/lttng-ust/events.h b/src/lib/lttng-ust/events.h index cfdbd2e0..093d8d09 100644 --- a/src/lib/lttng-ust/events.h +++ b/src/lib/lttng-ust/events.h @@ -10,35 +10,48 @@ #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 diff --git a/src/lib/lttng-ust/lttng-events.c b/src/lib/lttng-ust/lttng-events.c index 320d459e..69a6c7b4 100644 --- a/src/lib/lttng-ust/lttng-events.c +++ b/src/lib/lttng-ust/lttng-events.c @@ -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(¬ifier_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, - <tng_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(¬ifier_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(); diff --git a/src/lib/lttng-ust/lttng-ust-abi.c b/src/lib/lttng-ust/lttng-ust-abi.c index 2a8b8c09..d71a818d 100644 --- a/src/lib/lttng-ust/lttng-ust-abi.c +++ b/src/lib/lttng-ust/lttng-ust-abi.c @@ -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, <tng_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, <tng_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, <tng_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); diff --git a/src/lib/lttng-ust/lttng-ust-comm.c b/src/lib/lttng-ust/lttng-ust-comm.c index 9745c182..423cedbc 100644 --- a/src/lib/lttng-ust/lttng-ust-comm.c +++ b/src/lib/lttng-ust/lttng-ust-comm.c @@ -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 */ -- 2.34.1