# 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)
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 {
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 {
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
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
*/
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 */
/*
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);
enum lttng_ust_event_type {
LTTNG_UST_EVENT_TYPE_RECORDER = 0,
LTTNG_UST_EVENT_TYPE_NOTIFIER = 1,
+ LTTNG_UST_EVENT_TYPE_COUNTER = 2,
};
/*
/* 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
enum lttng_ust_channel_type {
LTTNG_UST_CHANNEL_TYPE_BUFFER = 0,
+ LTTNG_UST_CHANNEL_TYPE_COUNTER = 1,
};
struct lttng_ust_channel_common_private;
/* 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
*/
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
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; \
\
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))) { \
&__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; \
+ } \
} \
}
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) {
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();
}
.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,
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;
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,
};
.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,
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;
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,
};
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;
};
{
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;
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
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)
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,
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,
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 */
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.
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;
};
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;
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.
*/
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
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;
};
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;
};
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;
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 ? */
};
int objd; /* Object associated with channel. */
unsigned int tstate:1; /* Transient enable state */
+ bool coalesce_hits;
};
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
})
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;
}
#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 */
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);
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")));
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <lttng/ust-ctl.h>
#include "common/ustcomm.h"
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 {
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;
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) {
/* 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));
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;
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));
/* 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
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")));
/*
* 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 */
};
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);
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;
*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;
* 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;
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;
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)
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;
}
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) {
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) {
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);
}
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;
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)
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);
}
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,
{
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;
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);
}
#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")));
/*
* 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")));
*
* 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")));
* 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")));
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.
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
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)
{
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)
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);
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)
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)
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) {
}
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;
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);
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:
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;
}
{
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;
* 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) {
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;
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;
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:
}
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;
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;
* 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;
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);
}
}
}
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;
* 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;
}
}
* 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) {
{
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;
* 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.
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. */
}
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);
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();
}
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;
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,
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;
*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;
*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;
}
}
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;
+ }
+ }
}
/*
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;
/* 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;
* 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();
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;
* 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) {
/*
* 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;
}
* 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) {
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,
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();
#include "common/ust-fd.h"
#include "common/logging.h"
+#include "common/align.h"
#include "common/ringbuffer/frontend_types.h"
#include "common/ringbuffer/frontend.h"
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;
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
*
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;
}
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:
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;
__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;
}
};
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;
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) {
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;
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. */
}
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;
}
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';
* 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;
* 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:
.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
*
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:
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);
/* 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;
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:
/*
}
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 */