--- /dev/null
+Trace hit counter
*/
} LTTNG_PACKED;
+#define LTTNG_UST_EVENT_PADDING1 8
+#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
+struct lttng_ust_event {
+ enum lttng_ust_instrumentation instrumentation;
+ char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */
+
+ enum lttng_ust_loglevel_type loglevel_type;
+ int loglevel; /* value, -1: all */
+ uint64_t token; /* User-provided token */
+ char padding[LTTNG_UST_EVENT_PADDING1];
+
+ /* Per instrumentation type configuration */
+ union {
+ char padding[LTTNG_UST_EVENT_PADDING2];
+ } u;
+} LTTNG_PACKED;
+
+#define LTTNG_UST_EVENT_NOTIFIER_PADDING 32
+struct lttng_ust_event_notifier {
+ struct lttng_ust_event event;
+ uint64_t error_counter_index;
+
+ char padding[LTTNG_UST_EVENT_NOTIFIER_PADDING];
+} LTTNG_PACKED;
+
+#define LTTNG_UST_EVENT_NOTIFIER_NOTIFICATION_PADDING 32
+struct lttng_ust_event_notifier_notification {
+ uint64_t token;
+ uint16_t capture_buf_size;
+ char padding[LTTNG_UST_EVENT_NOTIFIER_NOTIFICATION_PADDING];
+} LTTNG_PACKED;
+
+enum lttng_ust_key_token_type {
+ LTTNG_UST_KEY_TOKEN_STRING = 0, /* arg: strtab_offset. */
+ LTTNG_UST_KEY_TOKEN_EVENT_NAME = 1, /* no arg. */
+ LTTNG_UST_KEY_TOKEN_PROVIDER_NAME = 2, /* no arg. */
+};
+
+#define LTTNG_UST_KEY_ARG_PADDING1 256
+#define LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX 256
+struct lttng_ust_key_token {
+ uint32_t type; /* enum lttng_ust_key_token_type */
+ union {
+ char string[LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX];
+ char padding[LTTNG_UST_KEY_ARG_PADDING1];
+ } arg;
+} LTTNG_PACKED;
+
+#define LTTNG_UST_NR_KEY_TOKEN 4
+struct lttng_ust_counter_key_dimension {
+ uint32_t nr_key_tokens;
+ struct lttng_ust_key_token key_tokens[LTTNG_UST_NR_KEY_TOKEN];
+} LTTNG_PACKED;
+
+#define LTTNG_UST_COUNTER_DIMENSION_MAX 4
+struct lttng_ust_counter_key {
+ uint32_t nr_dimensions;
+ struct lttng_ust_counter_key_dimension key_dimensions[LTTNG_UST_COUNTER_DIMENSION_MAX];
+} LTTNG_PACKED;
+
+#define LTTNG_UST_COUNTER_EVENT_PADDING1 16
+struct lttng_ust_counter_event {
+ struct lttng_ust_event event;
+ struct lttng_ust_counter_key key;
+ char padding[LTTNG_UST_COUNTER_EVENT_PADDING1];
+} LTTNG_PACKED;
enum lttng_ust_counter_arithmetic {
LTTNG_UST_COUNTER_ARITHMETIC_MODULAR = 0,
uint8_t has_overflow;
} LTTNG_PACKED;
-#define LTTNG_UST_COUNTER_DIMENSION_MAX 8
+#define LTTNG_UST_COUNTER_CONF_PADDING1 67
struct lttng_ust_counter_conf {
uint32_t arithmetic; /* enum lttng_ust_counter_arithmetic */
uint32_t bitness; /* enum lttng_ust_counter_bitness */
uint32_t number_dimensions;
int64_t global_sum_step;
struct lttng_ust_counter_dimension dimensions[LTTNG_UST_COUNTER_DIMENSION_MAX];
+ uint8_t coalesce_hits;
+ char padding[LTTNG_UST_COUNTER_CONF_PADDING1];
} LTTNG_PACKED;
struct lttng_ust_counter_value {
int64_t value;
} LTTNG_PACKED;
-#define LTTNG_UST_EVENT_PADDING1 8
-#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
-struct lttng_ust_event {
- enum lttng_ust_instrumentation instrumentation;
- char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */
-
- enum lttng_ust_loglevel_type loglevel_type;
- int loglevel; /* value, -1: all */
- uint64_t token; /* User-provided token */
- char padding[LTTNG_UST_EVENT_PADDING1];
-
- /* Per instrumentation type configuration */
- union {
- char padding[LTTNG_UST_EVENT_PADDING2];
- } u;
-} LTTNG_PACKED;
-
-#define LTTNG_UST_EVENT_NOTIFIER_PADDING 32
-struct lttng_ust_event_notifier {
- struct lttng_ust_event event;
- uint64_t error_counter_index;
- char padding[LTTNG_UST_EVENT_NOTIFIER_PADDING];
-} LTTNG_PACKED;
-
-#define LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING 32
-struct lttng_ust_event_notifier_notification {
- uint64_t token;
- uint16_t capture_buf_size;
- char padding[LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING];
-} LTTNG_PACKED;
-
#define LTTNG_UST_COUNTER_PADDING1 (LTTNG_UST_SYM_NAME_LEN + 32)
#define LTTNG_UST_COUNTER_DATA_MAX_LEN 4096U
struct lttng_ust_counter {
LTTNG_UST_OBJECT_TYPE_COUNTER = 6,
LTTNG_UST_OBJECT_TYPE_COUNTER_GLOBAL = 7,
LTTNG_UST_OBJECT_TYPE_COUNTER_CPU = 8,
+ LTTNG_UST_OBJECT_TYPE_COUNTER_EVENT = 9,
};
#define LTTNG_UST_OBJECT_DATA_PADDING1 32
_UST_CMDW(0xD0, struct lttng_ust_counter_global)
#define LTTNG_UST_COUNTER_CPU \
_UST_CMDW(0xD1, struct lttng_ust_counter_cpu)
+#define LTTNG_UST_COUNTER_EVENT \
+ _UST_CMDW(0xD2, struct lttng_ust_counter_event)
#define LTTNG_UST_ROOT_HANDLE 0
*/
size_t *nr_fields,
struct ustctl_field **fields,
- char **model_emf_uri);
+ char **model_emf_uri,
+ uint64_t *user_token);
/*
* Returns 0 on success, negative error value on error.
*/
int ustctl_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 */
/*
const int *counter_cpu_fds,
enum ustctl_counter_bitness bitness,
enum ustctl_counter_arithmetic arithmetic,
- uint32_t alloc_flags);
+ uint32_t alloc_flags,
+ bool coalesce_hits);
int ustctl_create_counter_data(struct ustctl_daemon_counter *counter,
struct lttng_ust_object_data **counter_data);
struct lttng_ust_object_data *counter_data,
struct lttng_ust_object_data *counter_cpu_data);
+int ustctl_counter_create_event(int sock,
+ struct lttng_ust_counter_event *counter_event,
+ struct lttng_ust_object_data *counter_data,
+ struct lttng_ust_object_data **counter_event_data);
+
int ustctl_counter_read(struct ustctl_daemon_counter *counter,
const size_t *dimension_indexes,
int cpu, int64_t *value,
* library, but the opposite is rejected: a newer tracepoint provider is
* rejected by an older lttng-ust library.
*/
-#define LTTNG_UST_PROVIDER_MAJOR 2
+#define LTTNG_UST_PROVIDER_MAJOR 3
#define LTTNG_UST_PROVIDER_MINOR 0
struct lttng_channel;
#define LTTNG_UST_EVENT_DESC_PADDING 40
struct lttng_event_desc {
const char *name;
- void (*probe_callback)(void);
+ void (*probe_callback)(void); /* store-event and count-event probe */
const struct lttng_event_ctx *ctx; /* context */
const struct lttng_event_field *fields; /* event payload */
unsigned int nr_fields;
LTTNG_ENABLER_FORMAT_EVENT,
};
-/*
- * Enabler field, within whatever object is enabling an event. Target of
- * backward reference.
- */
-struct lttng_enabler {
- enum lttng_enabler_format_type format_type;
-
- /* head list of struct lttng_ust_filter_bytecode_node */
- struct cds_list_head filter_bytecode_head;
- /* head list of struct lttng_ust_excluder_node */
- struct cds_list_head excluder_head;
-
- struct lttng_ust_event event_param;
- unsigned int enabled:1;
-};
-
struct tp_list_entry {
struct lttng_ust_tracepoint_iter tp;
struct cds_list_head head;
struct lttng_enabler *ref; /* backward ref */
};
+enum lttng_event_container_type {
+ LTTNG_EVENT_CONTAINER_CHANNEL,
+ LTTNG_EVENT_CONTAINER_COUNTER,
+};
+
+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_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_NR_KEY_TOKEN
+struct lttng_counter_key_dimension {
+ size_t nr_key_tokens;
+ struct lttng_key_token key_tokens[LTTNG_UST_NR_KEY_TOKEN];
+};
+
+#define LTTNG_COUNTER_DIMENSION_MAX LTTNG_UST_COUNTER_DIMENSION_MAX
+struct lttng_counter_key {
+ size_t nr_dimensions;
+ struct lttng_counter_key_dimension key_dimensions[LTTNG_COUNTER_DIMENSION_MAX];
+};
+
/*
* lttng_event structure is referred to by the tracing fast path. It
* must be kept small.
*/
struct lttng_event {
unsigned int id;
- struct lttng_channel *chan;
+ struct lttng_channel *chan; /* for backward compatibility */
int enabled;
const struct lttng_event_desc *desc;
struct lttng_ctx *ctx;
int has_enablers_without_bytecode;
/* Backward references: list of lttng_enabler_ref (ref to enablers) */
struct cds_list_head enablers_ref_head;
- struct cds_hlist_node hlist; /* session ht of events */
- int registered; /* has reg'd tracepoint probe */
+ struct cds_hlist_node name_hlist; /* session ht of events, per event name */
+ int registered; /* has reg'd tracepoint probe */
+
+ /* LTTng-UST 2.14 starts here */
+ uint64_t counter_index; /* counter index */
+ struct lttng_event_container *container;
+ struct cds_hlist_node key_hlist; /* session ht of events, per key */
+ char key[LTTNG_KEY_TOKEN_STRING_LEN_MAX];
+ /*
+ * For non-coalesce-hit event containers, each events is
+ * associated with a single event enabler token.
+ */
+ uint64_t user_token;
};
struct lttng_event_notifier {
const char *src, size_t len);
};
+/*
+ * This structure is ABI with the tracepoint probes, and must preserve
+ * backward compatibility. Fields can only be added at the end, and
+ * never removed nor reordered.
+ */
+struct lttng_event_container {
+ enum lttng_event_container_type type;
+ int objd;
+ struct lttng_session *session; /* Session containing the container */
+ int enabled;
+ unsigned int tstate:1; /* Transient enable state */
+ bool coalesce_hits;
+};
+
/*
* 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
* and perform subbuffer flush.
*/
struct channel *chan; /* Channel buffers */
- int enabled;
+ int enabled; /* For backward compatibility */
struct lttng_ctx *ctx;
/* Event ID management */
- struct lttng_session *session;
+ struct lttng_session *session; /* For backward compatibility */
int objd; /* Object associated to channel */
struct cds_list_head node; /* Channel list in session */
const struct lttng_channel_ops *ops;
unsigned int id;
enum lttng_ust_chan_type type;
unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
- int tstate:1; /* Transient enable state */
-};
+ int _deprecated:1;
-#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_event_container parent;
};
struct lttng_counter_ops {
struct lib_counter *(*counter_create)(size_t nr_dimensions,
- const struct lttng_counter_dimension *dimensions,
+ const size_t *dimensions,
int64_t global_sum_step,
int global_counter_fd,
int nr_counter_cpu_fds,
/* New UST 2.1 */
/* List of enablers */
struct cds_list_head enablers_head;
- struct lttng_ust_event_ht events_ht; /* ht of events */
+ /* hash table of events, indexed by name */
+ struct lttng_ust_event_ht events_name_ht;
void *owner; /* object owner */
int tstate:1; /* Transient enable state */
struct lttng_ust_enum_ht enums_ht; /* ht of enumerations */
struct cds_list_head enums_head;
struct lttng_ctx *ctx; /* contexts for filters. */
+
+ /* New UST 2.14 */
+ struct cds_list_head counters; /* Counters list */
+ /* hash table of events, indexed by key */
+ struct lttng_ust_event_ht events_key_ht;
};
struct lttng_counter {
- int objd;
- struct lttng_event_notifier_group *event_notifier_group; /* owner */
+ struct lttng_event_container parent;
+ union {
+ struct lttng_event_notifier_group *event_notifier_group;
+ struct lttng_session *session;
+ } owner;
struct lttng_counter_transport *transport;
struct lib_counter *counter;
struct lttng_counter_ops *ops;
+ struct cds_list_head node; /* Counter list (in session) */
+ size_t free_index; /* Next index to allocate */
};
struct lttng_event_notifier_group {
int lttng_session_statedump(struct lttng_session *session);
void lttng_session_destroy(struct lttng_session *session);
-struct lttng_channel *lttng_channel_create(struct lttng_session *session,
- const char *transport_name,
- void *buf_addr,
- size_t subbuf_size, size_t num_subbuf,
- unsigned int switch_timer_interval,
- unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size,
- struct lttng_channel *chan_priv_init);
-
-int lttng_channel_enable(struct lttng_channel *channel);
-int lttng_channel_disable(struct lttng_channel *channel);
+int lttng_event_container_enable(struct lttng_event_container *container);
+int lttng_event_container_disable(struct lttng_event_container *container);
int lttng_attach_context(struct lttng_ust_context *context_param,
union ust_args *uargs,
void lttng_transport_register(struct lttng_transport *transport);
void lttng_transport_unregister(struct lttng_transport *transport);
+void lttng_counter_transport_register(struct lttng_counter_transport *transport);
+void lttng_counter_transport_unregister(struct lttng_counter_transport *transport);
+
int lttng_probe_register(struct lttng_probe_desc *desc);
void lttng_probe_unregister(struct lttng_probe_desc *desc);
void lttng_probe_provider_unregister_events(struct lttng_probe_desc *desc);
void lttng_ust_dl_update(void *ip);
void lttng_ust_fixup_fd_tracker_tls(void);
+static inline
+struct lttng_event_container *lttng_channel_get_event_container(struct lttng_channel *channel)
+{
+ return &channel->parent;
+}
+
+static inline
+struct lttng_event_container *lttng_counter_get_event_container(struct lttng_counter *counter)
+{
+ return &counter->parent;
+}
+
+static inline
+struct lttng_channel *lttng_event_container_get_channel(struct lttng_event_container *container)
+{
+ if (container->type != LTTNG_EVENT_CONTAINER_CHANNEL)
+ return NULL;
+ return caa_container_of(container, struct lttng_channel, parent);
+}
+
+static inline
+struct lttng_counter *lttng_event_container_get_counter(struct lttng_event_container *container)
+{
+ if (container->type != LTTNG_EVENT_CONTAINER_COUNTER)
+ return NULL;
+ return caa_container_of(container, struct lttng_counter, parent);
+}
+
#ifdef __cplusplus
}
#endif
#undef _TRACEPOINT_EVENT_CLASS
#define _TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \
-static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args));
-
-#include TRACEPOINT_INCLUDE
-
-/*
- * Stage 2.1 of tracepoint event generation.
- *
- * Create probe event notifier callback prototypes.
- */
-
-/* Reset all macros within TRACEPOINT_EVENT */
-#include <lttng/ust-tracepoint-event-reset.h>
-
-#undef TP_ARGS
-#define TP_ARGS(...) __VA_ARGS__
-
-#undef _TRACEPOINT_EVENT_CLASS
-#define _TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \
+static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); \
static void __event_notifier_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args));
#include TRACEPOINT_INCLUDE
void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \
{ \
struct lttng_event *__event = (struct lttng_event *) __tp_data; \
- struct lttng_channel *__chan = __event->chan; \
+ struct lttng_event_container *__container = __event->container; \
+ struct lttng_session *__session = __container->session; \
struct lttng_ust_lib_ring_buffer_ctx __ctx; \
struct lttng_stack_ctx __lttng_ctx; \
- size_t __event_len, __event_align; \
size_t __dynamic_len_idx = 0; \
const size_t __num_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1; \
union { \
\
if (0) \
(void) __dynamic_len_idx; /* don't warn if unused */ \
- if (!_TP_SESSION_CHECK(session, __chan->session)) \
+ if (!_TP_SESSION_CHECK(session, __container->session)) \
return; \
- if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->session->active))) \
+ if (caa_unlikely(!CMM_ACCESS_ONCE(__session->active))) \
return; \
- if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->enabled))) \
+ if (caa_unlikely(!CMM_ACCESS_ONCE(__container->enabled))) \
return; \
if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled))) \
return; \
if (caa_unlikely(!TP_RCU_LINK_TEST())) \
return; \
if (caa_unlikely(!cds_list_empty(&__event->filter_bytecode_runtime_head))) { \
- struct lttng_bytecode_runtime *__filter_bc_runtime; \
+ struct lttng_bytecode_runtime *__filter_bc_runtime; \
int __filter_record = __event->has_enablers_without_bytecode; \
\
__event_prepare_interpreter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \
if (caa_likely(!__filter_record)) \
return; \
} \
- __event_len = __event_get_size__##_provider##___##_name(__stackvar.__dynamic_len, \
- _TP_ARGS_DATA_VAR(_args)); \
- __event_align = __event_get_align__##_provider##___##_name(_TP_ARGS_VAR(_args)); \
- memset(&__lttng_ctx, 0, sizeof(__lttng_ctx)); \
- __lttng_ctx.event = __event; \
- __lttng_ctx.chan_ctx = tp_rcu_dereference(__chan->ctx); \
- __lttng_ctx.event_ctx = tp_rcu_dereference(__event->ctx); \
- lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \
- __event_align, -1, __chan->handle, &__lttng_ctx); \
- __ctx.ip = _TP_IP_PARAM(TP_IP_PARAM); \
- __ret = __chan->ops->event_reserve(&__ctx, __event->id); \
- if (__ret < 0) \
- return; \
- _fields \
- __chan->ops->event_commit(&__ctx); \
+ switch (__container->type) { \
+ case LTTNG_EVENT_CONTAINER_CHANNEL: \
+ { \
+ struct lttng_channel *__chan = lttng_event_container_get_channel(__container); \
+ size_t __event_len, __event_align; \
+ \
+ __event_len = __event_get_size__##_provider##___##_name(__stackvar.__dynamic_len, \
+ _TP_ARGS_DATA_VAR(_args)); \
+ __event_align = __event_get_align__##_provider##___##_name(_TP_ARGS_VAR(_args)); \
+ memset(&__lttng_ctx, 0, sizeof(__lttng_ctx)); \
+ __lttng_ctx.event = __event; \
+ __lttng_ctx.chan_ctx = tp_rcu_dereference(__chan->ctx); \
+ __lttng_ctx.event_ctx = tp_rcu_dereference(__event->ctx); \
+ lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \
+ __event_align, -1, __chan->handle, &__lttng_ctx); \
+ __ctx.ip = _TP_IP_PARAM(TP_IP_PARAM); \
+ __ret = __chan->ops->event_reserve(&__ctx, __event->id); \
+ if (__ret < 0) \
+ return; \
+ _fields \
+ __chan->ops->event_commit(&__ctx); \
+ break; \
+ } \
+ case LTTNG_EVENT_CONTAINER_COUNTER: \
+ { \
+ struct lttng_counter *__counter = lttng_event_container_get_counter(__container); \
+ size_t __index = __event->id; \
+ \
+ (void) __counter->ops->counter_add(__counter->counter, &__index, 1); \
+ break; \
+ } \
+ } \
}
#include TRACEPOINT_INCLUDE
/* Length of struct lttng_ust_event_notifier */
uint32_t len;
} event_notifier;
+ /*
+ * For LTTNG_UST_COUNTER_EVENT, a struct
+ * lttng_ust_counter_event implicitly follows struct
+ * ustcomm_ust_msg.
+ */
+ struct {
+ /* Length of struct lttng_ust_counter_event */
+ uint32_t len;
+ } counter_event;
char padding[USTCOMM_MSG_PADDING2];
} u;
} LTTNG_PACKED;
uint32_t notify_cmd;
} LTTNG_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 */
+ /* followed by signature, fields, model_emf_uri, and key */
} LTTNG_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 events. */
char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING];
} LTTNG_PACKED;
/* followed by enum entries */
} LTTNG_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];
} LTTNG_PACKED;
#define USTCOMM_NOTIFY_CHANNEL_MSG_PADDING 32
size_t nr_fields, /* fields */
const struct lttng_event_field *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) */
/*
* Returns 0 on success, negative error value on error.
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 >= lttng_counter_num_possible_cpus())
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);
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,
#define _LTTNG_COUNTER_H
#include <stdint.h>
+#include <stdbool.h>
#include <lttng/ust-config.h>
#include "counter-types.h"
#include "helper.h"
LTTNG_HIDDEN
int lttng_counter_get_cpu_shm(struct lib_counter *counter, int cpu, int *fd, size_t *len);
+/*
+ * Has counter received all expected shm ?
+ */
+LTTNG_HIDDEN
+bool lttng_counter_ready(struct lib_counter *counter);
+
LTTNG_HIDDEN
int lttng_counter_read(const struct lib_counter_config *config,
struct lib_counter *counter,
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <lttng/ust-ctl.h>
#include <ust-comm.h>
size_t nr_fields, /* fields */
const struct lttng_event_field *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_SYM_NAME_LEN);
msg.m.event_name[LTTNG_UST_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);
+ *event_id = reply.r.event_id;
+ *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) {
uint32_t nr_dimensions;
int64_t global_sum_step;
struct ustctl_counter_dimension dimensions[USTCTL_COUNTER_ATTR_DIMENSION_MAX];
+ bool coalesce_hits;
};
/*
case LTTNG_UST_OBJECT_TYPE_CONTEXT:
case LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER_GROUP:
case LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER:
+ case LTTNG_UST_OBJECT_TYPE_COUNTER_EVENT:
break;
case LTTNG_UST_OBJECT_TYPE_COUNTER:
free(data->u.counter.data);
/* Send struct lttng_ust_event_notifier */
len = ustcomm_send_unix_sock(sock, event_notifier, sizeof(*event_notifier));
if (len != sizeof(*event_notifier)) {
+ free(event_notifier_data);
if (len < 0)
return len;
else
char **signature,
size_t *nr_fields,
struct ustctl_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 ustctl_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 = USTCTL_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;
const int *counter_cpu_fds,
enum ustctl_counter_bitness bitness,
enum ustctl_counter_arithmetic arithmetic,
- uint32_t alloc_flags)
+ uint32_t alloc_flags,
+ bool coalesce_hits)
{
const char *transport_name;
struct ustctl_daemon_counter *counter;
struct lttng_counter_transport *transport;
- struct lttng_counter_dimension ust_dim[LTTNG_COUNTER_DIMENSION_MAX];
- size_t i;
+ struct lttng_ust_counter_dimension ust_dim[LTTNG_COUNTER_DIMENSION_MAX];
+ size_t counter_len[LTTNG_COUNTER_DIMENSION_MAX], i;
if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX)
return NULL;
return NULL;
}
+ for (i = 0; i < nr_dimensions; i++) {
+ if (dimensions[i].has_underflow)
+ return NULL;
+ if (dimensions[i].has_overflow)
+ return NULL;
+ counter_len[i] = ust_dim[i].size = dimensions[i].size;
+ }
+
counter = zmalloc(sizeof(*counter));
if (!counter)
return NULL;
counter->attr->arithmetic = arithmetic;
counter->attr->nr_dimensions = nr_dimensions;
counter->attr->global_sum_step = global_sum_step;
+ counter->attr->coalesce_hits = coalesce_hits;
+
for (i = 0; i < nr_dimensions; i++)
counter->attr->dimensions[i] = dimensions[i];
- for (i = 0; i < nr_dimensions; i++) {
- ust_dim[i].size = dimensions[i].size;
- ust_dim[i].underflow_index = dimensions[i].underflow_index;
- ust_dim[i].overflow_index = dimensions[i].overflow_index;
- 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,
- ust_dim, global_sum_step, global_counter_fd,
+ counter_len, global_sum_step, global_counter_fd,
nr_counter_cpu_fds, counter_cpu_fds, true);
if (!counter->counter)
goto free_attr;
}
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;
return ret;
}
+int ustctl_counter_create_event(int sock,
+ struct lttng_ust_counter_event *counter_event,
+ struct lttng_ust_object_data *counter_data,
+ struct lttng_ust_object_data **_counter_event_data)
+{
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ struct lttng_ust_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_OBJECT_TYPE_COUNTER_EVENT;
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = counter_data->handle;
+ lum.cmd = LTTNG_UST_COUNTER_EVENT;
+ lum.u.counter_event.len = sizeof(*counter_event);
+ ret = ustcomm_send_app_msg(sock, &lum);
+ 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 ustctl_counter_read(struct ustctl_daemon_counter *counter,
const size_t *dimension_indexes,
int cpu, int64_t *value,
};
static struct lib_counter *counter_create(size_t nr_dimensions,
- const struct lttng_counter_dimension *dimensions,
+ const size_t *max_nr_elem,
int64_t global_sum_step,
int global_counter_fd,
int nr_counter_cpu_fds,
const int *counter_cpu_fds,
bool is_daemon)
{
- size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i;
-
if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX)
return NULL;
- for (i = 0; i < nr_dimensions; i++) {
- if (dimensions[i].has_underflow || dimensions[i].has_overflow)
- return NULL;
- max_nr_elem[i] = dimensions[i].size;
- }
return 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);
};
static struct lib_counter *counter_create(size_t nr_dimensions,
- const struct lttng_counter_dimension *dimensions,
+ const size_t *max_nr_elem,
int64_t global_sum_step,
int global_counter_fd,
int nr_counter_cpu_fds,
const int *counter_cpu_fds,
bool is_daemon)
{
- size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i;
-
if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX)
return NULL;
- for (i = 0; i < nr_dimensions; i++) {
- if (dimensions[i].has_underflow || dimensions[i].has_overflow)
- return NULL;
- max_nr_elem[i] = dimensions[i].size;
- }
return 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);
static
void lttng_enabler_destroy(struct lttng_enabler *enabler);
+/*
+ * @buf must hold at least LTTNG_UST_SYM_NAME_LEN bytes.
+ */
+static
+int lttng_split_provider_event_name(const char *full_name,
+ char *buf, const char **event_name,
+ const char **provider_name)
+{
+ char *saveptr;
+
+ if (strlen(full_name) >= LTTNG_UST_SYM_NAME_LEN)
+ return -1;
+ strcpy(buf, full_name);
+ *provider_name = strtok_r(buf, ":", &saveptr); /* Stops at ':' or '\0'. */
+ if (!provider_name)
+ return -1;
+ *event_name = strtok_r(NULL, ":", &saveptr); /* Stops at ':' or '\0'. */
+ if (!event_name)
+ return -1;
+ /*
+ * Ensure we don't have leftover characters. Stops at '\0'. It validates
+ * that neither the provider nor event name contain ':'.
+ */
+ if (strtok_r(NULL, "", &saveptr))
+ return -1;
+ return 0;
+}
+
/*
* Called with ust lock held.
*/
CDS_INIT_LIST_HEAD(&session->events_head);
CDS_INIT_LIST_HEAD(&session->enums_head);
CDS_INIT_LIST_HEAD(&session->enablers_head);
+ CDS_INIT_LIST_HEAD(&session->counters);
+ for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++)
+ CDS_INIT_HLIST_HEAD(&session->events_name_ht.table[i]);
for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++)
- CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]);
- for (i = 0; i < LTTNG_UST_ENUM_HT_SIZE; i++)
CDS_INIT_HLIST_HEAD(&session->enums_ht.table[i]);
cds_list_add(&session->node, &sessions);
return session;
struct lttng_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 size_t *max_nr_elem,
+ int64_t global_sum_step,
+ bool coalesce_hits)
{
struct lttng_counter_transport *counter_transport = NULL;
struct lttng_counter *counter = NULL;
counter->transport = counter_transport;
counter->counter = counter->ops->counter_create(
- number_dimensions, dimensions, 0,
+ number_dimensions, max_nr_elem, global_sum_step,
-1, 0, NULL, false);
if (!counter->counter) {
goto create_error;
}
+ counter->parent.coalesce_hits = coalesce_hits;
return counter;
free(counter);
}
+struct lttng_counter *lttng_session_create_counter(
+ struct lttng_session *session,
+ const char *counter_transport_name,
+ size_t number_dimensions, const size_t *dimensions_sizes,
+ int64_t global_sum_step, bool coalesce_hits)
+{
+ struct lttng_counter *counter;
+ struct lttng_event_container *container;
+
+ counter = lttng_ust_counter_create(counter_transport_name,
+ number_dimensions, dimensions_sizes, global_sum_step,
+ coalesce_hits);
+ if (!counter) {
+ goto counter_error;
+ }
+ container = lttng_counter_get_event_container(counter);
+ container->type = LTTNG_EVENT_CONTAINER_COUNTER;
+
+ container->session = session;
+ cds_list_add(&counter->node, &session->counters);
+
+ return counter;
+
+counter_error:
+ return NULL;
+}
+
struct lttng_event_notifier_group *lttng_event_notifier_group_create(void)
{
struct lttng_event_notifier_group *event_notifier_group;
ret = ustcomm_register_channel(notify_socket,
session,
session->objd,
- chan->objd,
+ chan->parent.objd,
nr_fields,
fields,
&chan_id,
return ret;
}
-int lttng_channel_enable(struct lttng_channel *channel)
+int lttng_event_container_enable(struct lttng_event_container *container)
{
int ret = 0;
- if (channel->enabled) {
+ if (container->enabled) {
ret = -EBUSY;
goto end;
}
/* Set transient enabler state to "enabled" */
- channel->tstate = 1;
- lttng_session_sync_event_enablers(channel->session);
- /* Set atomically the state to "enabled" */
- CMM_ACCESS_ONCE(channel->enabled) = 1;
+ container->tstate = 1;
+ lttng_session_sync_event_enablers(container->session);
+ /* Atomically set the state to "enabled" */
+ switch (container->type) {
+ case LTTNG_EVENT_CONTAINER_CHANNEL:
+ {
+ struct lttng_channel *channel = caa_container_of(container,
+ struct lttng_channel, parent);
+
+ CMM_ACCESS_ONCE(channel->enabled) = 1; /* Backward compatibility */
+ break;
+ }
+ default:
+ break;
+ }
+ CMM_ACCESS_ONCE(container->enabled) = 1;
end:
return ret;
}
-int lttng_channel_disable(struct lttng_channel *channel)
+int lttng_event_container_disable(struct lttng_event_container *container)
{
int ret = 0;
- if (!channel->enabled) {
+ if (!container->enabled) {
ret = -EBUSY;
goto end;
}
- /* Set atomically the state to "disabled" */
- CMM_ACCESS_ONCE(channel->enabled) = 0;
+ /* Atomically set the state to "disabled" */
+ CMM_ACCESS_ONCE(container->enabled) = 0;
+ switch (container->type) {
+ case LTTNG_EVENT_CONTAINER_CHANNEL:
+ {
+ struct lttng_channel *channel = caa_container_of(container,
+ struct lttng_channel, parent);
+
+ CMM_ACCESS_ONCE(channel->enabled) = 0; /* Backward compatibility */
+ break;
+ }
+ default:
+ break;
+ }
/* Set transient enabler state to "enabled" */
- channel->tstate = 0;
- lttng_session_sync_event_enablers(channel->session);
+ container->tstate = 0;
+ lttng_session_sync_event_enablers(container->session);
end:
return ret;
}
struct cds_hlist_head *borrow_hash_table_bucket(
struct cds_hlist_head *hash_table,
unsigned int hash_table_size,
- const struct lttng_event_desc *desc)
+ const char *name)
{
- const char *event_name;
size_t name_len;
uint32_t hash;
- event_name = desc->name;
- name_len = strlen(event_name);
+ name_len = strlen(name);
- hash = jhash(event_name, name_len, 0);
+ 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 *full_name)
+{
+ const struct lttng_counter_key_dimension *dim;
+ size_t i, left = LTTNG_KEY_TOKEN_STRING_LEN_MAX;
+ char buf[LTTNG_UST_SYM_NAME_LEN];
+ const char *provider_name, *event_name;
+
+ if (lttng_split_provider_event_name(full_name, buf, &provider_name, &event_name))
+ return -EINVAL;
+ 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_token(struct lttng_event_container *container,
+ struct lttng_event *event, uint64_t token)
+{
+ if (container->coalesce_hits)
+ return true;
+ if (event->user_token == token)
+ return true;
+ return false;
+}
+
/*
* Supports event creation while tracing session is active.
*/
static
-int lttng_event_create(const struct lttng_event_desc *desc,
- struct lttng_channel *chan)
+int lttng_event_create(struct lttng_event_enabler *event_enabler,
+ const struct lttng_event_desc *event_desc,
+ const struct lttng_counter_key *key)
{
+ struct lttng_event_container *container = event_enabler->container;
struct lttng_event *event;
- struct lttng_session *session = chan->session;
- struct cds_hlist_head *head;
+ struct lttng_session *session = container->session;
+ const char *event_name;
+ struct cds_hlist_head *name_head;
+ char key_string[LTTNG_KEY_TOKEN_STRING_LEN_MAX];
int ret = 0;
int notify_socket, loglevel;
const char *uri;
- head = borrow_hash_table_bucket(chan->session->events_ht.table,
- LTTNG_UST_EVENT_HT_SIZE, desc);
+ event_name = event_desc->name;
+ if (format_event_key(key_string, key, event_name)) {
+ ret = -EINVAL;
+ goto type_error;
+ }
+
+ name_head = borrow_hash_table_bucket(session->events_name_ht.table,
+ LTTNG_UST_EVENT_HT_SIZE, event_name);
+ cds_hlist_for_each_entry_2(event, name_head, name_hlist) {
+ bool same_event = false, same_container = false, same_key = false,
+ same_token = false;
+
+ WARN_ON_ONCE(!event->desc);
+ if (event_desc) {
+ if (event->desc == event_desc)
+ same_event = true;
+ } else {
+ if (!strcmp(event_name, event->desc->name))
+ same_event = true;
+ }
+ if (container == event->container) {
+ same_container = true;
+ if (match_event_token(container, event,
+ event_enabler->base.user_token))
+ same_token = true;
+ }
+ if (key_string[0] == '\0' || !strcmp(key_string, event->key))
+ same_key = true;
+ if (same_event && same_container && same_key && same_token) {
+ ret = -EEXIST;
+ goto exist;
+ }
+ }
notify_socket = lttng_get_notify_socket(session->owner);
if (notify_socket < 0) {
goto socket_error;
}
- ret = lttng_create_all_event_enums(desc->nr_fields, desc->fields,
+ ret = lttng_create_all_event_enums(event_desc->nr_fields, event_desc->fields,
session);
if (ret < 0) {
DBG("Error (%d) adding enum to session", ret);
ret = -ENOMEM;
goto cache_error;
}
- event->chan = chan;
+ /* for backward compatibility */
+ event->chan = lttng_event_container_get_channel(container);
/* Event will be enabled by enabler sync. */
event->enabled = 0;
event->registered = 0;
CDS_INIT_LIST_HEAD(&event->filter_bytecode_runtime_head);
CDS_INIT_LIST_HEAD(&event->enablers_ref_head);
- event->desc = desc;
+ event->desc = event_desc;
+ event->container = container;
+ strcpy(event->key, key_string);
+ if (!container->coalesce_hits)
+ event->user_token = event_enabler->base.user_token;
- if (desc->loglevel)
+ if (event_desc->loglevel)
loglevel = *(*event->desc->loglevel);
else
loglevel = TRACE_DEFAULT;
- if (desc->u.ext.model_emf_uri)
- uri = *(desc->u.ext.model_emf_uri);
+ if (event_desc->u.ext.model_emf_uri)
+ uri = *(event_desc->u.ext.model_emf_uri);
else
uri = NULL;
ret = ustcomm_register_event(notify_socket,
session,
session->objd,
- chan->objd,
- desc->name,
+ container->objd,
+ event_desc->name,
loglevel,
- desc->signature,
- desc->nr_fields,
- desc->fields,
+ event_desc->signature,
+ event_desc->nr_fields,
+ event_desc->fields,
uri,
- &event->id);
+ event_enabler->base.user_token,
+ &event->id,
+ &event->counter_index);
if (ret < 0) {
DBG("Error (%d) registering event to sessiond", ret);
goto sessiond_register_error;
}
- cds_list_add(&event->node, &chan->session->events_head);
- cds_hlist_add_head(&event->hlist, head);
+ cds_list_add(&event->node, &session->events_head);
+ cds_hlist_add_head(&event->name_hlist, name_head);
return 0;
sessiond_register_error:
cache_error:
create_enum_error:
socket_error:
+exist:
+type_error:
return ret;
}
*/
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, desc->name);
event_notifier = zmalloc(sizeof(struct lttng_event_notifier));
if (!event_notifier) {
}
static
-int lttng_event_enabler_match_event(struct lttng_event_enabler *event_enabler,
+bool lttng_event_enabler_match_event(struct lttng_event_enabler *event_enabler,
struct lttng_event *event)
{
if (lttng_desc_match_enabler(event->desc,
- lttng_event_enabler_as_enabler(event_enabler))
- && event->chan == event_enabler->chan)
- return 1;
+ lttng_event_enabler_as_enabler(event_enabler)) > 0
+ && event->container == event_enabler->container
+ && match_event_token(event->container, event, event_enabler->base.user_token))
+ return true;
else
- return 0;
+ return false;
}
static
struct lttng_event_notifier_enabler *event_notifier_enabler,
struct lttng_event_notifier *event_notifier)
{
- int desc_matches = lttng_desc_match_enabler(event_notifier->desc,
- lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
+ bool desc_matches = lttng_desc_match_enabler(event_notifier->desc,
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)) > 0;
if (desc_matches && event_notifier->group == event_notifier_enabler->group &&
- event_notifier->user_token == event_notifier_enabler->user_token)
+ event_notifier->user_token == event_notifier_enabler->base.user_token)
return 1;
else
return 0;
static
void lttng_create_event_if_missing(struct lttng_event_enabler *event_enabler)
{
- struct lttng_session *session = event_enabler->chan->session;
struct lttng_probe_desc *probe_desc;
const struct lttng_event_desc *desc;
- struct lttng_event *event;
int i;
struct cds_list_head *probe_list;
cds_list_for_each_entry(probe_desc, probe_list, head) {
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,
+ lttng_event_enabler_as_enabler(event_enabler)) <= 0)
continue;
- head = borrow_hash_table_bucket(
- session->events_ht.table,
- LTTNG_UST_EVENT_HT_SIZE, desc);
-
- cds_hlist_for_each_entry(event, node, head, hlist) {
- if (event->desc == desc
- && event->chan == event_enabler->chan) {
- found = true;
- break;
- }
- }
- if (found)
+ /* Try to create an event for this event probe. */
+ ret = lttng_event_create(event_enabler,
+ probe_desc->event_desc[i],
+ &event_enabler->key);
+ /* Skip if event is already found. */
+ if (ret == -EEXIST)
continue;
-
- /*
- * We need to create an event for this
- * event probe.
- */
- ret = lttng_event_create(probe_desc->event_desc[i],
- event_enabler->chan);
if (ret) {
DBG("Unable to create event %s, error %d\n",
probe_desc->event_desc[i]->name, ret);
* iterate to find the event matching this descriptor.
*/
head = borrow_hash_table_bucket(
- session->events_ht.table,
- LTTNG_UST_EVENT_HT_SIZE, event_desc);
+ session->events_name_ht.table,
+ LTTNG_UST_EVENT_HT_SIZE, event_desc->name);
- cds_hlist_for_each_entry_safe(event, node, tmp_node, head, hlist) {
+ cds_hlist_for_each_entry_safe(event, node, tmp_node, head, name_hlist) {
if (event_desc == event->desc) {
event_func(session, event);
break;
*/
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, event_desc->name);
cds_hlist_for_each_entry_safe(event_notifier, node, tmp_node, head, hlist) {
if (event_desc == event_notifier->desc) {
static
int lttng_event_enabler_ref_events(struct lttng_event_enabler *event_enabler)
{
- struct lttng_session *session = event_enabler->chan->session;
+ struct lttng_session *session = event_enabler->container->session;
struct lttng_event *event;
if (!lttng_event_enabler_as_enabler(event_enabler)->enabled)
/* Remove from event list. */
cds_list_del(&event->node);
/* Remove from event hash table. */
- cds_hlist_del(&event->hlist);
+ cds_hlist_del(&event->name_hlist);
lttng_destroy_context(event->ctx);
lttng_free_event_filter_runtime(event);
lttng_session_destroy(session);
}
+static
+int copy_counter_key(struct lttng_counter_key *key,
+ const struct lttng_ust_counter_key *key_param)
+{
+ size_t i, j, nr_dimensions;
+
+ nr_dimensions = key_param->nr_dimensions;
+ if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX)
+ return -EINVAL;
+ key->nr_dimensions = nr_dimensions;
+ for (i = 0; i < nr_dimensions; i++) {
+ const struct lttng_ust_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_NR_KEY_TOKEN)
+ return -EINVAL;
+ dim->nr_key_tokens = nr_key_tokens;
+ for (j = 0; j < nr_key_tokens; j++) {
+ const struct lttng_ust_key_token *utoken =
+ &udim->key_tokens[j];
+ struct lttng_key_token *token =
+ &dim->key_tokens[j];
+
+ switch (utoken->type) {
+ case LTTNG_UST_KEY_TOKEN_STRING:
+ {
+ size_t len;
+
+ token->type = LTTNG_KEY_TOKEN_STRING;
+ len = strnlen(utoken->arg.string, LTTNG_KEY_TOKEN_STRING_LEN_MAX);
+ if (!len || len >= LTTNG_KEY_TOKEN_STRING_LEN_MAX)
+ return -EINVAL;
+ strcpy(token->arg.string, utoken->arg.string);
+ break;
+ }
+ case LTTNG_UST_KEY_TOKEN_EVENT_NAME:
+ token->type = LTTNG_KEY_TOKEN_EVENT_NAME;
+ break;
+ case LTTNG_UST_KEY_TOKEN_PROVIDER_NAME:
+ token->type = LTTNG_KEY_TOKEN_PROVIDER_NAME;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
+
/*
* Enabler management.
*/
struct lttng_event_enabler *lttng_event_enabler_create(
enum lttng_enabler_format_type format_type,
struct lttng_ust_event *event_param,
- struct lttng_channel *chan)
+ const struct lttng_ust_counter_key *key,
+ struct lttng_event_container *container)
{
struct lttng_event_enabler *event_enabler;
if (!event_enabler)
return NULL;
event_enabler->base.format_type = format_type;
+ event_enabler->base.user_token = event_param->token;
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->chan = chan;
+ event_enabler->container = container;
+ if (key) {
+ if (copy_counter_key(&event_enabler->key, key))
+ return NULL;
+ }
/* ctx left NULL */
event_enabler->base.enabled = 0;
- cds_list_add(&event_enabler->node, &event_enabler->chan->session->enablers_head);
- lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ cds_list_add(&event_enabler->node, &event_enabler->container->session->enablers_head);
+ lttng_session_lazy_sync_event_enablers(event_enabler->container->session);
return event_enabler;
}
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->error_counter_index = event_notifier_param->error_counter_index;
event_notifier_enabler->num_captures = 0;
+ event_notifier_enabler->base.user_token = event_notifier_param->event.token;
memcpy(&event_notifier_enabler->base.event_param.name,
event_notifier_param->event.name,
sizeof(event_notifier_enabler->base.event_param.name));
int lttng_event_enabler_enable(struct lttng_event_enabler *event_enabler)
{
lttng_event_enabler_as_enabler(event_enabler)->enabled = 1;
- lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ lttng_session_lazy_sync_event_enablers(event_enabler->container->session);
return 0;
}
int lttng_event_enabler_disable(struct lttng_event_enabler *event_enabler)
{
lttng_event_enabler_as_enabler(event_enabler)->enabled = 0;
- lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ lttng_session_lazy_sync_event_enablers(event_enabler->container->session);
return 0;
}
_lttng_enabler_attach_filter_bytecode(
lttng_event_enabler_as_enabler(event_enabler), bytecode);
- lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ lttng_session_lazy_sync_event_enablers(event_enabler->container->session);
return 0;
}
_lttng_enabler_attach_exclusion(
lttng_event_enabler_as_enabler(event_enabler), excluder);
- lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ lttng_session_lazy_sync_event_enablers(event_enabler->container->session);
return 0;
}
* intesection of session and channel transient enable
* states.
*/
- enabled = enabled && session->tstate && event->chan->tstate;
+ enabled = enabled && session->tstate && event->container->tstate;
CMM_STORE_SHARED(event->enabled, enabled);
/*
desc = probe_desc->event_desc[i];
- if (!lttng_desc_match_enabler(desc,
- lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)))
+ if (lttng_desc_match_enabler(desc,
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)) <= 0)
continue;
/*
*/
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, desc->name);
cds_hlist_for_each_entry(event_notifier, node, head, hlist) {
/*
* description and id.
*/
if (event_notifier->desc == desc &&
- event_notifier->user_token == event_notifier_enabler->user_token) {
+ event_notifier->user_token == event_notifier_enabler->base.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->base.user_token,
event_notifier_enabler->error_counter_index,
event_notifier_group);
if (ret) {
}
if (is_owner) {
if (!obj->u.s.owner_ref) {
- ERR("Error decrementing owner reference");
+ ERR("Error decrementing owner reference\n");
return -EINVAL;
}
obj->u.s.owner_ref--;
static const struct lttng_ust_objd_ops lttng_event_notifier_group_ops;
static const struct lttng_ust_objd_ops lttng_session_ops;
static const struct lttng_ust_objd_ops lttng_channel_ops;
+static const struct lttng_ust_objd_ops lttng_counter_ops;
static const struct lttng_ust_objd_ops lttng_event_enabler_ops;
static const struct lttng_ust_objd_ops lttng_event_notifier_enabler_ops;
static const struct lttng_ust_objd_ops lttng_tracepoint_list_ops;
/* Initialize our lttng chan */
lttng_chan->chan = chan;
- lttng_chan->tstate = 1;
- lttng_chan->enabled = 1;
+ lttng_chan->enabled = 1; /* Backward compatibility */
lttng_chan->ctx = NULL;
- lttng_chan->session = session;
+ lttng_chan->session = session; /* Backward compatibility */
lttng_chan->ops = &transport->ops;
memcpy(<tng_chan->chan->backend.config,
transport->client_config,
lttng_chan->handle = channel_handle;
lttng_chan->type = type;
+ /* Set container properties */
+ lttng_chan->parent.type = LTTNG_EVENT_CONTAINER_CHANNEL;
+ lttng_chan->parent.session = session;
+ lttng_chan->parent.enabled = 1;
+ lttng_chan->parent.tstate = 1;
+ /*
+ * The ring buffer always coalesces hits from various event
+ * enablers matching a given event to a single event record within the
+ * ring buffer.
+ */
+ lttng_chan->parent.coalesce_hits = true;
+
/*
* We tolerate no failure path after channel creation. It will stay
* invariant for the rest of the session.
*/
objd_set_private(chan_objd, lttng_chan);
- lttng_chan->objd = chan_objd;
+ lttng_chan->parent.objd = chan_objd;
/* The channel created holds a reference on the session */
objd_ref(session_objd);
return chan_objd;
return ret;
}
+static
+long lttng_abi_session_create_counter(
+ int session_objd,
+ struct lttng_ust_counter *ust_counter,
+ union ust_args *uargs,
+ void *owner)
+{
+ struct lttng_session *session = objd_private(session_objd);
+ int counter_objd, ret, i;
+ char *counter_transport_name;
+ struct lttng_counter *counter = NULL;
+ struct lttng_event_container *container;
+ size_t dimension_sizes[LTTNG_UST_COUNTER_DIMENSION_MAX] = { 0 };
+ size_t number_dimensions;
+ const struct lttng_ust_counter_conf *counter_conf;
+
+ if (ust_counter->len != sizeof(*counter_conf)) {
+ ERR("LTTng: Map: Error counter configuration of wrong size.\n");
+ return -EINVAL;
+ }
+ counter_conf = uargs->counter.counter_data;
+
+ if (counter_conf->arithmetic != LTTNG_UST_COUNTER_ARITHMETIC_MODULAR) {
+ ERR("LTTng: Map: Error counter of the wrong type.\n");
+ return -EINVAL;
+ }
+
+ if (counter_conf->global_sum_step) {
+ /* Unsupported. */
+ return -EINVAL;
+ }
+
+ switch (counter_conf->bitness) {
+ case LTTNG_UST_COUNTER_BITNESS_64:
+ counter_transport_name = "counter-per-cpu-64-modular";
+ break;
+ case LTTNG_UST_COUNTER_BITNESS_32:
+ counter_transport_name = "counter-per-cpu-32-modular";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ number_dimensions = (size_t) counter_conf->number_dimensions;
+
+ for (i = 0; i < counter_conf->number_dimensions; i++) {
+ if (counter_conf->dimensions[i].has_underflow)
+ return -EINVAL;
+ if (counter_conf->dimensions[i].has_overflow)
+ return -EINVAL;
+ dimension_sizes[i] = counter_conf->dimensions[i].size;
+ }
+
+ counter_objd = objd_alloc(NULL, <tng_counter_ops, owner, "counter");
+ if (counter_objd < 0) {
+ ret = counter_objd;
+ goto objd_error;
+ }
+
+ counter = lttng_session_create_counter(session,
+ counter_transport_name,
+ number_dimensions, dimension_sizes,
+ 0, counter_conf->coalesce_hits);
+ if (!counter) {
+ ret = -EINVAL;
+ goto counter_error;
+ }
+ container = lttng_counter_get_event_container(counter);
+ objd_set_private(counter_objd, counter);
+ container->objd = counter_objd;
+ container->enabled = 1;
+ container->tstate = 1;
+ /* The channel created holds a reference on the session */
+ objd_ref(session_objd);
+ return counter_objd;
+
+counter_error:
+ {
+ int err;
+
+ err = lttng_ust_objd_unref(counter_objd, 1);
+ assert(!err);
+ }
+objd_error:
+ return ret;
+}
+
+
/**
* lttng_session_cmd - lttng session object command
*
case LTTNG_UST_SESSION_STATEDUMP:
return lttng_session_statedump(session);
case LTTNG_UST_COUNTER:
+ return lttng_abi_session_create_counter(objd,
+ (struct lttng_ust_counter *) arg,
+ uargs, owner);
case LTTNG_UST_COUNTER_GLOBAL:
case LTTNG_UST_COUNTER_CPU:
/* Not implemented yet. */
struct lttng_counter *counter = objd_private(objd);
if (counter) {
- return lttng_ust_objd_unref(counter->event_notifier_group->objd, 0);
+ return lttng_ust_objd_unref(counter->owner.event_notifier_group->objd, 0);
} else {
return -EINVAL;
}
struct lttng_event_notifier_group *event_notifier_group =
objd_private(event_notifier_group_objd);
struct lttng_counter *counter;
+ struct lttng_event_container *container;
int counter_objd, ret;
- struct lttng_counter_dimension dimensions[1];
size_t counter_len;
if (event_notifier_group->error_counter)
if (error_counter_conf->number_dimensions != 1)
return -EINVAL;
+ if (error_counter_conf->dimensions[0].has_underflow)
+ return -EINVAL;
+
+ if (error_counter_conf->dimensions[0].has_overflow)
+ return -EINVAL;
+
switch (error_counter_conf->bitness) {
case LTTNG_UST_COUNTER_BITNESS_64:
counter_transport_name = "counter-per-cpu-64-modular";
}
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, &counter_len, 0, false);
if (!counter) {
ret = -EINVAL;
goto create_error;
}
+ container = lttng_counter_get_event_container(counter);
event_notifier_group->error_counter_len = counter_len;
/*
cmm_smp_mb();
CMM_STORE_SHARED(event_notifier_group->error_counter, counter);
- counter->objd = counter_objd;
- counter->event_notifier_group = event_notifier_group; /* owner */
+ container->objd = counter_objd;
+ counter->owner.event_notifier_group = event_notifier_group; /* owner */
objd_set_private(counter_objd, counter);
/* The error counter holds a reference on the event_notifier group. */
}
static
-int lttng_abi_create_event_enabler(int channel_objd,
+int lttng_abi_create_event_enabler(int objd, /* channel or counter objd */
+ struct lttng_event_container *container,
struct lttng_ust_event *event_param,
+ struct lttng_ust_counter_key *key_param,
void *owner,
enum lttng_enabler_format_type format_type)
{
- struct lttng_channel *channel = objd_private(channel_objd);
struct lttng_event_enabler *enabler;
int event_objd, ret;
* 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_enabler_create(format_type, event_param,
+ key_param, container);
if (!enabler) {
ret = -ENOMEM;
goto event_error;
}
objd_set_private(event_objd, enabler);
- /* The event holds a reference on the channel */
- objd_ref(channel_objd);
+ /* The event holds a reference on the channel or counter */
+ objd_ref(objd);
return event_objd;
event_error:
union ust_args *uargs, void *owner)
{
struct lttng_channel *channel = objd_private(objd);
+ struct lttng_event_container *container = lttng_channel_get_event_container(channel);
if (cmd != LTTNG_UST_STREAM) {
/*
* 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,
+ return lttng_abi_create_event_enabler(objd, container, event_param, NULL,
owner, LTTNG_ENABLER_FORMAT_STAR_GLOB);
} else {
- return lttng_abi_create_event_enabler(objd, event_param,
+ return lttng_abi_create_event_enabler(objd, container, event_param, NULL,
owner, LTTNG_ENABLER_FORMAT_EVENT);
}
}
(struct lttng_ust_context *) arg, uargs,
&channel->ctx, channel->session);
case LTTNG_UST_ENABLE:
- return lttng_channel_enable(channel);
+ return lttng_event_container_enable(&channel->parent);
case LTTNG_UST_DISABLE:
- return lttng_channel_disable(channel);
+ return lttng_event_container_disable(&channel->parent);
case LTTNG_UST_FLUSH_BUFFER:
return channel->ops->flush_buffer(channel->chan, channel->handle);
default:
.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_COUNTER_GLOBAL:
+ * Returns a global counter object descriptor or failure.
+ * LTTNG_UST_COUNTER_CPU:
+ * Returns a per-cpu counter object descriptor or failure.
+ * LTTNG_UST_COUNTER_EVENT
+ * Returns an event object descriptor or failure.
+ * LTTNG_UST_ENABLE
+ * Enable recording for events in this channel (weak enable)
+ * LTTNG_UST_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 ust_args *uargs, void *owner)
+{
+ struct lttng_counter *counter = objd_private(objd);
+ struct lttng_event_container *container = lttng_counter_get_event_container(counter);
+
+ if (cmd != LTTNG_UST_COUNTER_GLOBAL && cmd != LTTNG_UST_COUNTER_CPU) {
+ /*
+ * Check if counter received all global/per-cpu objects.
+ */
+ if (!lttng_counter_ready(counter->counter))
+ return -EPERM;
+ }
+
+ switch (cmd) {
+ case LTTNG_UST_COUNTER_GLOBAL:
+ {
+ long ret;
+ int shm_fd;
+
+ shm_fd = uargs->counter_shm.shm_fd;
+ ret = lttng_counter_set_global_shm(counter->counter, shm_fd);
+ if (!ret) {
+ /* Take ownership of shm_fd. */
+ uargs->counter_shm.shm_fd = -1;
+ }
+ return ret;
+ }
+ case LTTNG_UST_COUNTER_CPU:
+ {
+ struct lttng_ust_counter_cpu *counter_cpu =
+ (struct lttng_ust_counter_cpu *) arg;
+ long ret;
+ int shm_fd;
+
+ shm_fd = uargs->counter_shm.shm_fd;
+ ret = lttng_counter_set_cpu_shm(counter->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_COUNTER_EVENT:
+ {
+ struct lttng_ust_counter_event *counter_event_param =
+ (struct lttng_ust_counter_event *) arg;
+ struct lttng_ust_event *event_param = &counter_event_param->event;
+ struct lttng_ust_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_enabler(objd, container, event_param, key_param,
+ owner, LTTNG_ENABLER_FORMAT_STAR_GLOB);
+ } else {
+ return lttng_abi_create_event_enabler(objd, container, event_param, key_param,
+ owner, LTTNG_ENABLER_FORMAT_EVENT);
+ }
+ }
+ case LTTNG_UST_ENABLE:
+ return lttng_event_container_enable(container);
+ case LTTNG_UST_DISABLE:
+ return lttng_event_container_disable(container);
+ default:
+ return -EINVAL;
+ }
+}
+
+
+static
+int lttng_counter_release(int objd)
+{
+ struct lttng_counter *counter = objd_private(objd);
+
+ if (counter) {
+ struct lttng_event_container *container = lttng_counter_get_event_container(counter);
+
+ return lttng_ust_objd_unref(container->session->objd, 0);
+ }
+ return 0;
+}
+
+static const struct lttng_ust_objd_ops lttng_counter_ops = {
+ .release = lttng_counter_release,
+ .cmd = lttng_counter_cmd,
+};
+
/**
* lttng_enabler_cmd - lttng control through object descriptors
*
struct lttng_event_enabler *event_enabler = objd_private(objd);
if (event_enabler)
- return lttng_ust_objd_unref(event_enabler->chan->objd, 0);
+ return lttng_ust_objd_unref(event_enabler->container->objd, 0);
return 0;
}
/* Counter commands */
[ LTTNG_UST_COUNTER_GLOBAL ] = "Create Counter Global",
[ LTTNG_UST_COUNTER_CPU ] = "Create Counter CPU",
+ [ LTTNG_UST_COUNTER_EVENT ] = "Create Counter Event",
};
static const char *str_timeout;
ret = -ENOSYS;
break;
}
+ case LTTNG_UST_COUNTER_EVENT:
+ {
+ /* Receive struct lttng_ust_counter_event */
+ struct lttng_ust_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;
+ }
default:
if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
#include <helper.h>
#include <lttng/ust-events.h>
+/*
+ * Enabler field, within whatever object is enabling an event. Target of
+ * backward reference.
+ */
+struct lttng_enabler {
+ enum lttng_enabler_format_type format_type;
+
+ /* head list of struct lttng_ust_filter_bytecode_node */
+ struct cds_list_head filter_bytecode_head;
+ /* head list of struct lttng_ust_excluder_node */
+ struct cds_list_head excluder_head;
+
+ struct lttng_ust_event event_param;
+ unsigned int enabled:1;
+
+ uint64_t user_token; /* User-provided token */
+};
+
struct lttng_event_enabler {
struct lttng_enabler base;
struct cds_list_head node; /* per-session list of enablers */
- struct lttng_channel *chan;
+ struct lttng_event_container *container;
+ struct lttng_counter_key key;
/*
* Unused, but kept around to make it explicit that the tracer can do
* it.
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_event_enabler *lttng_event_enabler_create(
enum lttng_enabler_format_type format_type,
struct lttng_ust_event *event_param,
- struct lttng_channel *chan);
+ const struct lttng_ust_counter_key *key,
+ struct lttng_event_container *container);
/*
* Destroy a `struct lttng_event_enabler` object.
LTTNG_HIDDEN
struct lttng_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 size_t *max_nr_elem,
+ int64_t global_sum_step,
+ bool coalesce_hits);
+
+LTTNG_HIDDEN
+struct lttng_counter *lttng_session_create_counter(
+ struct lttng_session *session,
+ const char *counter_transport_name,
+ size_t number_dimensions, const size_t *dimensions_sizes,
+ int64_t global_sum_step, bool coalesce_hits);
#endif /* _LTTNG_UST_EVENTS_INTERNAL_H */