LTTNG_UST_ABI_COUNTER_BITNESS_64 = 1,
};
-struct lttng_ust_abi_counter_key_string {
- uint32_t string_len; /* string length (includes \0) */
- char str[]; /* Null-terminated string. */
+struct lttng_ust_abi_key_token {
+ uint32_t len; /* length of child structure. */
+ uint32_t type; /* enum lttng_ust_abi_key_token_type */
+ /*
+ * The size of this structure is fixed because it is embedded into
+ * children structures.
+ */
} __attribute__((packed));
-struct lttng_ust_abi_key_token {
- uint32_t len; /* length of this structure. */
- uint32_t type; /* enum lttng_ust_key_token_type */
+/* Length of this structure excludes the following string. */
+struct lttng_ust_abi_key_token_string {
+ struct lttng_ust_abi_key_token parent;
+ uint32_t string_len; /* string length (includes \0) */
- /* Followed by a struct lttng_ust_abi_counter_key_string for LTTNG_UST_ABI_KEY_TOKEN_STRING. */
+ char str[]; /* Null-terminated string following this structure. */
} __attribute__((packed));
+/*
+ * token types event_name and provider_name don't have specific fields,
+ * so they do not need to derive their own specific child structure.
+ */
+
+/*
+ * Dimension indexing: All events should use the same key type to index
+ * a given map dimension.
+ */
+enum lttng_ust_abi_key_type {
+ LTTNG_UST_ABI_KEY_TYPE_TOKENS = 0, /* Dimension key is a set of tokens. */
+ LTTNG_UST_ABI_KEY_TYPE_INTEGER = 1, /* Dimension key is an integer value. */
+};
+
struct lttng_ust_abi_counter_key_dimension {
- uint32_t len; /* length of this structure */
+ uint32_t len; /* length of child structure */
+ uint32_t key_type; /* enum lttng_ust_abi_key_type */
+ /*
+ * The size of this structure is fixed because it is embedded into
+ * children structures.
+ */
+} __attribute__((packed));
+
+struct lttng_ust_abi_counter_key_dimension_tokens {
+ struct lttng_ust_abi_counter_key_dimension parent;
uint32_t nr_key_tokens;
- /* Followed by a variable-length array of key tokens */
+ /* Followed by an array of nr_key_tokens struct lttng_ust_abi_key_token elements. */
} __attribute__((packed));
+/*
+ * The "integer" key type is not implemented yet, but when it will be
+ * introduced in the future, its specific key dimension will allow
+ * defining the function to apply over input argument, bytecode to run
+ * and so on.
+ */
+
+enum lttng_ust_abi_counter_action {
+ LTTNG_UST_ABI_COUNTER_ACTION_INCREMENT = 0,
+
+ /*
+ * Can be extended with additional actions, such as decrement,
+ * set value, run bytecode, and so on.
+ */
+};
+
struct lttng_ust_abi_counter_event {
uint32_t len; /* length of this structure */
+ uint32_t action; /* enum lttng_ust_abi_counter_action */
struct lttng_ust_abi_event event;
uint32_t number_key_dimensions; /* array of dimensions is an array of var. len. elements. */
- /* Followed by a variable-length array of key dimensions */
+ /*
+ * Followed by additional data specific to the action, and by a
+ * variable-length array of key dimensions.
+ */
} __attribute__((packed));
enum lttng_ust_abi_counter_dimension_flags {
};
struct lttng_ust_abi_counter_dimension {
+ uint32_t key_type; /* enum lttng_ust_abi_key_type */
uint32_t flags; /* enum lttng_ust_abi_counter_dimension_flags */
uint64_t size; /* dimension size */
uint64_t underflow_index;
LTTNG_UST_CTL_NOTIFY_CMD_EVENT = 0,
LTTNG_UST_CTL_NOTIFY_CMD_CHANNEL = 1,
LTTNG_UST_CTL_NOTIFY_CMD_ENUM = 2,
+ LTTNG_UST_CTL_NOTIFY_CMD_KEY = 3,
};
enum lttng_ust_ctl_channel_header {
* Returns 0 on success, negative error value on error.
*/
int lttng_ust_ctl_reply_register_event(int sock,
- uint64_t id, /* id (input) */
+ uint32_t id, /* id (input) */
+ int ret_code); /* return code. 0 ok, negative error */
+
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ */
+int lttng_ust_ctl_recv_register_key(int sock,
+ int *session_objd, /* session descriptor (output) */
+ int *map_objd, /* map descriptor (output) */
+ uint32_t *dimension, /*
+ * Against which dimension is
+ * this key expressed. (output)
+ */
+ uint64_t **dimension_indexes, /*
+ * Indexes (output,
+ * dynamically
+ * allocated, must be
+ * free(3)'d by the
+ * caller if function
+ * returns success.)
+ * Contains @dimension
+ * elements.
+ */
+ char **key_string, /*
+ * key string (output,
+ * dynamically allocated, must
+ * be free(3)'d by the caller if
+ * function returns success.)
+ */
+ uint64_t *user_token);
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int lttng_ust_ctl_reply_register_key(int sock,
+ uint64_t index, /* Index within dimension (input) */
int ret_code); /* return code. 0 ok, negative error */
/*
LTTNG_UST_CTL_COUNTER_ARITHMETIC_SATURATION = 1,
};
+enum lttng_ust_ctl_key_type {
+ LTTNG_UST_CTL_KEY_TYPE_TOKENS = 0,
+ LTTNG_UST_CTL_KEY_TYPE_INTEGER = 1,
+};
+
/* Used as alloc flags. */
enum lttng_ust_ctl_counter_alloc {
LTTNG_UST_CTL_COUNTER_ALLOC_PER_CPU = (1 << 0),
uint64_t size;
uint64_t underflow_index;
uint64_t overflow_index;
+ enum lttng_ust_ctl_key_type key_type;
uint8_t has_underflow;
uint8_t has_overflow;
};
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.
+ *
+ * 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_ctx {
+ uint32_t struct_size; /* Size of this structure. */
+ int args_available; /* Input arguments are available. */
+
+ /* 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
struct lttng_ust_channel_counter *chan;
+ int use_args; /* Use input arguments. */
+
/* End of base ABI. Fields below should be used after checking 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);
+ int (*counter_hit)(struct lttng_ust_event_counter *event_counter,
+ const char *stack_data,
+ struct lttng_ust_probe_ctx *probe_ctx,
+ struct lttng_ust_event_counter_ctx *event_counter_ctx);
/* End of base ABI. Fields below should be used after checking struct_size. */
};
case LTTNG_UST_EVENT_TYPE_COUNTER: \
{ \
struct lttng_ust_event_counter *__event_counter = (struct lttng_ust_event_counter *) __event->child; \
+ struct lttng_ust_event_counter_ctx __event_counter_ctx; \
\
- (void) __event_counter->chan->ops->event_counter_add(__event_counter, 1); \
+ __event_counter_ctx.struct_size = sizeof(struct lttng_ust_event_counter_ctx); \
+ __event_counter_ctx.args_available = CMM_ACCESS_ONCE(__event_counter->use_args); \
+ \
+ if (caa_unlikely(!__interpreter_stack_prepared && __event_counter_ctx.args_available)) \
+ lttng_ust__event_prepare_interpreter_stack__##_provider##___##_name(__stackvar.__interpreter_stack_data, \
+ LTTNG_UST__TP_ARGS_DATA_VAR(_args)); \
+ \
+ (void) __event_counter->chan->ops->counter_hit(__event_counter, \
+ __stackvar.__interpreter_stack_data, \
+ &__probe_ctx, \
+ &__event_counter_ctx); \
break; \
} \
} \
if (!counter)
goto error;
lttng_chan_counter->priv->counter = counter;
+ for (i = 0; i < nr_dimensions; i++)
+ lttng_chan_counter->priv->dimension_key_types[i] = dimensions[i].key_type;
return lttng_chan_counter;
error:
return lttng_counter_add(&client_config, counter->priv->counter, dimension_indexes, v);
}
-static int event_counter_add(struct lttng_ust_event_counter *event_counter, int64_t v)
+static int counter_hit(struct lttng_ust_event_counter *event_counter,
+ const char *stack_data __attribute__((unused)),
+ struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)),
+ struct lttng_ust_event_counter_ctx *event_counter_ctx __attribute__((unused)))
{
struct lttng_ust_channel_counter *counter = event_counter->chan;
- size_t index = event_counter->priv->parent.id;
- return counter_add(counter, &index, v);
+ switch (event_counter->priv->action) {
+ case LTTNG_EVENT_COUNTER_ACTION_INCREMENT:
+ {
+ size_t index = event_counter->priv->parent.id;
+ return counter_add(counter, &index, 1);
+ }
+ default:
+ return -ENOSYS;
+ }
}
static int counter_read(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes, int cpu,
.counter_aggregate = counter_aggregate,
.counter_clear = counter_clear,
}),
- .event_counter_add = event_counter_add,
+ .counter_hit = counter_hit,
},
.client_config = &client_config,
};
if (!counter)
goto error;
lttng_chan_counter->priv->counter = counter;
+ for (i = 0; i < nr_dimensions; i++)
+ lttng_chan_counter->priv->dimension_key_types[i] = dimensions[i].key_type;
return lttng_chan_counter;
error:
return lttng_counter_add(&client_config, counter->priv->counter, dimension_indexes, v);
}
-static int event_counter_add(struct lttng_ust_event_counter *event_counter, int64_t v)
+static int counter_hit(struct lttng_ust_event_counter *event_counter,
+ const char *stack_data __attribute__((unused)),
+ struct lttng_ust_probe_ctx *probe_ctx __attribute__((unused)),
+ struct lttng_ust_event_counter_ctx *event_counter_ctx __attribute__((unused)))
{
struct lttng_ust_channel_counter *counter = event_counter->chan;
- size_t index = event_counter->priv->parent.id;
- return counter_add(counter, &index, v);
+ switch (event_counter->priv->action) {
+ case LTTNG_EVENT_COUNTER_ACTION_INCREMENT:
+ {
+ size_t index = event_counter->priv->parent.id;
+ return counter_add(counter, &index, 1);
+ }
+ default:
+ return -ENOSYS;
+ }
}
static int counter_read(struct lttng_ust_channel_counter *counter, const size_t *dimension_indexes, int cpu,
.counter_aggregate = counter_aggregate,
.counter_clear = counter_clear,
}),
- .event_counter_add = event_counter_add,
+ .counter_hit = counter_hit,
},
.client_config = &client_config,
};
} arg;
};
+enum lttng_key_type {
+ LTTNG_KEY_TYPE_TOKENS = 0,
+ LTTNG_KEY_TYPE_INTEGER = 1,
+};
+
#define LTTNG_NR_KEY_TOKEN 8
struct lttng_counter_key_dimension {
- size_t nr_key_tokens;
- struct lttng_key_token key_tokens[LTTNG_NR_KEY_TOKEN];
+ enum lttng_key_type key_type;
+
+ union {
+ struct {
+ size_t nr_key_tokens;
+ struct lttng_key_token key_tokens[LTTNG_NR_KEY_TOKEN];
+ } tokens;
+ } u;
};
#define LTTNG_COUNTER_DIMENSION_MAX 4
uint64_t size;
uint64_t underflow_index;
uint64_t overflow_index;
+ enum lttng_key_type key_type;
uint8_t has_underflow;
uint8_t has_overflow;
};
struct lttng_ust_channel_buffer *chan;
};
+enum lttng_event_counter_action {
+ LTTNG_EVENT_COUNTER_ACTION_INCREMENT = 0,
+};
+
struct lttng_event_counter_enabler {
struct lttng_event_enabler_session_common parent;
struct lttng_ust_channel_counter *chan;
struct lttng_counter_key key;
+
+ enum lttng_event_counter_action action;
};
struct lttng_event_notifier_enabler {
struct lttng_ust_event_session_common_private parent;
struct lttng_ust_event_counter *pub; /* Public event interface */
+ enum lttng_event_counter_action action;
char key[LTTNG_KEY_TOKEN_STRING_LEN_MAX];
};
struct lttng_session *session;
struct cds_list_head node; /* Counter list (in session) */
size_t free_index; /* Next index to allocate */
+ enum lttng_key_type dimension_key_types[LTTNG_COUNTER_DIMENSION_MAX];
};
/*
const struct lttng_ust_event_field * const *lttng_fields,
const char *model_emf_uri,
uint64_t user_token,
- uint64_t *id) /* event id (output) */
+ uint32_t *id) /* event id (output) */
{
ssize_t len;
struct {
if (reply.r.ret_code < 0)
return reply.r.ret_code;
*id = reply.r.id;
- DBG("Sent register event notification for name \"%s\": ret_code %d, id %" PRIu64 "\n",
+ DBG("Sent register event notification for name \"%s\": ret_code %d, id %" PRIu32 "\n",
event_name, reply.r.ret_code, reply.r.id);
return 0;
default:
return ret;
}
+/*
+ * Returns 0 on success, negative error value on error.
+ * Returns -EPIPE or -ECONNRESET if other end has hung up.
+ */
+int ustcomm_register_key(int sock,
+ int session_objd, /* session descriptor */
+ int map_objd, /* map descriptor */
+ uint32_t dimension,
+ const uint64_t *dimension_indexes,
+ const char *key_string, /* key string (input) */
+ uint64_t user_token,
+ uint64_t *index) /* (output) */
+{
+ ssize_t len;
+ struct {
+ struct ustcomm_notify_hdr header;
+ struct ustcomm_notify_key_msg m;
+ } msg;
+ struct {
+ struct ustcomm_notify_hdr header;
+ struct ustcomm_notify_key_reply r;
+ } reply;
+ size_t dimension_indexes_len;
+ int ret;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.header.notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_KEY;
+ msg.m.session_objd = session_objd;
+ msg.m.map_objd = map_objd;
+ msg.m.dimension = dimension;
+ dimension_indexes_len = sizeof(uint64_t) * dimension;
+ msg.m.key_string_len = strlen(key_string) + 1;
+ msg.m.user_token = user_token;
+
+ len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg));
+ if (len > 0 && len != sizeof(msg)) {
+ ret = -EIO;
+ goto error_send;
+ }
+ if (len < 0) {
+ ret = len;
+ goto error_send;
+ }
+
+ /* send dimension_indexes */
+ if (dimension_indexes) {
+ len = ustcomm_send_unix_sock(sock, dimension_indexes, dimension_indexes_len);
+ if (len > 0 && len != dimension_indexes_len) {
+ ret = -EIO;
+ goto error_dimension_indexes;
+ }
+ if (len < 0) {
+ ret = len;
+ goto error_dimension_indexes;
+ }
+ }
+
+ /* send key_string */
+ len = ustcomm_send_unix_sock(sock, key_string, msg.m.key_string_len);
+ if (len > 0 && len != dimension_indexes_len) {
+ ret = -EIO;
+ goto error_dimension_indexes;
+ }
+ if (len < 0) {
+ ret = len;
+ goto error_dimension_indexes;
+ }
+
+ /* receive reply */
+ len = ustcomm_recv_unix_sock(sock, &reply, sizeof(reply));
+ switch (len) {
+ case 0: /* orderly shutdown */
+ return -EPIPE;
+ case sizeof(reply):
+ if (reply.header.notify_cmd != msg.header.notify_cmd) {
+ ERR("Unexpected result message command "
+ "expected: %u vs received: %u\n",
+ msg.header.notify_cmd, reply.header.notify_cmd);
+ return -EINVAL;
+ }
+ if (reply.r.ret_code > 0)
+ return -EINVAL;
+ if (reply.r.ret_code < 0)
+ return reply.r.ret_code;
+ *index = reply.r.index;
+ DBG("Sent register key notification for key \"%s\": ret_code %d, index %" PRIu64 "\n",
+ key_string, reply.r.ret_code, reply.r.index);
+ return 0;
+ default:
+ if (len < 0) {
+ /* Transport level error */
+ if (errno == EPIPE || errno == ECONNRESET)
+ len = -errno;
+ return len;
+ } else {
+ ERR("incorrect message size: %zd\n", len);
+ return len;
+ }
+ }
+ /* Unreached. */
+
+ /* Error path only. */
+error_dimension_indexes:
+error_send:
+ return ret;
+}
+
/*
* Returns 0 on success, negative error value on error.
* Returns -EPIPE or -ECONNRESET if other end has hung up.
/* followed by signature, fields, and model_emf_uri */
} __attribute__((packed));
-#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 24
+#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 32
struct ustcomm_notify_event_reply {
int32_t ret_code; /* 0: ok, negative: error code */
-
- /* 32-bit (lower bits) event id for backward compatibility with ABI major < 10 */
- uint32_t old_event_id; /* TODO: remove field on future protocol compatibility break. */
- uint64_t id; /* 64-bit event id. */
+ uint32_t id; /* 32-bit event id. */
char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING];
} __attribute__((packed));
+#define USTCOMM_NOTIFY_KEY_MSG_PADDING 24
+struct ustcomm_notify_key_msg {
+ uint32_t session_objd;
+ uint32_t map_objd;
+ uint32_t dimension;
+ uint32_t key_string_len;
+ uint64_t user_token;
+ char padding[USTCOMM_NOTIFY_KEY_MSG_PADDING];
+ /* followed by dimension_indexes (array of @dimension uint64_t items) and key_string. */
+} __attribute__((packed));
+
+#define USTCOMM_NOTIFY_KEY_REPLY_PADDING 32
+struct ustcomm_notify_key_reply {
+ int32_t ret_code; /* 0: ok, negative: error code */
+ uint64_t index; /* 64-bit key index. */
+ char padding[USTCOMM_NOTIFY_KEY_REPLY_PADDING];
+} __attribute__((packed));
+
#define USTCOMM_NOTIFY_ENUM_MSG_PADDING 32
struct ustcomm_notify_enum_msg {
uint32_t session_objd;
const struct lttng_ust_event_field * const *fields,
const char *model_emf_uri,
uint64_t user_token,
- uint64_t *id) /* (output) */
+ uint32_t *id) /* (output) */
+ __attribute__((visibility("hidden")));
+
+/*
+ * Returns 0 on success, negative error value on error.
+ * Returns -EPIPE or -ECONNRESET if other end has hung up.
+ */
+int ustcomm_register_key(int sock,
+ int session_objd, /* session descriptor */
+ int map_objd, /* map descriptor */
+ uint32_t dimension,
+ const uint64_t *dimension_indexes,
+ const char *key_string, /* key string (input) */
+ uint64_t user_token,
+ uint64_t *index) /* (output) */
__attribute__((visibility("hidden")));
/*
case 2:
*notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_ENUM;
break;
+ case 3:
+ *notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_KEY;
+ break;
default:
return -EINVAL;
}
* Returns 0 on success, negative error value on error.
*/
int lttng_ust_ctl_reply_register_event(int sock,
- uint64_t id,
+ uint32_t id,
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.old_event_id = (uint32_t) id; /* For backward compatibility */
reply.r.id = id;
len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply));
if (len > 0 && len != sizeof(reply))
return 0;
}
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ */
+int lttng_ust_ctl_recv_register_key(int sock,
+ int *session_objd, /* session descriptor (output) */
+ int *map_objd, /* map descriptor (output) */
+ uint32_t *dimension, /*
+ * Against which dimension is
+ * this key expressed. (output)
+ */
+ uint64_t **dimension_indexes, /*
+ * Indexes (output,
+ * dynamically
+ * allocated, must be
+ * free(3)'d by the
+ * caller if function
+ * returns success.)
+ * Contains @dimension
+ * elements.
+ */
+ char **key_string, /*
+ * key string (output,
+ * dynamically allocated, must
+ * be free(3)'d by the caller if
+ * function returns success.)
+ */
+ uint64_t *user_token)
+{
+ ssize_t len;
+ struct ustcomm_notify_key_msg msg;
+ size_t dimension_indexes_len, key_string_len;
+ uint64_t *a_dimension_indexes = NULL;
+ char *a_key_string = NULL;
+
+ len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg));
+ if (len > 0 && len != sizeof(msg))
+ return -EIO;
+ if (len == 0)
+ return -EPIPE;
+ if (len < 0)
+ return len;
+
+ *session_objd = msg.session_objd;
+ *map_objd = msg.map_objd;
+ *dimension = msg.dimension;
+ dimension_indexes_len = msg.dimension * sizeof(uint64_t);
+ key_string_len = msg.key_string_len;
+ *user_token = msg.user_token;
+
+ if (dimension_indexes_len) {
+ /* recv dimension_indexes */
+ a_dimension_indexes = zmalloc(dimension_indexes_len);
+ if (!a_dimension_indexes) {
+ len = -ENOMEM;
+ goto error;
+ }
+ len = ustcomm_recv_unix_sock(sock, a_dimension_indexes, dimension_indexes_len);
+ if (len > 0 && len != dimension_indexes_len) {
+ len = -EIO;
+ goto error;
+ }
+ if (len == 0) {
+ len = -EPIPE;
+ goto error;
+ }
+ if (len < 0) {
+ goto error;
+ }
+ }
+
+ if (key_string_len) {
+ /* recv key_string */
+ a_key_string = zmalloc(key_string_len);
+ if (!a_key_string) {
+ len = -ENOMEM;
+ goto error;
+ }
+ len = ustcomm_recv_unix_sock(sock, a_key_string, key_string_len);
+ if (len > 0 && len != key_string_len) {
+ len = -EIO;
+ goto error;
+ }
+ if (len == 0) {
+ len = -EPIPE;
+ goto error;
+ }
+ if (len < 0) {
+ goto error;
+ }
+ /* Enforce end of string */
+ a_key_string[key_string_len - 1] = '\0';
+ }
+
+ *dimension_indexes = a_dimension_indexes;
+ *key_string = a_key_string;
+ return 0;
+
+error:
+ free(a_key_string);
+ free(a_dimension_indexes);
+ return len;
+}
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int lttng_ust_ctl_reply_register_key(int sock,
+ uint64_t index, /* Index within dimension (input) */
+ int ret_code) /* return code. 0 ok, negative error */
+{
+ ssize_t len;
+ struct {
+ struct ustcomm_notify_hdr header;
+ struct ustcomm_notify_key_reply r;
+ } reply;
+
+ memset(&reply, 0, sizeof(reply));
+ reply.header.notify_cmd = LTTNG_UST_CTL_NOTIFY_CMD_KEY;
+ reply.r.ret_code = ret_code;
+ reply.r.index = index;
+ len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply));
+ if (len > 0 && len != sizeof(reply))
+ return -EIO;
+ if (len < 0)
+ return len;
+ return 0;
+}
+
/*
* Returns 0 on success, negative UST or system error value on error.
*/
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;
+ switch (dimensions[i].key_type) {
+ case LTTNG_UST_CTL_KEY_TYPE_TOKENS:
+ ust_dim[i].key_type = LTTNG_KEY_TYPE_TOKENS;
+ break;
+ case LTTNG_UST_CTL_KEY_TYPE_INTEGER: /* Fall-through */
+ default:
+ goto free_attr;
+ }
}
counter->counter = transport->ops.priv->counter_create(nr_dimensions,
ust_dim, global_sum_step, global_counter_fd,
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;
+ switch (counter->attr->dimensions[0].key_type) {
+ case LTTNG_UST_CTL_KEY_TYPE_TOKENS:
+ dimension->key_type = LTTNG_UST_ABI_KEY_TYPE_TOKENS;
+ break;
+ case LTTNG_UST_CTL_KEY_TYPE_INTEGER: /* Fall-through */
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
counter_data = zmalloc(sizeof(*counter_data));
if (!counter_data) {
old_counter_conf.dimensions[0].has_overflow = (dimension->flags & LTTNG_UST_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW) ? 1 : 0;
old_counter_conf.dimensions[0].underflow_index = dimension->underflow_index;
old_counter_conf.dimensions[0].overflow_index = dimension->overflow_index;
+ if (dimension->key_type != LTTNG_UST_ABI_KEY_TYPE_TOKENS)
+ return -EINVAL;
size = sizeof(old_counter_conf);
lum.handle = parent_handle;
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];
+ /* Currently only tokens keys are supported. */
+ if (dim->key_type != LTTNG_KEY_TYPE_TOKENS)
+ return -EINVAL;
+ for (i = 0; i < dim->u.tokens.nr_key_tokens; i++) {
+ const struct lttng_key_token *token = &dim->u.tokens.key_tokens[i];
size_t token_len;
const char *str;
event_counter->priv->parent.parent.user_token = event_counter_enabler->parent.parent.user_token;
event_counter->priv->parent.parent.desc = desc;
strcpy(event_counter_priv->key, key_string);
+ event_counter_priv->action = event_counter_enabler->action;
return event_counter->parent;
}
default:
{
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 *event_enabler_session =
caa_container_of(event_enabler, struct lttng_event_enabler_session_common, parent);
caa_container_of(event->priv, struct lttng_ust_event_session_common_private, parent);
struct lttng_ust_session *session = event_enabler_session->chan->session;
const struct lttng_ust_event_desc *desc = event->priv->desc;
- int notify_socket, loglevel;
+ int notify_socket, loglevel, ret;
const char *uri;
+ uint32_t id;
if (desc->loglevel)
loglevel = *(*desc->loglevel);
return notify_socket;
/* Fetch event ID from sessiond */
- return ustcomm_register_event(notify_socket,
+ ret = ustcomm_register_event(notify_socket,
session,
session->priv->objd,
event_enabler_session->chan->priv->objd,
desc->tp_class->fields,
uri,
event_enabler_session->parent.user_token,
- &event_session_priv->id);
+ &id);
+ if (ret)
+ return ret;
+ event_session_priv->id = id;
+ return 0;
+ }
+ case LTTNG_EVENT_ENABLER_TYPE_COUNTER:
+ {
+ struct lttng_event_enabler_session_common *event_enabler_session =
+ caa_container_of(event_enabler, struct lttng_event_enabler_session_common, parent);
+ 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_enabler_session->chan->session;
+ uint64_t dimension_index[LTTNG_COUNTER_DIMENSION_MAX];
+ int notify_socket, ret;
+
+ notify_socket = lttng_get_notify_socket(session->priv->owner);
+ if (notify_socket < 0)
+ return notify_socket;
+
+ /* Fetch key index from sessiond */
+ ret = ustcomm_register_key(notify_socket,
+ session->priv->objd,
+ event_enabler_session->chan->priv->objd,
+ 0, /* target dimension */
+ NULL,
+ name,
+ event_enabler_session->parent.user_token,
+ dimension_index); /* Filled up to target dimension. */
+ if (ret)
+ return ret;
+ event_session_priv->id = dimension_index[0];
+ return 0;
}
case LTTNG_EVENT_ENABLER_TYPE_NOTIFIER:
struct lttng_ust_channel_counter *chan)
{
struct lttng_event_counter_enabler *event_enabler;
+ enum lttng_event_counter_action action;
event_enabler = zmalloc(sizeof(*event_enabler));
if (!event_enabler)
return NULL;
+
+ switch (counter_event->action) {
+ case LTTNG_UST_ABI_COUNTER_ACTION_INCREMENT:
+ action = LTTNG_EVENT_COUNTER_ACTION_INCREMENT;
+ break;
+ default:
+ goto error;
+ }
+ event_enabler->action = action;
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);
lttng_session_lazy_sync_event_enablers(event_enabler->chan->parent->session);
return event_enabler;
+
+error:
+ free(event_enabler);
+ return NULL;
}
struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
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;
+ switch (dimension.key_type) {
+ case LTTNG_UST_ABI_KEY_TYPE_TOKENS:
+ dimensions[0].key_type = LTTNG_KEY_TYPE_TOKENS;
+ break;
+ case LTTNG_UST_ABI_KEY_TYPE_INTEGER: /* Fall-through */
+ default:
+ return -EINVAL;
+ }
counter_objd = objd_alloc(NULL, <tng_counter_ops, owner, "counter");
if (counter_objd < 0) {
return ret;
}
+static
+int copy_counter_key_dimension_tokens(const struct lttng_ust_abi_counter_key_dimension_tokens *abi_dim_tokens,
+ const char *addr, size_t *offset, size_t arg_len, struct lttng_counter_key_dimension *internal_dim)
+{
+ struct lttng_ust_abi_counter_key_dimension_tokens dim_tokens;
+ size_t nr_key_tokens, j;
+ int ret;
+
+ if (abi_dim_tokens->parent.len < sizeof(struct lttng_ust_abi_counter_key_dimension_tokens))
+ return -EINVAL;
+ ret = copy_abi_struct(&dim_tokens, sizeof(dim_tokens), abi_dim_tokens, abi_dim_tokens->parent.len);
+ if (ret)
+ return ret;
+ nr_key_tokens = dim_tokens.nr_key_tokens;
+ if (!nr_key_tokens || nr_key_tokens > LTTNG_NR_KEY_TOKEN)
+ return -EINVAL;
+ internal_dim->key_type = LTTNG_KEY_TYPE_TOKENS;
+ internal_dim->u.tokens.nr_key_tokens = nr_key_tokens;
+ *offset += sizeof(struct lttng_ust_abi_counter_key_dimension_tokens);
+ for (j = 0; j < nr_key_tokens; j++) {
+ struct lttng_key_token *internal_token = &internal_dim->u.tokens.key_tokens[j];
+ const struct lttng_ust_abi_key_token *abi_token;
+
+ if (*offset + sizeof(struct lttng_ust_abi_key_token) > arg_len)
+ return -EINVAL;
+ abi_token = (const struct lttng_ust_abi_key_token *)(addr + *offset);
+ if (abi_token->len < sizeof(struct lttng_ust_abi_key_token))
+ return -EINVAL;
+ if (*offset + abi_token->len > arg_len)
+ return -EINVAL;
+ switch (abi_token->type) {
+ case LTTNG_UST_ABI_KEY_TOKEN_STRING:
+ {
+ const struct lttng_ust_abi_key_token_string *abi_key_string;
+ struct lttng_ust_abi_key_token_string token_string;
+
+ if (abi_token->len < sizeof(struct lttng_ust_abi_key_token_string))
+ return -EINVAL;
+ abi_key_string = (const struct lttng_ust_abi_key_token_string *)(addr + *offset);
+ ret = copy_abi_struct(&token_string, sizeof(token_string), abi_key_string, abi_key_string->parent.len);
+ if (ret)
+ return ret;
+ *offset += abi_key_string->parent.len;
+ internal_token->type = LTTNG_KEY_TOKEN_STRING;
+ if (!abi_key_string->string_len || abi_key_string->string_len > LTTNG_KEY_TOKEN_STRING_LEN_MAX)
+ return -EINVAL;
+ *offset += abi_key_string->string_len;
+ if (*offset > arg_len)
+ return -EINVAL;
+ if (abi_key_string->str[abi_key_string->string_len - 1] != '\0' ||
+ strlen(abi_key_string->str) + 1 != abi_key_string->string_len)
+ return -EINVAL;
+ memcpy(internal_token->arg.string, abi_key_string->str, abi_key_string->string_len);
+ break;
+ }
+ case LTTNG_UST_ABI_KEY_TOKEN_EVENT_NAME:
+ internal_token->type = LTTNG_KEY_TOKEN_EVENT_NAME;
+ *offset += abi_token->len;
+ break;
+ case LTTNG_UST_ABI_KEY_TOKEN_PROVIDER_NAME:
+ internal_token->type = LTTNG_KEY_TOKEN_PROVIDER_NAME;
+ *offset += abi_token->len;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
static
int copy_counter_key(struct lttng_counter_key *internal_key,
- unsigned long arg, size_t arg_len,
+ unsigned long arg, size_t action_fields_len, size_t arg_len,
const struct lttng_ust_abi_counter_event *counter_event)
{
- size_t i, j, nr_dimensions, offset = 0;
- char *addr = (char *)arg;
+ size_t i, nr_dimensions, offset = 0;
+ const char *addr = (const char *)arg;
int ret;
nr_dimensions = counter_event->number_key_dimensions;
if (nr_dimensions != 1)
return -EINVAL;
internal_key->nr_dimensions = nr_dimensions;
- offset += counter_event->len;
+ offset += counter_event->len + action_fields_len;
for (i = 0; i < nr_dimensions; i++) {
- const struct lttng_ust_abi_counter_key_dimension *abi_dim;
- struct lttng_ust_abi_counter_key_dimension dim;
struct lttng_counter_key_dimension *internal_dim = &internal_key->key_dimensions[i];
- size_t nr_key_tokens;
+ const struct lttng_ust_abi_counter_key_dimension *abi_dim;
abi_dim = (const struct lttng_ust_abi_counter_key_dimension *)(addr + offset);
- offset += abi_dim->len;
- if (offset > arg_len || abi_dim->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_key_dimension, nr_key_tokens))
+ if (offset + abi_dim->len > arg_len || abi_dim->len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_key_dimension, key_type))
return -EINVAL;
- ret = copy_abi_struct(&dim, sizeof(dim), abi_dim, abi_dim->len);
- if (ret)
- return ret;
- nr_key_tokens = dim.nr_key_tokens;
- if (!nr_key_tokens || nr_key_tokens > LTTNG_NR_KEY_TOKEN)
- return -EINVAL;
- internal_dim->nr_key_tokens = nr_key_tokens;
- for (j = 0; j < nr_key_tokens; j++) {
- const struct lttng_ust_abi_key_token *abi_token;
- struct lttng_ust_abi_key_token token;
- struct lttng_key_token *internal_token = &internal_dim->key_tokens[j];
-
- abi_token = (const struct lttng_ust_abi_key_token *)(addr + offset);
- offset += abi_token->len;
- if (offset > arg_len || abi_token->len < lttng_ust_offsetofend(struct lttng_ust_abi_key_token, type))
- return -EINVAL;
- ret = copy_abi_struct(&token, sizeof(token), abi_token, abi_token->len);
+ switch (abi_dim->key_type) {
+ case LTTNG_UST_ABI_KEY_TYPE_TOKENS:
+ {
+ struct lttng_ust_abi_counter_key_dimension_tokens *dim_tokens =
+ caa_container_of(abi_dim, struct lttng_ust_abi_counter_key_dimension_tokens, parent);
+ ret = copy_counter_key_dimension_tokens(dim_tokens, addr, &offset, arg_len,
+ internal_dim);
if (ret)
return ret;
- switch (token.type) {
- case LTTNG_UST_ABI_KEY_TOKEN_STRING:
- {
- const struct lttng_ust_abi_counter_key_string *abi_key_string;
-
- abi_key_string = (const struct lttng_ust_abi_counter_key_string *)(addr + offset);
- offset += sizeof(struct lttng_ust_abi_counter_key_string);
- if (offset > arg_len)
- return -EINVAL;
- internal_token->type = LTTNG_KEY_TOKEN_STRING;
- if (!abi_key_string->string_len || abi_key_string->string_len > LTTNG_KEY_TOKEN_STRING_LEN_MAX)
- return -EINVAL;
- offset += abi_key_string->string_len;
- if (offset > arg_len)
- return -EINVAL;
- if (abi_key_string->str[abi_key_string->string_len - 1] != '\0' ||
- strlen(abi_key_string->str) + 1 != abi_key_string->string_len)
- return -EINVAL;
- memcpy(internal_token->arg.string, abi_key_string->str, abi_key_string->string_len);
- break;
- }
- case LTTNG_UST_ABI_KEY_TOKEN_EVENT_NAME:
- internal_token->type = LTTNG_KEY_TOKEN_EVENT_NAME;
- break;
- case LTTNG_UST_ABI_KEY_TOKEN_PROVIDER_NAME:
- internal_token->type = LTTNG_KEY_TOKEN_PROVIDER_NAME;
- break;
- default:
- return -EINVAL;
- }
+ break;
+ }
+ default:
+ return -EINVAL;
}
}
return 0;
struct lttng_counter_key counter_key = {};
struct lttng_event_counter_enabler *enabler;
enum lttng_enabler_format_type format_type;
+ size_t action_fields_len = 0;
int event_objd, ret;
+ size_t i;
if (arg_len < lttng_ust_offsetofend(struct lttng_ust_abi_counter_event, number_key_dimensions)) {
return -EINVAL;
if (ret) {
return ret;
}
+ switch (counter_event.action) {
+ case LTTNG_UST_ABI_COUNTER_ACTION_INCREMENT:
+ /* No additional fields specific to this action. */
+ break;
+ default:
+ return -EINVAL;
+ }
counter_event.event.name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0';
if (strutils_is_star_glob_pattern(counter_event.event.name)) {
format_type = LTTNG_ENABLER_FORMAT_STAR_GLOB;
} else {
format_type = LTTNG_ENABLER_FORMAT_EVENT;
}
- ret = copy_counter_key(&counter_key, arg, arg_len, &counter_event);
+ ret = copy_counter_key(&counter_key, arg, action_fields_len, arg_len, &counter_event);
if (ret) {
return ret;
}
+ /*
+ * Validate that each dimension counter key type match the map
+ * key type.
+ */
+ for (i = 0; i < counter_key.nr_dimensions; i++) {
+ if (channel->priv->dimension_key_types[i] != counter_key.key_dimensions[i].key_type)
+ return -EINVAL;
+ }
event_objd = objd_alloc(NULL, <tng_event_enabler_ops, owner,
"event enabler");
if (event_objd < 0) {