*/
} LTTNG_PACKED;
+#define LTTNG_UST_TRIGGER_PADDING1 16
+#define LTTNG_UST_TRIGGER_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
+struct lttng_ust_trigger {
+ uint64_t id;
+ 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 */
+ char padding[LTTNG_UST_TRIGGER_PADDING1];
+
+ /* Per instrumentation type configuration */
+ union {
+ char padding[LTTNG_UST_TRIGGER_PADDING2];
+ } u;
+} LTTNG_PACKED;
+
+#define LTTNG_TRIGGER_NOTIFICATION_PADDING 32
+struct lttng_ust_trigger_notification {
+ uint64_t id;
+ char padding[LTTNG_TRIGGER_NOTIFICATION_PADDING];
+} LTTNG_PACKED;
+
#define LTTNG_UST_EVENT_PADDING1 16
#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
struct lttng_ust_event {
LTTNG_UST_OBJECT_TYPE_STREAM = 1,
LTTNG_UST_OBJECT_TYPE_EVENT = 2,
LTTNG_UST_OBJECT_TYPE_CONTEXT = 3,
+ LTTNG_UST_OBJECT_TYPE_TRIGGER_GROUP = 4,
+ LTTNG_UST_OBJECT_TYPE_TRIGGER = 5,
};
#define LTTNG_UST_OBJECT_DATA_PADDING1 32
#define LTTNG_UST_FILTER _UST_CMD(0xA0)
#define LTTNG_UST_EXCLUSION _UST_CMD(0xA1)
+/* Trigger commands */
+#define LTTNG_UST_TRIGGER_GROUP_CREATE _UST_CMD(0xB0)
+#define LTTNG_UST_TRIGGER_CREATE \
+ _UST_CMDW(0xB1, struct lttng_ust_trigger)
+
#define LTTNG_UST_ROOT_HANDLE 0
struct lttng_ust_obj;
struct {
char *ctxname;
} app_context;
+ struct {
+ int trigger_notif_fd;
+ } trigger_handle;
};
struct lttng_ust_objd_ops {
int ustctl_start_session(int sock, int handle);
int ustctl_stop_session(int sock, int handle);
+/*
+ * ustctl_create_trigger_group creates a trigger group. It establishes the
+ * connection with the application by providing a file descriptor of the pipe
+ * to be used by the application when a trigger of that group is fired. It
+ * returns a handle to be used when creating trigger in that group.
+ */
+int ustctl_create_trigger_group(int sock, int pipe_fd,
+ struct lttng_ust_object_data **trigger_group);
+
+/*
+ * ustctl_create_trigger creates a trigger in a trigger group giving a trigger
+ * description and a trigger group handle. It returns a trigger handle to be
+ * used when enabling the trigger, attaching filter, attaching exclusion, and
+ * disabling the trigger.
+ */
+int ustctl_create_trigger(int sock, struct lttng_ust_trigger *trigger,
+ struct lttng_ust_object_data *trigger_group,
+ struct lttng_ust_object_data **trigger_data);
+
/*
* ustctl_tracepoint_list returns a tracepoint list handle, or negative
* error value.
union {
struct {
const char **model_emf_uri;
+ void (*trigger_callback)(void);
} ext;
char padding[LTTNG_UST_EVENT_DESC_PADDING];
} u;
/* Data structures used by the tracer. */
-enum lttng_enabler_type {
- LTTNG_ENABLER_STAR_GLOB,
- LTTNG_ENABLER_EVENT,
+enum lttng_enabler_format_type {
+ LTTNG_ENABLER_FORMAT_STAR_GLOB,
+ LTTNG_ENABLER_FORMAT_EVENT,
};
/*
* backward reference.
*/
struct lttng_enabler {
- enum lttng_enabler_type type;
+ 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 cds_list_head node; /* per-session list of enablers */
struct lttng_ust_event event_param;
- struct lttng_channel *chan;
- /*
- * Unused, but kept around to make it explicit that the tracer can do
- * it.
- */
- struct lttng_ctx *ctx;
unsigned int enabled:1;
};
uint64_t (*filter)(void *filter_data, const char *filter_stack_data);
int link_failed;
struct cds_list_head node; /* list of bytecode runtime in event */
- struct lttng_session *session;
+ /*
+ * Pointer to a URCU-protected pointer owned by an `struct
+ * lttng_session`or `struct lttng_trigger_group`.
+ */
+ struct lttng_ctx **ctx;
};
/*
- * Objects in a linked-list of enablers, owned by an event.
+ * Objects in a linked-list of enablers, owned by an event or trigger.
+ * This is used because an event (or a trigger) can be enabled by more than one
+ * enabler and we want a quick way to iterate over all enablers of an object.
+ *
+ * For example, event rules "my_app:a*" and "my_app:ab*" will both match the
+ * event with the name "my_app:abc".
*/
struct lttng_enabler_ref {
struct cds_list_head node; /* enabler ref list */
int registered; /* has reg'd tracepoint probe */
};
+struct lttng_trigger {
+ uint64_t id;
+ int enabled;
+ int registered; /* has reg'd tracepoint probe */
+ struct cds_list_head bytecode_runtime_head;
+ int has_enablers_without_bytecode;
+ struct cds_list_head enablers_ref_head;
+ const struct lttng_event_desc *desc;
+ struct cds_hlist_node hlist; /* hashtable of triggers */
+ struct cds_list_head node; /* Trigger list in session */
+ struct lttng_trigger_group *group; /* weak ref */
+};
+
struct lttng_enum {
const struct lttng_enum_desc *desc;
struct lttng_session *session;
struct cds_hlist_head table[LTTNG_UST_EVENT_HT_SIZE];
};
+#define LTTNG_UST_TRIGGER_HT_BITS 12
+#define LTTNG_UST_TRIGGER_HT_SIZE (1U << LTTNG_UST_TRIGGER_HT_BITS)
+struct lttng_ust_trigger_ht {
+ struct cds_hlist_head table[LTTNG_UST_TRIGGER_HT_SIZE];
+};
+
#define LTTNG_UST_ENUM_HT_BITS 12
#define LTTNG_UST_ENUM_HT_SIZE (1U << LTTNG_UST_ENUM_HT_BITS)
struct lttng_ctx *ctx; /* contexts for filters. */
};
+struct lttng_trigger_group {
+ int objd;
+ void *owner;
+ int notification_fd;
+ struct cds_list_head node; /* Trigger group handle list */
+ struct cds_list_head enablers_head;
+ struct cds_list_head triggers_head; /* list of triggers */
+ struct lttng_ust_trigger_ht triggers_ht; /* hashtable of triggers */
+ struct lttng_ctx *ctx; /* contexts for filters. */
+};
+
struct lttng_transport {
char *name;
struct cds_list_head node;
int lttng_session_statedump(struct lttng_session *session);
void lttng_session_destroy(struct lttng_session *session);
+void lttng_trigger_send_notification(struct lttng_trigger *trigger);
+
struct lttng_channel *lttng_channel_create(struct lttng_session *session,
const char *transport_name,
void *buf_addr,
int lttng_channel_enable(struct lttng_channel *channel);
int lttng_channel_disable(struct lttng_channel *channel);
-struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type,
- struct lttng_ust_event *event_param,
- struct lttng_channel *chan);
-int lttng_enabler_enable(struct lttng_enabler *enabler);
-int lttng_enabler_disable(struct lttng_enabler *enabler);
-int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
- struct lttng_ust_filter_bytecode_node *bytecode);
-int lttng_enabler_attach_context(struct lttng_enabler *enabler,
- struct lttng_ust_context *ctx);
-int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler,
- struct lttng_ust_excluder_node *excluder);
-
int lttng_attach_context(struct lttng_ust_context *context_param,
union ust_args *uargs,
struct lttng_ctx **ctx, struct lttng_session *session);
struct lttng_ust_field_iter *
lttng_ust_field_list_get_iter_next(struct lttng_ust_field_list *list);
-void lttng_enabler_event_link_bytecode(struct lttng_event *event,
- struct lttng_enabler *enabler);
void lttng_free_event_filter_runtime(struct lttng_event *event);
void lttng_filter_sync_state(struct lttng_bytecode_runtime *runtime);
void lttng_context_init(void);
void lttng_context_exit(void);
void lttng_filter_event_link_bytecode(struct lttng_event *event);
+struct lttng_enabler *lttng_enabler_create(
+ enum lttng_enabler_format_type format_type,
+ struct lttng_ust_event *event_param,
+ struct lttng_channel *chan);
+int lttng_enabler_enable(struct lttng_enabler *enabler);
+int lttng_enabler_disable(struct lttng_enabler *enabler);
+int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
+ struct lttng_ust_filter_bytecode_node *bytecode);
+int lttng_enabler_attach_context(struct lttng_enabler *enabler,
+ struct lttng_ust_context *ctx);
+int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler,
+ struct lttng_ust_excluder_node *excluder);
+void lttng_enabler_event_link_bytecode(struct lttng_event *event,
+ struct lttng_enabler *enabler);
#ifdef __cplusplus
}
#include TRACEPOINT_INCLUDE
+/*
+ * Stage 2.1 of tracepoint event generation.
+ *
+ * Create probe trigger 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 __trigger_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args));
+
+#include TRACEPOINT_INCLUDE
+
/*
* Stage 3.0 of tracepoint event generation.
*
#undef _TP_EXTRACT_STRING2
+/*
+ * Stage 5.2 of tracepoint event generation.
+ *
+ * Create the trigger probe function.
+ */
+#undef TRACEPOINT_EVENT_CLASS
+#define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \
+static lttng_ust_notrace \
+void __trigger_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); \
+static \
+void __trigger_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \
+{ \
+ struct lttng_trigger *__trigger = (struct lttng_trigger *) __tp_data; \
+ \
+ union { \
+ size_t __dynamic_len[_TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1]; \
+ char __filter_stack_data[2 * sizeof(unsigned long) * (_TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1)]; \
+ } __stackvar; \
+ if (caa_unlikely(!CMM_ACCESS_ONCE(__trigger->enabled))) \
+ return; \
+ if (caa_unlikely(!TP_RCU_LINK_TEST())) \
+ return; \
+ if (caa_unlikely(!cds_list_empty(&__trigger->bytecode_runtime_head))) { \
+ struct lttng_bytecode_runtime *bc_runtime; \
+ int __filter_record = __trigger->has_enablers_without_bytecode; \
+ \
+ __event_prepare_filter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \
+ _TP_ARGS_DATA_VAR(_args)); \
+ tp_list_for_each_entry_rcu(bc_runtime, &__trigger->bytecode_runtime_head, node) { \
+ if (caa_unlikely(bc_runtime->filter(bc_runtime, \
+ __stackvar.__filter_stack_data) & LTTNG_FILTER_RECORD_FLAG)) \
+ __filter_record = 1; \
+ } \
+ if (caa_likely(!__filter_record)) \
+ return; \
+ } \
+ \
+ lttng_trigger_send_notification(__trigger); \
+}
+
+#include TRACEPOINT_INCLUDE
+
/*
* Stage 6 of tracepoint event generation.
*
.u = { \
.ext = { \
.model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name, \
+ .trigger_callback = (void (*)(void)) &__trigger_probe__##_provider##___##_template,\
}, \
}, \
};
uint32_t cmd;
char padding[USTCOMM_MSG_PADDING1];
union {
+ struct lttng_ust_trigger trigger;
struct lttng_ust_channel channel;
struct lttng_ust_stream stream;
struct lttng_ust_event event;
int ustcomm_recv_stream_from_sessiond(int sock,
uint64_t *memory_map_size,
int *shm_fd, int *wakeup_fd);
+ssize_t ustcomm_recv_trigger_notif_fd_from_sessiond(int sock,
+ int *trigger_notif_fd);
/*
* Returns 0 on success, negative error value on error.
return len;
}
+ssize_t ustcomm_recv_trigger_notif_fd_from_sessiond(int sock,
+ int *_trigger_notif_fd)
+{
+ ssize_t nr_fd;
+ int trigger_notif_fd, ret;
+
+ /* Receive trigger notification fd */
+ lttng_ust_lock_fd_tracker();
+ nr_fd = ustcomm_recv_fds_unix_sock(sock, &trigger_notif_fd, 1);
+ if (nr_fd <= 0) {
+ lttng_ust_unlock_fd_tracker();
+ if (nr_fd < 0) {
+ ret = nr_fd;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
+ }
+ }
+
+ ret = lttng_ust_add_fd_to_tracker(trigger_notif_fd);
+ if (ret < 0) {
+ ret = close(trigger_notif_fd);
+ if (ret) {
+ PERROR("close on trigger notif fd");
+ }
+ ret = -EIO;
+ lttng_ust_unlock_fd_tracker();
+ goto error;
+ }
+
+ *_trigger_notif_fd = ret;
+ lttng_ust_unlock_fd_tracker();
+
+ ret = nr_fd;
+
+error:
+ return ret;
+}
+
int ustcomm_recv_stream_from_sessiond(int sock,
uint64_t *memory_map_size,
int *shm_fd, int *wakeup_fd)
break;
case LTTNG_UST_OBJECT_TYPE_EVENT:
case LTTNG_UST_OBJECT_TYPE_CONTEXT:
+ case LTTNG_UST_OBJECT_TYPE_TRIGGER_GROUP:
+ case LTTNG_UST_OBJECT_TYPE_TRIGGER:
break;
default:
assert(0);
return ustctl_disable(sock, &obj);
}
+int ustctl_create_trigger_group(int sock, int pipe_fd,
+ struct lttng_ust_object_data **_trigger_group_data)
+{
+ struct lttng_ust_object_data *trigger_group_data;
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ ssize_t len;
+ int ret;
+
+ if (!_trigger_group_data)
+ return -EINVAL;
+
+ trigger_group_data = zmalloc(sizeof(*trigger_group_data));
+ if (!trigger_group_data)
+ return -ENOMEM;
+
+ trigger_group_data->type = LTTNG_UST_OBJECT_TYPE_TRIGGER_GROUP;
+
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = LTTNG_UST_ROOT_HANDLE;
+ lum.cmd = LTTNG_UST_TRIGGER_GROUP_CREATE;
+
+ ret = ustcomm_send_app_msg(sock, &lum);
+ if (ret) {
+ return ret;
+ }
+
+ /* Send trigger notification pipe. */
+ len = ustcomm_send_fds_unix_sock(sock, &pipe_fd, 1);
+ if (len <= 0) {
+ return ret;
+ }
+
+ ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
+ if (ret) {
+ return ret;
+ }
+
+ trigger_group_data->handle = lur.ret_val;
+ DBG("received trigger group handle %d", trigger_group_data->handle);
+
+ *_trigger_group_data = trigger_group_data;
+ return 0;
+}
+
+int ustctl_create_trigger(int sock, struct lttng_ust_trigger *trigger,
+ struct lttng_ust_object_data *trigger_group,
+ struct lttng_ust_object_data **_trigger_data)
+{
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ struct lttng_ust_object_data *trigger_data;
+ int ret;
+
+ if (!trigger_group || !_trigger_data)
+ return -EINVAL;
+
+ trigger_data = zmalloc(sizeof(*trigger_data));
+ if (!trigger_data)
+ return -ENOMEM;
+
+ trigger_data->type = LTTNG_UST_OBJECT_TYPE_TRIGGER;
+
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = trigger_group->handle;
+ lum.cmd = LTTNG_UST_TRIGGER_CREATE;
+
+ strncpy(lum.u.trigger.name, trigger->name,
+ LTTNG_UST_SYM_NAME_LEN);
+ lum.u.trigger.instrumentation = trigger->instrumentation;
+ lum.u.trigger.loglevel_type = trigger->loglevel_type;
+ lum.u.trigger.loglevel = trigger->loglevel;
+ lum.u.trigger.id = trigger->id;
+ ret = ustcomm_send_app_cmd(sock, &lum, &lur);
+ if (ret) {
+ free(trigger_data);
+ return ret;
+ }
+ trigger_data->handle = lur.ret_val;
+ DBG("received event handle %u", trigger_data->handle);
+ *_trigger_data = trigger_data;
+
+ return ret;
+}
+
int ustctl_tracepoint_list(int sock)
{
struct ustcomm_ust_msg lum;
--- /dev/null
+#ifndef _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H
+#define _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H
+
+/*
+ * Copyright 2019 - Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stddef.h>
+#include <lttng/ust-events.h>
+
+void lttng_ust_context_set_trigger_group_provider(const char *name,
+ size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+ void (*record)(struct lttng_ctx_field *field,
+ struct lttng_ust_lib_ring_buffer_ctx *ctx,
+ struct lttng_channel *chan),
+ void (*get_value)(struct lttng_ctx_field *field,
+ struct lttng_ctx_value *value));
+
+#endif /* _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H */
#include <unistd.h>
#include <lttng/ust-context-provider.h>
+
#include "lttng-tracer-core.h"
#include "jhash.h"
+#include "context-provider-internal.h"
#include <helper.h>
#define CONTEXT_PROVIDER_HT_BITS 12
hash = jhash(provider->name, name_len, 0);
head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)];
cds_hlist_add_head(&provider->node, head);
+
lttng_ust_context_set_session_provider(provider->name,
provider->get_size, provider->record,
provider->get_value);
+
+ lttng_ust_context_set_trigger_group_provider(provider->name,
+ provider->get_size, provider->record,
+ provider->get_value);
end:
ust_unlock();
return ret;
lttng_ust_context_set_session_provider(provider->name,
lttng_ust_dummy_get_size, lttng_ust_dummy_record,
lttng_ust_dummy_get_value);
+
+ lttng_ust_context_set_trigger_group_provider(provider->name,
+ lttng_ust_dummy_get_size, lttng_ust_dummy_record,
+ lttng_ust_dummy_get_value);
+
cds_hlist_del(&provider->node);
end:
ust_unlock();
#define _GNU_SOURCE
#define _LGPL_SOURCE
#include <stdio.h>
-#include <urcu/list.h>
-#include <urcu/hlist.h>
-#include <pthread.h>
+#include <assert.h>
#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <stdint.h>
#include <inttypes.h>
#include <time.h>
#include <stdbool.h>
+#include <unistd.h>
#include <lttng/ust-endian.h>
-#include "clock.h"
#include <urcu-bp.h>
+#include <urcu/arch.h>
#include <urcu/compiler.h>
+#include <urcu/hlist.h>
+#include <urcu/list.h>
#include <urcu/uatomic.h>
-#include <urcu/arch.h>
#include <lttng/tracepoint.h>
#include <lttng/ust-events.h>
#include <helper.h>
#include <lttng/ust-ctl.h>
#include <ust-comm.h>
+#include <ust-fd.h>
#include <lttng/ust-dynamic-type.h>
#include <lttng/ust-context-provider.h>
#include "error.h"
#include "lttng-tracer.h"
#include "lttng-tracer-core.h"
#include "lttng-ust-statedump.h"
+#include "share.h"
+#include "ust-events-internal.h"
#include "wait.h"
#include "../libringbuffer/shm.h"
#include "jhash.h"
+#include "ust-abi.h"
/*
* All operations within this file are called by the communication
*/
static CDS_LIST_HEAD(sessions);
+static CDS_LIST_HEAD(trigger_groups);
struct cds_list_head *_lttng_get_sessions(void)
{
}
static void _lttng_event_destroy(struct lttng_event *event);
+static void _lttng_trigger_destroy(struct lttng_trigger *trigger);
static void _lttng_enum_destroy(struct lttng_enum *_enum);
static
-void lttng_session_lazy_sync_enablers(struct lttng_session *session);
+void lttng_session_lazy_sync_event_enablers(struct lttng_session *session);
+static
+void lttng_session_sync_event_enablers(struct lttng_session *session);
static
-void lttng_session_sync_enablers(struct lttng_session *session);
+void lttng_trigger_group_sync_enablers(struct lttng_trigger_group *trigger_group);
static
void lttng_enabler_destroy(struct lttng_enabler *enabler);
return session;
}
+struct lttng_trigger_group *lttng_trigger_group_create(void)
+{
+ struct lttng_trigger_group *trigger_group;
+ int i;
+
+ trigger_group = zmalloc(sizeof(struct lttng_trigger_group));
+ if (!trigger_group)
+ return NULL;
+
+ CDS_INIT_LIST_HEAD(&trigger_group->enablers_head);
+ CDS_INIT_LIST_HEAD(&trigger_group->triggers_head);
+ for (i = 0; i < LTTNG_UST_TRIGGER_HT_SIZE; i++)
+ CDS_INIT_HLIST_HEAD(&trigger_group->triggers_ht.table[i]);
+
+ cds_list_add(&trigger_group->node, &trigger_groups);
+
+ return trigger_group;
+}
+
/*
* Only used internally at session destruction.
*/
event->registered = 1;
}
+static
+void register_trigger(struct lttng_trigger *trigger)
+{
+ int ret;
+ const struct lttng_event_desc *desc;
+
+ assert(trigger->registered == 0);
+ desc = trigger->desc;
+ ret = __tracepoint_probe_register_queue_release(desc->name,
+ desc->u.ext.trigger_callback, trigger, desc->signature);
+ WARN_ON_ONCE(ret);
+ if (!ret)
+ trigger->registered = 1;
+}
+
static
void unregister_event(struct lttng_event *event)
{
event->registered = 0;
}
+static
+void unregister_trigger(struct lttng_trigger *trigger)
+{
+ int ret;
+ const struct lttng_event_desc *desc;
+
+ assert(trigger->registered == 1);
+ desc = trigger->desc;
+ ret = __tracepoint_probe_unregister_queue_release(desc->name,
+ desc->u.ext.trigger_callback, trigger);
+ WARN_ON_ONCE(ret);
+ if (!ret)
+ trigger->registered = 0;
+}
+
/*
* Only used internally at session destruction.
*/
unregister_event(event);
}
+/*
+ * Only used internally at session destruction.
+ */
+static
+void _lttng_trigger_unregister(struct lttng_trigger *trigger)
+{
+ if (trigger->registered)
+ unregister_trigger(trigger);
+}
+
void lttng_session_destroy(struct lttng_session *session)
{
struct lttng_channel *chan, *tmpchan;
struct lttng_event *event, *tmpevent;
struct lttng_enum *_enum, *tmp_enum;
- struct lttng_enabler *enabler, *tmpenabler;
+ struct lttng_event_enabler *event_enabler, *event_tmpenabler;
CMM_ACCESS_ONCE(session->active) = 0;
cds_list_for_each_entry(event, &session->events_head, node) {
}
synchronize_trace(); /* Wait for in-flight events to complete */
__tracepoint_probe_prune_release_queue();
- cds_list_for_each_entry_safe(enabler, tmpenabler,
+ cds_list_for_each_entry_safe(event_enabler, event_tmpenabler,
&session->enablers_head, node)
- lttng_enabler_destroy(enabler);
+ lttng_event_enabler_destroy(event_enabler);
cds_list_for_each_entry_safe(event, tmpevent,
&session->events_head, node)
_lttng_event_destroy(event);
free(session);
}
+void lttng_trigger_group_destroy(
+ struct lttng_trigger_group *trigger_group)
+{
+ int close_ret;
+ struct lttng_trigger_enabler *trigger_enabler, *tmptrigger_enabler;
+ struct lttng_trigger *trigger, *tmptrigger;
+
+ if (!trigger_group) {
+ return;
+ }
+
+ cds_list_for_each_entry(trigger, &trigger_group->triggers_head, node)
+ _lttng_trigger_unregister(trigger);
+
+ synchronize_trace();
+
+ cds_list_for_each_entry_safe(trigger_enabler, tmptrigger_enabler,
+ &trigger_group->enablers_head, node)
+ lttng_trigger_enabler_destroy(trigger_enabler);
+
+ cds_list_for_each_entry_safe(trigger, tmptrigger,
+ &trigger_group->triggers_head, node)
+ _lttng_trigger_destroy(trigger);
+
+ /* Close the notification fd to the listener of triggers. */
+
+ lttng_ust_lock_fd_tracker();
+ close_ret = close(trigger_group->notification_fd);
+ if (!close_ret) {
+ lttng_ust_delete_fd_from_tracker(trigger_group->notification_fd);
+ } else {
+ PERROR("close");
+ abort();
+ }
+ lttng_ust_unlock_fd_tracker();
+
+ cds_list_del(&trigger_group->node);
+
+ free(trigger_group);
+}
+
+static
+void lttng_enabler_destroy(struct lttng_enabler *enabler)
+{
+ struct lttng_ust_filter_bytecode_node *filter_node, *tmp_filter_node;
+ struct lttng_ust_excluder_node *excluder_node, *tmp_excluder_node;
+
+ if (!enabler) {
+ return;
+ }
+
+ /* Destroy filter bytecode */
+ cds_list_for_each_entry_safe(filter_node, tmp_filter_node,
+ &enabler->filter_bytecode_head, node) {
+ free(filter_node);
+ }
+
+ /* Destroy excluders */
+ cds_list_for_each_entry_safe(excluder_node, tmp_excluder_node,
+ &enabler->excluder_head, node) {
+ free(excluder_node);
+ }
+}
+
+ void lttng_trigger_enabler_destroy(struct lttng_trigger_enabler *trigger_enabler)
+{
+ if (!trigger_enabler) {
+ return;
+ }
+
+ cds_list_del(&trigger_enabler->node);
+
+ lttng_enabler_destroy(lttng_trigger_enabler_as_enabler(trigger_enabler));
+
+ free(trigger_enabler);
+}
+
static
int lttng_enum_create(const struct lttng_enum_desc *desc,
struct lttng_session *session)
session->tstate = 1;
/* We need to sync enablers with session before activation. */
- lttng_session_sync_enablers(session);
+ lttng_session_sync_event_enablers(session);
/*
* Snapshot the number of events per channel to know the type of header
/* Set transient enabler state to "disabled" */
session->tstate = 0;
- lttng_session_sync_enablers(session);
+ lttng_session_sync_event_enablers(session);
end:
return ret;
}
}
/* Set transient enabler state to "enabled" */
channel->tstate = 1;
- lttng_session_sync_enablers(channel->session);
+ lttng_session_sync_event_enablers(channel->session);
/* Set atomically the state to "enabled" */
CMM_ACCESS_ONCE(channel->enabled) = 1;
end:
CMM_ACCESS_ONCE(channel->enabled) = 0;
/* Set transient enabler state to "enabled" */
channel->tstate = 0;
- lttng_session_sync_enablers(channel->session);
+ lttng_session_sync_event_enablers(channel->session);
end:
return ret;
}
+static inline
+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 *event_name;
+ size_t name_len;
+ uint32_t hash;
+
+ event_name = desc->name;
+ name_len = strlen(event_name);
+
+ hash = jhash(event_name, name_len, 0);
+ return &hash_table[hash & (hash_table_size - 1)];
+}
+
/*
* Supports event creation while tracing session is active.
*/
int lttng_event_create(const struct lttng_event_desc *desc,
struct lttng_channel *chan)
{
- const char *event_name = desc->name;
struct lttng_event *event;
struct lttng_session *session = chan->session;
struct cds_hlist_head *head;
int ret = 0;
- size_t name_len = strlen(event_name);
- uint32_t hash;
int notify_socket, loglevel;
const char *uri;
- hash = jhash(event_name, name_len, 0);
- head = &chan->session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)];
+ head = borrow_hash_table_bucket(chan->session->events_ht.table,
+ LTTNG_UST_EVENT_HT_SIZE, desc);
notify_socket = lttng_get_notify_socket(session->owner);
if (notify_socket < 0) {
session,
session->objd,
chan->objd,
- event_name,
+ desc->name,
loglevel,
desc->signature,
desc->nr_fields,
return ret;
}
+static
+int lttng_trigger_create(const struct lttng_event_desc *desc,
+ uint64_t id, struct lttng_trigger_group *trigger_group)
+{
+ struct lttng_trigger *trigger;
+ struct cds_hlist_head *head;
+ int ret = 0;
+
+ /*
+ * Get the hashtable bucket the created lttng_trigger object should be
+ * inserted.
+ */
+ head = borrow_hash_table_bucket(trigger_group->triggers_ht.table,
+ LTTNG_UST_TRIGGER_HT_SIZE, desc);
+
+ trigger = zmalloc(sizeof(struct lttng_trigger));
+ if (!trigger) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ trigger->group = trigger_group;
+ trigger->id = id;
+
+ /* Trigger will be enabled by enabler sync. */
+ trigger->enabled = 0;
+ trigger->registered = 0;
+
+ CDS_INIT_LIST_HEAD(&trigger->bytecode_runtime_head);
+ CDS_INIT_LIST_HEAD(&trigger->enablers_ref_head);
+ trigger->desc = desc;
+
+ cds_list_add(&trigger->node, &trigger_group->triggers_head);
+ cds_hlist_add_head(&trigger->hlist, head);
+
+ return 0;
+
+error:
+ return ret;
+}
+
+static
+void _lttng_trigger_destroy(struct lttng_trigger *trigger)
+{
+ struct lttng_enabler_ref *enabler_ref, *tmp_enabler_ref;
+
+ /* Remove from trigger list. */
+ cds_list_del(&trigger->node);
+ /* Remove from trigger hash table. */
+ cds_hlist_del(&trigger->hlist);
+
+ lttng_free_trigger_filter_runtime(trigger);
+
+ /* Free trigger enabler refs */
+ cds_list_for_each_entry_safe(enabler_ref, tmp_enabler_ref,
+ &trigger->enablers_ref_head, node)
+ free(enabler_ref);
+ free(trigger);
+}
+
static
int lttng_desc_match_star_glob_enabler(const struct lttng_event_desc *desc,
struct lttng_enabler *enabler)
int loglevel = 0;
unsigned int has_loglevel = 0;
- assert(enabler->type == LTTNG_ENABLER_STAR_GLOB);
+ assert(enabler->format_type == LTTNG_ENABLER_FORMAT_STAR_GLOB);
if (!strutils_star_glob_match(enabler->event_param.name, SIZE_MAX,
desc->name, SIZE_MAX))
return 0;
int loglevel = 0;
unsigned int has_loglevel = 0;
- assert(enabler->type == LTTNG_ENABLER_EVENT);
+ assert(enabler->format_type == LTTNG_ENABLER_FORMAT_EVENT);
if (strcmp(desc->name, enabler->event_param.name))
return 0;
if (desc->loglevel) {
int lttng_desc_match_enabler(const struct lttng_event_desc *desc,
struct lttng_enabler *enabler)
{
- switch (enabler->type) {
- case LTTNG_ENABLER_STAR_GLOB:
+ switch (enabler->format_type) {
+ case LTTNG_ENABLER_FORMAT_STAR_GLOB:
{
struct lttng_ust_excluder_node *excluder;
}
return 1;
}
- case LTTNG_ENABLER_EVENT:
+ case LTTNG_ENABLER_FORMAT_EVENT:
return lttng_desc_match_event_enabler(desc, enabler);
default:
return -EINVAL;
}
static
-int lttng_event_match_enabler(struct lttng_event *event,
- struct lttng_enabler *enabler)
+int 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;
+ else
+ return 0;
+}
+
+static
+int lttng_trigger_enabler_match_trigger(
+ struct lttng_trigger_enabler *trigger_enabler,
+ struct lttng_trigger *trigger)
{
- if (lttng_desc_match_enabler(event->desc, enabler)
- && event->chan == enabler->chan)
+ int desc_matches = lttng_desc_match_enabler(trigger->desc,
+ lttng_trigger_enabler_as_enabler(trigger_enabler));
+
+ if (desc_matches && trigger->group == trigger_enabler->group &&
+ trigger->id == trigger_enabler->id)
return 1;
else
return 0;
}
static
-struct lttng_enabler_ref * lttng_event_enabler_ref(struct lttng_event *event,
+struct lttng_enabler_ref *lttng_enabler_ref(
+ struct cds_list_head *enabler_ref_list,
struct lttng_enabler *enabler)
{
struct lttng_enabler_ref *enabler_ref;
- cds_list_for_each_entry(enabler_ref,
- &event->enablers_ref_head, node) {
+ cds_list_for_each_entry(enabler_ref, enabler_ref_list, node) {
if (enabler_ref->ref == enabler)
return enabler_ref;
}
* tracepoint probes.
*/
static
-void lttng_create_event_if_missing(struct lttng_enabler *enabler)
+void lttng_create_event_if_missing(struct lttng_event_enabler *event_enabler)
{
- struct lttng_session *session = enabler->chan->session;
+ struct lttng_session *session = event_enabler->chan->session;
struct lttng_probe_desc *probe_desc;
const struct lttng_event_desc *desc;
struct lttng_event *event;
bool found = false;
struct cds_hlist_head *head;
struct cds_hlist_node *node;
- const char *event_name;
- size_t name_len;
- uint32_t hash;
desc = probe_desc->event_desc[i];
- if (!lttng_desc_match_enabler(desc, enabler))
+ if (!lttng_desc_match_enabler(desc,
+ lttng_event_enabler_as_enabler(event_enabler)))
continue;
- event_name = desc->name;
- name_len = strlen(event_name);
- /*
- * Check if already created.
- */
- hash = jhash(event_name, name_len, 0);
- head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)];
+ 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 == enabler->chan) {
+ && event->chan == event_enabler->chan) {
found = true;
break;
}
* event probe.
*/
ret = lttng_event_create(probe_desc->event_desc[i],
- enabler->chan);
+ event_enabler->chan);
if (ret) {
DBG("Unable to create event %s, error %d\n",
probe_desc->event_desc[i]->name, ret);
}
}
-/*
- * Iterate over all the UST sessions to unregister and destroy all probes from
- * the probe provider descriptor received as argument. Must me called with the
- * ust_lock held.
- */
-void lttng_probe_provider_unregister_events(struct lttng_probe_desc *provider_desc)
+static
+void probe_provider_event_for_each(struct lttng_probe_desc *provider_desc,
+ void (*event_func)(struct lttng_session *session,
+ struct lttng_event *event),
+ void (*trigger_func)(struct lttng_trigger *trigger))
{
struct cds_hlist_node *node, *tmp_node;
struct cds_list_head *sessionsp;
- struct lttng_session *session;
- struct cds_hlist_head *head;
- struct lttng_event *event;
- unsigned int i, j;
+ unsigned int i;
/* Get handle on list of sessions. */
sessionsp = _lttng_get_sessions();
/*
- * Iterate over all events in the probe provider descriptions and sessions
- * to queue the unregistration of the events.
+ * Iterate over all events in the probe provider descriptions and
+ * sessions to queue the unregistration of the events.
*/
for (i = 0; i < provider_desc->nr_events; i++) {
const struct lttng_event_desc *event_desc;
- const char *event_name;
- size_t name_len;
- uint32_t hash;
+ struct lttng_trigger_group *trigger_group;
+ struct lttng_trigger *trigger;
+ struct lttng_session *session;
+ struct cds_hlist_head *head;
+ struct lttng_event *event;
event_desc = provider_desc->event_desc[i];
- event_name = event_desc->name;
- name_len = strlen(event_name);
- hash = jhash(event_name, name_len, 0);
- /* Iterate over all session to find the current event description. */
+ /*
+ * Iterate over all session to find the current event
+ * description.
+ */
cds_list_for_each_entry(session, sessionsp, node) {
/*
- * Get the list of events in the hashtable bucket and iterate to
- * find the event matching this descriptor.
+ * Get the list of events in the hashtable bucket and
+ * iterate to find the event matching this descriptor.
*/
- head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)];
- cds_hlist_for_each_entry(event, node, head, hlist) {
+ head = borrow_hash_table_bucket(
+ session->events_ht.table,
+ LTTNG_UST_EVENT_HT_SIZE, event_desc);
+
+ cds_hlist_for_each_entry_safe(event, node, tmp_node, head, hlist) {
if (event_desc == event->desc) {
- /* Queue the unregistration of this event. */
- _lttng_event_unregister(event);
+ event_func(session, event);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Iterate over all trigger groups to find the current event
+ * description.
+ */
+ cds_list_for_each_entry(trigger_group, &trigger_groups, node) {
+ /*
+ * Get the list of triggers in the hashtable bucket and
+ * iterate to find the trigger matching this
+ * descriptor.
+ */
+ head = borrow_hash_table_bucket(
+ trigger_group->triggers_ht.table,
+ LTTNG_UST_TRIGGER_HT_SIZE, event_desc);
+
+ cds_hlist_for_each_entry_safe(trigger, node, tmp_node, head, hlist) {
+ if (event_desc == trigger->desc) {
+ trigger_func(trigger);
break;
}
}
}
}
+}
+
+static
+void _unregister_event(struct lttng_session *session,
+ struct lttng_event *event)
+{
+ _lttng_event_unregister(event);
+}
+
+static
+void _event_enum_destroy(struct lttng_session *session,
+ struct lttng_event *event)
+{
+ unsigned int i;
+
+ /* Destroy enums of the current event. */
+ for (i = 0; i < event->desc->nr_fields; i++) {
+ const struct lttng_enum_desc *enum_desc;
+ const struct lttng_event_field *field;
+ struct lttng_enum *curr_enum;
+
+ field = &(event->desc->fields[i]);
+ if (field->type.atype != atype_enum) {
+ continue;
+ }
+
+ enum_desc = field->type.u.basic.enumeration.desc;
+ curr_enum = lttng_ust_enum_get_from_desc(session, enum_desc);
+ if (curr_enum) {
+ _lttng_enum_destroy(curr_enum);
+ }
+ }
+
+ /* Destroy event. */
+ _lttng_event_destroy(event);
+}
+
+/*
+ * Iterate over all the UST sessions to unregister and destroy all probes from
+ * the probe provider descriptor received as argument. Must me called with the
+ * ust_lock held.
+ */
+void lttng_probe_provider_unregister_events(
+ struct lttng_probe_desc *provider_desc)
+{
+ /*
+ * Iterate over all events in the probe provider descriptions and sessions
+ * to queue the unregistration of the events.
+ */
+ probe_provider_event_for_each(provider_desc, _unregister_event,
+ _lttng_trigger_unregister);
/* Wait for grace period. */
synchronize_trace();
* It is now safe to destroy the events and remove them from the event list
* and hashtables.
*/
- for (i = 0; i < provider_desc->nr_events; i++) {
- const struct lttng_event_desc *event_desc;
- const char *event_name;
- size_t name_len;
- uint32_t hash;
-
- event_desc = provider_desc->event_desc[i];
- event_name = event_desc->name;
- name_len = strlen(event_name);
- hash = jhash(event_name, name_len, 0);
-
- /* Iterate over all sessions to find the current event description. */
- cds_list_for_each_entry(session, sessionsp, node) {
- /*
- * Get the list of events in the hashtable bucket and iterate to
- * find the event matching this descriptor.
- */
- head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)];
- cds_hlist_for_each_entry_safe(event, node, tmp_node, head, hlist) {
- if (event_desc == event->desc) {
- /* Destroy enums of the current event. */
- for (j = 0; j < event->desc->nr_fields; j++) {
- const struct lttng_enum_desc *enum_desc;
- const struct lttng_event_field *field;
- struct lttng_enum *curr_enum;
-
- field = &(event->desc->fields[j]);
- if (field->type.atype != atype_enum) {
- continue;
- }
-
- enum_desc = field->type.u.basic.enumeration.desc;
- curr_enum = lttng_ust_enum_get_from_desc(session, enum_desc);
- if (curr_enum) {
- _lttng_enum_destroy(curr_enum);
- }
- }
-
- /* Destroy event. */
- _lttng_event_destroy(event);
- break;
- }
- }
- }
- }
+ probe_provider_event_for_each(provider_desc, _event_enum_destroy,
+ _lttng_trigger_destroy);
}
/*
- * Create events associated with an enabler (if not already present),
+ * Create events associated with an event enabler (if not already present),
* and add backward reference from the event to the enabler.
*/
static
-int lttng_enabler_ref_events(struct lttng_enabler *enabler)
+int lttng_event_enabler_ref_events(struct lttng_event_enabler *event_enabler)
{
- struct lttng_session *session = enabler->chan->session;
+ struct lttng_session *session = event_enabler->chan->session;
struct lttng_event *event;
/* First ensure that probe events are created for this enabler. */
- lttng_create_event_if_missing(enabler);
+ lttng_create_event_if_missing(event_enabler);
/* For each event matching enabler in session event list. */
cds_list_for_each_entry(event, &session->events_head, node) {
struct lttng_enabler_ref *enabler_ref;
- if (!lttng_event_match_enabler(event, enabler))
+ if (!lttng_event_enabler_match_event(event_enabler, event))
continue;
- enabler_ref = lttng_event_enabler_ref(event, enabler);
+ enabler_ref = lttng_enabler_ref(&event->enablers_ref_head,
+ lttng_event_enabler_as_enabler(event_enabler));
if (!enabler_ref) {
/*
* If no backward ref, create it.
enabler_ref = zmalloc(sizeof(*enabler_ref));
if (!enabler_ref)
return -ENOMEM;
- enabler_ref->ref = enabler;
+ enabler_ref->ref = lttng_event_enabler_as_enabler(event_enabler);
cds_list_add(&enabler_ref->node,
&event->enablers_ref_head);
}
/*
* Link filter bytecodes if not linked yet.
*/
- lttng_enabler_event_link_bytecode(event, enabler);
+ lttng_enabler_link_bytecode(event->desc,
+ &session->ctx,
+ &event->bytecode_runtime_head,
+ lttng_event_enabler_as_enabler(event_enabler));
/* TODO: merge event context. */
}
struct lttng_session *session;
cds_list_for_each_entry(session, &sessions, node) {
- lttng_session_lazy_sync_enablers(session);
+ lttng_session_lazy_sync_event_enablers(session);
+ }
+ return 0;
+}
+
+int lttng_fix_pending_triggers(void)
+{
+ struct lttng_trigger_group *trigger_group;
+
+ cds_list_for_each_entry(trigger_group, &trigger_groups, node) {
+ lttng_trigger_group_sync_enablers(trigger_group);
}
return 0;
}
/*
* Enabler management.
*/
-struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type,
+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)
{
- struct lttng_enabler *enabler;
+ struct lttng_event_enabler *event_enabler;
- enabler = zmalloc(sizeof(*enabler));
- if (!enabler)
+ event_enabler = zmalloc(sizeof(*event_enabler));
+ if (!event_enabler)
return NULL;
- enabler->type = type;
- CDS_INIT_LIST_HEAD(&enabler->filter_bytecode_head);
- CDS_INIT_LIST_HEAD(&enabler->excluder_head);
- memcpy(&enabler->event_param, event_param,
- sizeof(enabler->event_param));
- enabler->chan = chan;
+ event_enabler->base.format_type = format_type;
+ CDS_INIT_LIST_HEAD(&event_enabler->base.filter_bytecode_head);
+ CDS_INIT_LIST_HEAD(&event_enabler->base.excluder_head);
+ memcpy(&event_enabler->base.event_param, event_param,
+ sizeof(event_enabler->base.event_param));
+ event_enabler->chan = chan;
/* ctx left NULL */
- enabler->enabled = 0;
- cds_list_add(&enabler->node, &enabler->chan->session->enablers_head);
- lttng_session_lazy_sync_enablers(enabler->chan->session);
- return enabler;
+ 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);
+
+ return event_enabler;
}
-int lttng_enabler_enable(struct lttng_enabler *enabler)
+struct lttng_trigger_enabler *lttng_trigger_enabler_create(
+ struct lttng_trigger_group *trigger_group,
+ enum lttng_enabler_format_type format_type,
+ struct lttng_ust_trigger *trigger_param)
{
- enabler->enabled = 1;
- lttng_session_lazy_sync_enablers(enabler->chan->session);
+ struct lttng_trigger_enabler *trigger_enabler;
+
+ trigger_enabler = zmalloc(sizeof(*trigger_enabler));
+ if (!trigger_enabler)
+ return NULL;
+ trigger_enabler->base.format_type = format_type;
+ CDS_INIT_LIST_HEAD(&trigger_enabler->base.filter_bytecode_head);
+ CDS_INIT_LIST_HEAD(&trigger_enabler->base.excluder_head);
+
+ trigger_enabler->id = trigger_param->id;
+
+ memcpy(&trigger_enabler->base.event_param.name, trigger_param->name,
+ sizeof(trigger_enabler->base.event_param.name));
+ trigger_enabler->base.event_param.instrumentation = trigger_param->instrumentation;
+ trigger_enabler->base.event_param.loglevel = trigger_param->loglevel;
+ trigger_enabler->base.event_param.loglevel_type = trigger_param->loglevel_type;
+
+ trigger_enabler->base.enabled = 0;
+ trigger_enabler->group = trigger_group;
+
+ cds_list_add(&trigger_enabler->node, &trigger_group->enablers_head);
+
+ lttng_trigger_group_sync_enablers(trigger_group);
+
+ return trigger_enabler;
+}
+
+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);
+
return 0;
}
-int lttng_enabler_disable(struct lttng_enabler *enabler)
+int lttng_event_enabler_disable(struct lttng_event_enabler *event_enabler)
{
- enabler->enabled = 0;
- lttng_session_lazy_sync_enablers(enabler->chan->session);
+ lttng_event_enabler_as_enabler(event_enabler)->enabled = 0;
+ lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+
return 0;
}
-int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
+static
+void _lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
struct lttng_ust_filter_bytecode_node *bytecode)
{
bytecode->enabler = enabler;
cds_list_add_tail(&bytecode->node, &enabler->filter_bytecode_head);
- lttng_session_lazy_sync_enablers(enabler->chan->session);
+}
+
+int lttng_event_enabler_attach_bytecode(struct lttng_event_enabler *event_enabler,
+ struct lttng_ust_filter_bytecode_node *bytecode)
+{
+ _lttng_enabler_attach_bytecode(
+ lttng_event_enabler_as_enabler(event_enabler), bytecode);
+
+ lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
return 0;
}
-int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler,
+static
+void _lttng_enabler_attach_exclusion(struct lttng_enabler *enabler,
struct lttng_ust_excluder_node *excluder)
{
excluder->enabler = enabler;
cds_list_add_tail(&excluder->node, &enabler->excluder_head);
- lttng_session_lazy_sync_enablers(enabler->chan->session);
+}
+
+int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *event_enabler,
+ struct lttng_ust_excluder_node *excluder)
+{
+ _lttng_enabler_attach_exclusion(
+ lttng_event_enabler_as_enabler(event_enabler), excluder);
+
+ lttng_session_lazy_sync_event_enablers(event_enabler->chan->session);
+ return 0;
+}
+
+int lttng_trigger_enabler_enable(struct lttng_trigger_enabler *trigger_enabler)
+{
+ lttng_trigger_enabler_as_enabler(trigger_enabler)->enabled = 1;
+ lttng_trigger_group_sync_enablers(trigger_enabler->group);
+
+ return 0;
+}
+
+int lttng_trigger_enabler_disable(struct lttng_trigger_enabler *trigger_enabler)
+{
+ lttng_trigger_enabler_as_enabler(trigger_enabler)->enabled = 0;
+ lttng_trigger_group_sync_enablers(trigger_enabler->group);
+
+ return 0;
+}
+
+int lttng_trigger_enabler_attach_bytecode( struct lttng_trigger_enabler *trigger_enabler,
+ struct lttng_ust_filter_bytecode_node *bytecode)
+{
+ _lttng_enabler_attach_bytecode(
+ lttng_trigger_enabler_as_enabler(trigger_enabler), bytecode);
+
+ lttng_trigger_group_sync_enablers(trigger_enabler->group);
+ return 0;
+}
+
+int lttng_trigger_enabler_attach_exclusion(
+ struct lttng_trigger_enabler *trigger_enabler,
+ struct lttng_ust_excluder_node *excluder)
+{
+ _lttng_enabler_attach_exclusion(
+ lttng_trigger_enabler_as_enabler(trigger_enabler), excluder);
+
+ lttng_trigger_group_sync_enablers(trigger_enabler->group);
return 0;
}
}
}
-int lttng_enabler_attach_context(struct lttng_enabler *enabler,
+int lttng_event_enabler_attach_context(struct lttng_event_enabler *enabler,
struct lttng_ust_context *context_param)
{
-#if 0 // disabled for now.
- struct lttng_session *session = enabler->chan->session;
- int ret;
-
- ret = lttng_attach_context(context_param, &enabler->ctx,
- session);
- if (ret)
- return ret;
- lttng_session_lazy_sync_enablers(enabler->chan->session);
-#endif
return -ENOSYS;
}
-static
-void lttng_enabler_destroy(struct lttng_enabler *enabler)
+void lttng_event_enabler_destroy(struct lttng_event_enabler *event_enabler)
{
- struct lttng_ust_filter_bytecode_node *filter_node, *tmp_filter_node;
- struct lttng_ust_excluder_node *excluder_node, *tmp_excluder_node;
-
- /* Destroy filter bytecode */
- cds_list_for_each_entry_safe(filter_node, tmp_filter_node,
- &enabler->filter_bytecode_head, node) {
- free(filter_node);
- }
-
- /* Destroy excluders */
- cds_list_for_each_entry_safe(excluder_node, tmp_excluder_node,
- &enabler->excluder_head, node) {
- free(excluder_node);
+ if (!event_enabler) {
+ return;
}
+ cds_list_del(&event_enabler->node);
- /* Destroy contexts */
- lttng_destroy_context(enabler->ctx);
+ lttng_enabler_destroy(lttng_event_enabler_as_enabler(event_enabler));
- cds_list_del(&enabler->node);
- free(enabler);
+ lttng_destroy_context(event_enabler->ctx);
+ free(event_enabler);
}
/*
- * lttng_session_sync_enablers should be called just before starting a
+ * lttng_session_sync_event_enablers should be called just before starting a
* session.
*/
static
-void lttng_session_sync_enablers(struct lttng_session *session)
+void lttng_session_sync_event_enablers(struct lttng_session *session)
{
- struct lttng_enabler *enabler;
+ struct lttng_event_enabler *event_enabler;
struct lttng_event *event;
- cds_list_for_each_entry(enabler, &session->enablers_head, node)
- lttng_enabler_ref_events(enabler);
+ cds_list_for_each_entry(event_enabler, &session->enablers_head, node)
+ lttng_event_enabler_ref_events(event_enabler);
/*
* For each event, if at least one of its enablers is enabled,
* and its channel and session transient states are enabled, we
__tracepoint_probe_prune_release_queue();
}
+static
+void lttng_create_trigger_if_missing(struct lttng_trigger_enabler *trigger_enabler)
+{
+ struct lttng_trigger_group *trigger_group = trigger_enabler->group;
+ struct lttng_probe_desc *probe_desc;
+ struct cds_list_head *probe_list;
+ int i;
+
+ probe_list = lttng_get_probe_list_head();
+
+ cds_list_for_each_entry(probe_desc, probe_list, head) {
+ for (i = 0; i < probe_desc->nr_events; i++) {
+ int ret;
+ bool found = false;
+ const struct lttng_event_desc *desc;
+ struct lttng_trigger *trigger;
+ struct cds_hlist_head *head;
+ struct cds_hlist_node *node;
+
+ desc = probe_desc->event_desc[i];
+ if (!lttng_desc_match_enabler(desc,
+ lttng_trigger_enabler_as_enabler(trigger_enabler)))
+ continue;
+
+ /*
+ * Given the current trigger group, get the bucket that
+ * the target trigger would be if it was already
+ * created.
+ */
+ head = borrow_hash_table_bucket(
+ trigger_group->triggers_ht.table,
+ LTTNG_UST_TRIGGER_HT_SIZE, desc);
+
+ cds_hlist_for_each_entry(trigger, node, head, hlist) {
+ /*
+ * Check if trigger already exists by checking
+ * if the trigger and enabler share the same
+ * description and id.
+ */
+ if (trigger->desc == desc &&
+ trigger->id == trigger_enabler->id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ /*
+ * We need to create a trigger for this event probe.
+ */
+ ret = lttng_trigger_create(desc, trigger_enabler->id,
+ trigger_group);
+ if (ret) {
+ DBG("Unable to create trigger %s, error %d\n",
+ probe_desc->event_desc[i]->name, ret);
+ }
+ }
+ }
+}
+
+void lttng_trigger_send_notification(struct lttng_trigger *trigger)
+{
+ /*
+ * We want this write to be atomic AND non-blocking, meaning that we
+ * want to write either everything OR nothing.
+ * According to `pipe(7)`, writes that are smaller that the `PIPE_BUF`
+ * value must be atomic, so we assert that the message we send is less
+ * than PIPE_BUF.
+ */
+ struct lttng_ust_trigger_notification notif;
+ ssize_t ret;
+
+ assert(trigger);
+ assert(trigger->group);
+ assert(sizeof(notif) <= PIPE_BUF);
+
+ notif.id = trigger->id;
+
+ ret = patient_write(trigger->group->notification_fd, ¬if,
+ sizeof(notif));
+ if (ret == -1) {
+ if (errno == EAGAIN) {
+ DBG("Cannot send trigger notification without blocking: %s",
+ strerror(errno));
+ } else {
+ DBG("Error to sending trigger notification: %s",
+ strerror(errno));
+ abort();
+ }
+ }
+}
+
+/*
+ * Create triggers associated with a trigger enabler (if not already present).
+ */
+static
+int lttng_trigger_enabler_ref_triggers(struct lttng_trigger_enabler *trigger_enabler)
+{
+ struct lttng_trigger_group *trigger_group = trigger_enabler->group;
+ struct lttng_trigger *trigger;
+
+ /* First, ensure that probe triggers are created for this enabler. */
+ lttng_create_trigger_if_missing(trigger_enabler);
+
+ /* Link the created trigger with its associated enabler. */
+ cds_list_for_each_entry(trigger, &trigger_group->triggers_head, node) {
+ struct lttng_enabler_ref *enabler_ref;
+
+ if (!lttng_trigger_enabler_match_trigger(trigger_enabler, trigger))
+ continue;
+
+ enabler_ref = lttng_enabler_ref(&trigger->enablers_ref_head,
+ lttng_trigger_enabler_as_enabler(trigger_enabler));
+ if (!enabler_ref) {
+ /*
+ * If no backward ref, create it.
+ * Add backward ref from trigger to enabler.
+ */
+ enabler_ref = zmalloc(sizeof(*enabler_ref));
+ if (!enabler_ref)
+ return -ENOMEM;
+
+ enabler_ref->ref = lttng_trigger_enabler_as_enabler(
+ trigger_enabler);
+ cds_list_add(&enabler_ref->node,
+ &trigger->enablers_ref_head);
+ }
+
+ /*
+ * Link filter bytecodes if not linked yet.
+ */
+ lttng_enabler_link_bytecode(trigger->desc,
+ &trigger_group->ctx, &trigger->bytecode_runtime_head,
+ lttng_trigger_enabler_as_enabler(trigger_enabler));
+ }
+ return 0;
+}
+
+static
+void lttng_trigger_group_sync_enablers(struct lttng_trigger_group *trigger_group)
+{
+ struct lttng_trigger_enabler *trigger_enabler;
+ struct lttng_trigger *trigger;
+
+ cds_list_for_each_entry(trigger_enabler, &trigger_group->enablers_head, node) {
+ /*
+ * Only link enablers that are enabled to triggers, the user
+ * might still be attaching filter or exclusion to the
+ * trigger_enabler.
+ */
+ if (!lttng_trigger_enabler_as_enabler(trigger_enabler)->enabled)
+ continue;
+
+ lttng_trigger_enabler_ref_triggers(trigger_enabler);
+ }
+
+ /*
+ * For each trigger, if at least one of its enablers is enabled,
+ * we enable the trigger, else we disable it.
+ */
+ cds_list_for_each_entry(trigger, &trigger_group->triggers_head, node) {
+ struct lttng_enabler_ref *enabler_ref;
+ struct lttng_bytecode_runtime *runtime;
+ int enabled = 0, has_enablers_without_bytecode = 0;
+
+ /* Enable triggers */
+ cds_list_for_each_entry(enabler_ref,
+ &trigger->enablers_ref_head, node) {
+ if (enabler_ref->ref->enabled) {
+ enabled = 1;
+ break;
+ }
+ }
+
+ CMM_STORE_SHARED(trigger->enabled, enabled);
+ /*
+ * Sync tracepoint registration with trigger enabled
+ * state.
+ */
+ if (enabled) {
+ if (!trigger->registered)
+ register_trigger(trigger);
+ } else {
+ if (trigger->registered)
+ unregister_trigger(trigger);
+ }
+
+ /* Check if has enablers without bytecode enabled */
+ cds_list_for_each_entry(enabler_ref,
+ &trigger->enablers_ref_head, node) {
+ if (enabler_ref->ref->enabled
+ && cds_list_empty(&enabler_ref->ref->filter_bytecode_head)) {
+ has_enablers_without_bytecode = 1;
+ break;
+ }
+ }
+ trigger->has_enablers_without_bytecode =
+ has_enablers_without_bytecode;
+
+ /* Enable filters */
+ cds_list_for_each_entry(runtime,
+ &trigger->bytecode_runtime_head, node) {
+ lttng_filter_sync_state(runtime);
+ }
+ }
+ __tracepoint_probe_prune_release_queue();
+}
+
/*
* Apply enablers to session events, adding events to session if need
* be. It is required after each modification applied to an active
* "lazy" sync means we only sync if required.
*/
static
-void lttng_session_lazy_sync_enablers(struct lttng_session *session)
+void lttng_session_lazy_sync_event_enablers(struct lttng_session *session)
{
/* We can skip if session is not active */
if (!session->active)
return;
- lttng_session_sync_enablers(session);
+ lttng_session_sync_event_enablers(session);
}
/*
}
}
}
+
+/*
+ * Update all trigger groups with the given app context.
+ * Called with ust lock held.
+ * This is invoked when an application context gets loaded/unloaded. It
+ * ensures the context callbacks are in sync with the application
+ * context (either app context callbacks, or dummy callbacks).
+ */
+void lttng_ust_context_set_trigger_group_provider(const char *name,
+ size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+ void (*record)(struct lttng_ctx_field *field,
+ struct lttng_ust_lib_ring_buffer_ctx *ctx,
+ struct lttng_channel *chan),
+ void (*get_value)(struct lttng_ctx_field *field,
+ struct lttng_ctx_value *value))
+{
+ struct lttng_trigger_group *trigger_group;
+
+ cds_list_for_each_entry(trigger_group, &trigger_groups, node) {
+ int ret;
+
+ ret = lttng_ust_context_set_provider_rcu(&trigger_group->ctx,
+ name, get_size, record, get_value);
+ if (ret)
+ abort();
+ }
+}
return 0;
}
-static int dynamic_get_index(struct lttng_session *session,
+static int dynamic_get_index(struct lttng_ctx *ctx,
struct bytecode_runtime *runtime,
uint64_t index, struct estack_entry *stack_top)
{
case LOAD_ROOT_CONTEXT:
case LOAD_ROOT_APP_CONTEXT: /* Fall-through */
{
- struct lttng_ctx *ctx;
-
- ctx = rcu_dereference(session->ctx);
ret = context_get_index(ctx,
&stack_top->u.ptr,
gid->ctx_index);
const char *filter_stack_data)
{
struct bytecode_runtime *bytecode = filter_data;
- struct lttng_session *session = bytecode->p.session;
+ struct lttng_ctx *ctx = rcu_dereference(*bytecode->p.ctx);
void *pc, *next_pc, *start_pc;
int ret = -EINVAL;
uint64_t retval = 0;
{
struct load_op *insn = (struct load_op *) pc;
struct field_ref *ref = (struct field_ref *) insn->data;
- struct lttng_ctx *ctx;
struct lttng_ctx_field *ctx_field;
struct lttng_ctx_value v;
dbg_printf("get context ref offset %u type dynamic\n",
ref->offset);
- ctx = rcu_dereference(session->ctx);
ctx_field = &ctx->fields[ref->offset];
ctx_field->get_value(ctx_field, &v);
estack_push(stack, top, ax, bx, ax_t, bx_t);
{
struct load_op *insn = (struct load_op *) pc;
struct field_ref *ref = (struct field_ref *) insn->data;
- struct lttng_ctx *ctx;
struct lttng_ctx_field *ctx_field;
struct lttng_ctx_value v;
dbg_printf("get context ref offset %u type string\n",
ref->offset);
- ctx = rcu_dereference(session->ctx);
ctx_field = &ctx->fields[ref->offset];
ctx_field->get_value(ctx_field, &v);
estack_push(stack, top, ax, bx, ax_t, bx_t);
{
struct load_op *insn = (struct load_op *) pc;
struct field_ref *ref = (struct field_ref *) insn->data;
- struct lttng_ctx *ctx;
struct lttng_ctx_field *ctx_field;
struct lttng_ctx_value v;
dbg_printf("get context ref offset %u type s64\n",
ref->offset);
- ctx = rcu_dereference(session->ctx);
ctx_field = &ctx->fields[ref->offset];
ctx_field->get_value(ctx_field, &v);
estack_push(stack, top, ax, bx, ax_t, bx_t);
{
struct load_op *insn = (struct load_op *) pc;
struct field_ref *ref = (struct field_ref *) insn->data;
- struct lttng_ctx *ctx;
struct lttng_ctx_field *ctx_field;
struct lttng_ctx_value v;
dbg_printf("get context ref offset %u type double\n",
ref->offset);
- ctx = rcu_dereference(session->ctx);
ctx_field = &ctx->fields[ref->offset];
ctx_field->get_value(ctx_field, &v);
estack_push(stack, top, ax, bx, ax_t, bx_t);
struct get_index_u16 *index = (struct get_index_u16 *) insn->data;
dbg_printf("op get index u16\n");
- ret = dynamic_get_index(session, bytecode, index->index, estack_ax(stack, top));
+ ret = dynamic_get_index(ctx, bytecode, index->index, estack_ax(stack, top));
if (ret)
goto end;
estack_ax_v = estack_ax(stack, top)->u.v;
struct get_index_u64 *index = (struct get_index_u64 *) insn->data;
dbg_printf("op get index u64\n");
- ret = dynamic_get_index(session, bytecode, index->index, estack_ax(stack, top));
+ ret = dynamic_get_index(ctx, bytecode, index->index, estack_ax(stack, top));
if (ret)
goto end;
estack_ax_v = estack_ax(stack, top)->u.v;
return 0;
}
-static int specialize_context_lookup(struct lttng_session *session,
+static int specialize_context_lookup(struct lttng_ctx *ctx,
struct bytecode_runtime *runtime,
struct load_op *insn,
struct vstack_load *load)
struct filter_get_index_data gid;
ssize_t data_offset;
- idx = specialize_context_lookup_name(session->ctx, runtime, insn);
+ idx = specialize_context_lookup_name(ctx, runtime, insn);
if (idx < 0) {
return -ENOENT;
}
- ctx_field = &session->ctx->fields[idx];
+ ctx_field = &ctx->fields[idx];
field = &ctx_field->event_field;
ret = specialize_load_object(field, load, true);
if (ret)
return 0;
}
-static int specialize_app_context_lookup(struct lttng_session *session,
+static int specialize_app_context_lookup(struct lttng_ctx *ctx,
struct bytecode_runtime *runtime,
struct load_op *insn,
struct vstack_load *load)
}
strcpy(name, "$app.");
strcat(name, orig_name);
- idx = lttng_get_context_index(session->ctx, name);
+ idx = lttng_get_context_index(ctx, name);
if (idx < 0) {
assert(lttng_context_is_app(name));
ret = lttng_ust_add_app_context_to_ctx_rcu(name,
- &session->ctx);
+ &ctx);
if (ret)
return ret;
- idx = lttng_get_context_index(session->ctx,
- name);
+ idx = lttng_get_context_index(ctx, name);
if (idx < 0)
return -ENOENT;
}
- ctx_field = &session->ctx->fields[idx];
+ ctx_field = &ctx->fields[idx];
field = &ctx_field->event_field;
ret = specialize_load_object(field, load, true);
if (ret)
return ret;
}
-static int specialize_event_payload_lookup(struct lttng_event *event,
+static int specialize_payload_lookup(const struct lttng_event_desc *event_desc,
struct bytecode_runtime *runtime,
struct load_op *insn,
struct vstack_load *load)
{
const char *name;
uint16_t offset;
- const struct lttng_event_desc *desc = event->desc;
unsigned int i, nr_fields;
bool found = false;
uint32_t field_offset = 0;
struct filter_get_index_data gid;
ssize_t data_offset;
- nr_fields = desc->nr_fields;
+ nr_fields = event_desc->nr_fields;
offset = ((struct get_symbol *) insn->data)->offset;
name = runtime->p.bc->bc.data + runtime->p.bc->bc.reloc_offset + offset;
for (i = 0; i < nr_fields; i++) {
- field = &desc->fields[i];
+ field = &event_desc->fields[i];
if (!strcmp(field->name, name)) {
found = true;
break;
return ret;
}
-int lttng_filter_specialize_bytecode(struct lttng_event *event,
+int lttng_filter_specialize_bytecode(const struct lttng_event_desc *event_desc,
struct bytecode_runtime *bytecode)
{
void *pc, *next_pc, *start_pc;
int ret = -EINVAL;
struct vstack _stack;
struct vstack *stack = &_stack;
- struct lttng_session *session = bytecode->p.session;
+ struct lttng_ctx *ctx = *bytecode->p.ctx;
vstack_init(stack);
goto end;
case LOAD_ROOT_CONTEXT:
/* Lookup context field. */
- ret = specialize_context_lookup(session,
+ ret = specialize_context_lookup(ctx,
bytecode, insn,
&vstack_ax(stack)->load);
if (ret)
break;
case LOAD_ROOT_APP_CONTEXT:
/* Lookup app context field. */
- ret = specialize_app_context_lookup(session,
+ ret = specialize_app_context_lookup(ctx,
bytecode, insn,
&vstack_ax(stack)->load);
if (ret)
break;
case LOAD_ROOT_PAYLOAD:
/* Lookup event payload field. */
- ret = specialize_event_payload_lookup(event,
+ ret = specialize_payload_lookup(event_desc,
bytecode, insn,
&vstack_ax(stack)->load);
if (ret)
#include <urcu/rculist.h>
#include "lttng-filter.h"
+#include "ust-events-internal.h"
static const char *opnames[] = {
[ FILTER_OP_UNKNOWN ] = "UNKNOWN",
}
static
-int apply_field_reloc(struct lttng_event *event,
+int apply_field_reloc(const struct lttng_event_desc *event_desc,
struct bytecode_runtime *runtime,
uint32_t runtime_len,
uint32_t reloc_offset,
const char *field_name,
enum filter_op filter_op)
{
- const struct lttng_event_desc *desc;
const struct lttng_event_field *fields, *field = NULL;
unsigned int nr_fields, i;
struct load_op *op;
dbg_printf("Apply field reloc: %u %s\n", reloc_offset, field_name);
/* Lookup event by name */
- desc = event->desc;
- if (!desc)
+ if (!event_desc)
return -EINVAL;
- fields = desc->fields;
+ fields = event_desc->fields;
if (!fields)
return -EINVAL;
- nr_fields = desc->nr_fields;
+ nr_fields = event_desc->nr_fields;
for (i = 0; i < nr_fields; i++) {
if (!strcmp(fields[i].name, field_name)) {
field = &fields[i];
}
static
-int apply_context_reloc(struct lttng_event *event,
- struct bytecode_runtime *runtime,
+int apply_context_reloc(struct bytecode_runtime *runtime,
uint32_t runtime_len,
uint32_t reloc_offset,
const char *context_name,
struct load_op *op;
struct lttng_ctx_field *ctx_field;
int idx;
- struct lttng_session *session = runtime->p.session;
+ struct lttng_ctx *ctx = *runtime->p.ctx;
dbg_printf("Apply context reloc: %u %s\n", reloc_offset, context_name);
/* Get context index */
- idx = lttng_get_context_index(session->ctx, context_name);
+ idx = lttng_get_context_index(ctx, context_name);
if (idx < 0) {
if (lttng_context_is_app(context_name)) {
int ret;
ret = lttng_ust_add_app_context_to_ctx_rcu(context_name,
- &session->ctx);
+ &ctx);
if (ret)
return ret;
- idx = lttng_get_context_index(session->ctx,
- context_name);
+ idx = lttng_get_context_index(ctx, context_name);
if (idx < 0)
return -ENOENT;
} else {
return -EINVAL;
/* Get context return type */
- ctx_field = &session->ctx->fields[idx];
+ ctx_field = &ctx->fields[idx];
op = (struct load_op *) &runtime->code[reloc_offset];
switch (filter_op) {
}
static
-int apply_reloc(struct lttng_event *event,
+int apply_reloc(const struct lttng_event_desc *event_desc,
struct bytecode_runtime *runtime,
uint32_t runtime_len,
uint32_t reloc_offset,
op = (struct load_op *) &runtime->code[reloc_offset];
switch (op->op) {
case FILTER_OP_LOAD_FIELD_REF:
- return apply_field_reloc(event, runtime, runtime_len,
+ return apply_field_reloc(event_desc, runtime, runtime_len,
reloc_offset, name, op->op);
case FILTER_OP_GET_CONTEXT_REF:
- return apply_context_reloc(event, runtime, runtime_len,
+ return apply_context_reloc(runtime, runtime_len,
reloc_offset, name, op->op);
case FILTER_OP_GET_SYMBOL:
case FILTER_OP_GET_SYMBOL_FIELD:
static
int bytecode_is_linked(struct lttng_ust_filter_bytecode_node *filter_bytecode,
- struct lttng_event *event)
+ struct cds_list_head *bytecode_runtime_head)
{
struct lttng_bytecode_runtime *bc_runtime;
- cds_list_for_each_entry(bc_runtime,
- &event->bytecode_runtime_head, node) {
+ cds_list_for_each_entry(bc_runtime, bytecode_runtime_head, node) {
if (bc_runtime->bc == filter_bytecode)
return 1;
}
* bytecode runtime.
*/
static
-int _lttng_filter_event_link_bytecode(struct lttng_event *event,
+int _lttng_filter_link_bytecode(const struct lttng_event_desc *event_desc,
+ struct lttng_ctx **ctx,
struct lttng_ust_filter_bytecode_node *filter_bytecode,
struct cds_list_head *insert_loc)
{
if (!filter_bytecode)
return 0;
/* Bytecode already linked */
- if (bytecode_is_linked(filter_bytecode, event))
+ if (bytecode_is_linked(filter_bytecode, insert_loc))
return 0;
dbg_printf("Linking...\n");
goto alloc_error;
}
runtime->p.bc = filter_bytecode;
- runtime->p.session = event->chan->session;
+ runtime->p.ctx = ctx;
runtime->len = filter_bytecode->bc.reloc_offset;
/* copy original bytecode */
memcpy(runtime->code, filter_bytecode->bc.data, runtime->len);
const char *name =
(const char *) &filter_bytecode->bc.data[offset + sizeof(uint16_t)];
- ret = apply_reloc(event, runtime, runtime->len, reloc_offset, name);
+ ret = apply_reloc(event_desc, runtime, runtime->len, reloc_offset, name);
if (ret) {
goto link_error;
}
goto link_error;
}
/* Specialize bytecode */
- ret = lttng_filter_specialize_bytecode(event, runtime);
+ ret = lttng_filter_specialize_bytecode(event_desc, runtime);
if (ret) {
goto link_error;
}
/*
* Link bytecode for all enablers referenced by an event.
*/
-void lttng_enabler_event_link_bytecode(struct lttng_event *event,
+void lttng_enabler_link_bytecode(const struct lttng_event_desc *event_desc,
+ struct lttng_ctx **ctx,
+ struct cds_list_head *bytecode_runtime_head,
struct lttng_enabler *enabler)
{
struct lttng_ust_filter_bytecode_node *bc;
struct lttng_bytecode_runtime *runtime;
- /* Can only be called for events with desc attached */
- assert(event->desc);
+ assert(event_desc);
/* Link each bytecode. */
cds_list_for_each_entry(bc, &enabler->filter_bytecode_head, node) {
struct cds_list_head *insert_loc;
cds_list_for_each_entry(runtime,
- &event->bytecode_runtime_head, node) {
+ bytecode_runtime_head, node) {
if (runtime->bc == bc) {
found = 1;
break;
* order.
*/
cds_list_for_each_entry_reverse(runtime,
- &event->bytecode_runtime_head, node) {
+ bytecode_runtime_head, node) {
if (runtime->bc->bc.seqnum < bc->bc.seqnum) {
/* insert here */
insert_loc = &runtime->node;
goto add_within;
}
}
+
/* Add to head to list */
- insert_loc = &event->bytecode_runtime_head;
+ insert_loc = bytecode_runtime_head;
add_within:
dbg_printf("linking bytecode\n");
- ret = _lttng_filter_event_link_bytecode(event, bc,
- insert_loc);
+ ret = _lttng_filter_link_bytecode(event_desc, ctx, bc,
+ insert_loc);
if (ret) {
dbg_printf("[lttng filter] warning: cannot link event bytecode\n");
}
return 0;
}
-void lttng_free_event_filter_runtime(struct lttng_event *event)
+static
+void free_filter_runtime(struct cds_list_head *bytecode_runtime_head)
{
struct bytecode_runtime *runtime, *tmp;
- cds_list_for_each_entry_safe(runtime, tmp,
- &event->bytecode_runtime_head, p.node) {
+ cds_list_for_each_entry_safe(runtime, tmp, bytecode_runtime_head,
+ p.node) {
free(runtime->data);
free(runtime);
}
}
+
+void lttng_free_event_filter_runtime(struct lttng_event *event)
+{
+ free_filter_runtime(&event->bytecode_runtime_head);
+}
+
+void lttng_free_trigger_filter_runtime(struct lttng_trigger *trigger)
+{
+ free_filter_runtime(&trigger->bytecode_runtime_head);
+}
const char *print_op(enum filter_op op);
int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode);
-int lttng_filter_specialize_bytecode(struct lttng_event *event,
+int lttng_filter_specialize_bytecode(const struct lttng_event_desc *event_desc,
struct bytecode_runtime *bytecode);
uint64_t lttng_filter_false(void *filter_data,
#include "lttng-tracer-core.h"
#include "jhash.h"
#include "error.h"
+#include "ust-events-internal.h"
/*
* probe list is protected by ust_lock()/ust_unlock().
if (lttng_session_active())
fixup_lazy_probes();
+ lttng_fix_pending_triggers();
+
ust_unlock();
return ret;
}
*/
#define _LGPL_SOURCE
+#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include "../libringbuffer/shm.h"
#include "lttng-tracer.h"
#include "string-utils.h"
+#include "ust-events-internal.h"
#define OBJ_NAME_LEN 16
*/
static const struct lttng_ust_objd_ops lttng_ops;
+static const struct lttng_ust_objd_ops lttng_trigger_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_enabler_ops;
+static const struct lttng_ust_objd_ops lttng_event_enabler_ops;
+static const struct lttng_ust_objd_ops lttng_trigger_enabler_ops;
static const struct lttng_ust_objd_ops lttng_tracepoint_list_ops;
static const struct lttng_ust_objd_ops lttng_tracepoint_field_list_ops;
return 0;
}
+static
+int lttng_abi_trigger_send_fd(void *owner, int trigger_notif_fd)
+{
+ struct lttng_trigger_group *trigger_group;
+ int trigger_group_objd, ret, fd_flag, close_ret;
+
+ trigger_group = lttng_trigger_group_create();
+ if (!trigger_group)
+ return -ENOMEM;
+
+ /*
+ * Set this file descriptor as NON-BLOCKING.
+ */
+ fd_flag = fcntl(trigger_notif_fd, F_GETFL);
+
+ fd_flag |= O_NONBLOCK;
+
+ ret = fcntl(trigger_notif_fd, F_SETFL, fd_flag);
+ if (ret) {
+ ret = -errno;
+ goto fd_error;
+ }
+
+ trigger_group_objd = objd_alloc(trigger_group,
+ <tng_trigger_group_ops, owner, "trigger_group");
+ if (trigger_group_objd < 0) {
+ ret = trigger_group_objd;
+ goto objd_error;
+ }
+
+ trigger_group->objd = trigger_group_objd;
+ trigger_group->owner = owner;
+ trigger_group->notification_fd = trigger_notif_fd;
+
+ return trigger_group_objd;
+
+objd_error:
+ lttng_trigger_group_destroy(trigger_group);
+fd_error:
+ close_ret = close(trigger_notif_fd);
+ if (close_ret) {
+ PERROR("close");
+ }
+
+ return ret;
+}
+
static
long lttng_abi_add_context(int objd,
struct lttng_ust_context *context_param,
case LTTNG_UST_WAIT_QUIESCENT:
synchronize_trace();
return 0;
+ case LTTNG_UST_TRIGGER_GROUP_CREATE:
+ return lttng_abi_trigger_send_fd(owner,
+ uargs->trigger_handle.trigger_notif_fd);
default:
return -EINVAL;
}
.cmd = lttng_session_cmd,
};
+static int lttng_ust_trigger_enabler_create(int trigger_group_obj, void *owner,
+ struct lttng_ust_trigger *trigger_param,
+ enum lttng_enabler_format_type type)
+{
+ struct lttng_trigger_group *trigger_group =
+ objd_private(trigger_group_obj);
+ struct lttng_trigger_enabler *trigger_enabler;
+ int trigger_objd, ret;
+
+ trigger_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+ trigger_objd = objd_alloc(NULL, <tng_trigger_enabler_ops, owner,
+ "trigger enabler");
+ if (trigger_objd < 0) {
+ ret = trigger_objd;
+ goto objd_error;
+ }
+
+ trigger_enabler = lttng_trigger_enabler_create(trigger_group, type,
+ trigger_param);
+ if (!trigger_enabler) {
+ ret = -ENOMEM;
+ goto trigger_error;
+ }
+
+ objd_set_private(trigger_objd, trigger_enabler);
+ /* The trigger holds a reference on the trigger group. */
+ objd_ref(trigger_enabler->group->objd);
+
+ return trigger_objd;
+
+trigger_error:
+ {
+ int err;
+
+ err = lttng_ust_objd_unref(trigger_objd, 1);
+ assert(!err);
+ }
+objd_error:
+ return ret;
+}
+
+static
+long lttng_trigger_enabler_cmd(int objd, unsigned int cmd, unsigned long arg,
+ union ust_args *uargs, void *owner)
+{
+ struct lttng_trigger_enabler *trigger_enabler = objd_private(objd);
+ switch (cmd) {
+ case LTTNG_UST_FILTER:
+ return lttng_trigger_enabler_attach_bytecode(trigger_enabler,
+ (struct lttng_ust_filter_bytecode_node *) arg);
+ case LTTNG_UST_EXCLUSION:
+ return lttng_trigger_enabler_attach_exclusion(trigger_enabler,
+ (struct lttng_ust_excluder_node *) arg);
+ case LTTNG_UST_ENABLE:
+ return lttng_trigger_enabler_enable(trigger_enabler);
+ case LTTNG_UST_DISABLE:
+ return lttng_trigger_enabler_disable(trigger_enabler);
+ default:
+ return -EINVAL;
+ }
+}
+
+static
+long lttng_trigger_group_cmd(int objd, unsigned int cmd, unsigned long arg,
+ union ust_args *uargs, void *owner)
+{
+ switch (cmd) {
+ case LTTNG_UST_TRIGGER_CREATE:
+ {
+ struct lttng_ust_trigger *trigger_param =
+ (struct lttng_ust_trigger *) arg;
+ if (strutils_is_star_glob_pattern(trigger_param->name)) {
+ /*
+ * If the event name is a star globbing pattern,
+ * we create the special star globbing enabler.
+ */
+ return lttng_ust_trigger_enabler_create(objd, owner,
+ trigger_param, LTTNG_ENABLER_FORMAT_STAR_GLOB);
+ } else {
+ return lttng_ust_trigger_enabler_create(objd, owner,
+ trigger_param, LTTNG_ENABLER_FORMAT_EVENT);
+ }
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static
+int lttng_trigger_enabler_release(int objd)
+{
+ struct lttng_trigger_enabler *trigger_enabler = objd_private(objd);
+
+ if (trigger_enabler)
+ return lttng_ust_objd_unref(trigger_enabler->group->objd, 0);
+ return 0;
+}
+
+static const struct lttng_ust_objd_ops lttng_trigger_enabler_ops = {
+ .release = lttng_trigger_enabler_release,
+ .cmd = lttng_trigger_enabler_cmd,
+};
+
+static
+int lttng_release_trigger_group(int objd)
+{
+ struct lttng_trigger_group *trigger_group = objd_private(objd);
+
+ if (trigger_group) {
+ lttng_trigger_group_destroy(trigger_group);
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+
+static const struct lttng_ust_objd_ops lttng_trigger_group_ops = {
+ .release = lttng_release_trigger_group,
+ .cmd = lttng_trigger_group_cmd,
+};
+
static
long lttng_tracepoint_list_cmd(int objd, unsigned int cmd, unsigned long arg,
union ust_args *uargs, void *owner)
}
static
-int lttng_abi_create_enabler(int channel_objd,
+int lttng_abi_create_event_enabler(int channel_objd,
struct lttng_ust_event *event_param,
void *owner,
- enum lttng_enabler_type type)
+ enum lttng_enabler_format_type format_type)
{
struct lttng_channel *channel = objd_private(channel_objd);
- struct lttng_enabler *enabler;
+ struct lttng_event_enabler *enabler;
int event_objd, ret;
event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
- event_objd = objd_alloc(NULL, <tng_enabler_ops, owner, "enabler");
+ event_objd = objd_alloc(NULL, <tng_event_enabler_ops, owner,
+ "event enabler");
if (event_objd < 0) {
ret = event_objd;
goto objd_error;
* We tolerate no failure path after event creation. It will stay
* invariant for the rest of the session.
*/
- enabler = lttng_enabler_create(type, event_param, channel);
+ enabler = lttng_event_enabler_create(format_type, event_param, channel);
if (!enabler) {
ret = -ENOMEM;
goto event_error;
* If the event name is a star globbing pattern,
* we create the special star globbing enabler.
*/
- return lttng_abi_create_enabler(objd, event_param,
- owner, LTTNG_ENABLER_STAR_GLOB);
+ return lttng_abi_create_event_enabler(objd, event_param,
+ owner, LTTNG_ENABLER_FORMAT_STAR_GLOB);
} else {
- return lttng_abi_create_enabler(objd, event_param,
- owner, LTTNG_ENABLER_EVENT);
+ return lttng_abi_create_event_enabler(objd, event_param,
+ owner, LTTNG_ENABLER_FORMAT_EVENT);
}
}
case LTTNG_UST_CONTEXT:
* Attach exclusions to an enabler.
*/
static
-long lttng_enabler_cmd(int objd, unsigned int cmd, unsigned long arg,
+long lttng_event_enabler_cmd(int objd, unsigned int cmd, unsigned long arg,
union ust_args *uargs, void *owner)
{
- struct lttng_enabler *enabler = objd_private(objd);
+ struct lttng_event_enabler *enabler = objd_private(objd);
switch (cmd) {
case LTTNG_UST_CONTEXT:
- return lttng_enabler_attach_context(enabler,
+ return lttng_event_enabler_attach_context(enabler,
(struct lttng_ust_context *) arg);
case LTTNG_UST_ENABLE:
- return lttng_enabler_enable(enabler);
+ return lttng_event_enabler_enable(enabler);
case LTTNG_UST_DISABLE:
- return lttng_enabler_disable(enabler);
+ return lttng_event_enabler_disable(enabler);
case LTTNG_UST_FILTER:
{
int ret;
- ret = lttng_enabler_attach_bytecode(enabler,
+ ret = lttng_event_enabler_attach_bytecode(enabler,
(struct lttng_ust_filter_bytecode_node *) arg);
if (ret)
return ret;
}
case LTTNG_UST_EXCLUSION:
{
- return lttng_enabler_attach_exclusion(enabler,
+ return lttng_event_enabler_attach_exclusion(enabler,
(struct lttng_ust_excluder_node *) arg);
}
default:
}
static
-int lttng_enabler_release(int objd)
+int lttng_event_enabler_release(int objd)
{
- struct lttng_enabler *enabler = objd_private(objd);
+ struct lttng_event_enabler *event_enabler = objd_private(objd);
+
+ if (event_enabler)
+ return lttng_ust_objd_unref(event_enabler->chan->objd, 0);
- if (enabler)
- return lttng_ust_objd_unref(enabler->chan->objd, 0);
return 0;
}
-static const struct lttng_ust_objd_ops lttng_enabler_ops = {
- .release = lttng_enabler_release,
- .cmd = lttng_enabler_cmd,
+static const struct lttng_ust_objd_ops lttng_event_enabler_ops = {
+ .release = lttng_event_enabler_release,
+ .cmd = lttng_event_enabler_cmd,
};
void lttng_ust_abi_exit(void)
[ LTTNG_UST_REGISTER_DONE ] = "Registration Done",
[ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List",
+ [ LTTNG_UST_TRIGGER_GROUP_CREATE ] = "Create trigger group",
+ [ LTTNG_UST_TRIGGER_CREATE ] = "Create trigger",
+
/* Session FD commands */
[ LTTNG_UST_CHANNEL ] = "Create Channel",
[ LTTNG_UST_SESSION_START ] = "Start Session",
}
break;
}
+ case LTTNG_UST_TRIGGER_GROUP_CREATE:
+ {
+ int trigger_notif_fd;
+
+ len = ustcomm_recv_trigger_notif_fd_from_sessiond(sock,
+ &trigger_notif_fd);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error;
+ case 1:
+ break;
+ default:
+ 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 trigger fd message size: %zd", len);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ args.trigger_handle.trigger_notif_fd = trigger_notif_fd;
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
case LTTNG_UST_CHANNEL:
{
void *chan_data;
--- /dev/null
+#ifndef _LTTNG_UST_EVENTS_INTERNAL_H
+#define _LTTNG_UST_EVENTS_INTERNAL_H
+
+/*
+ * ust-events-internal.h
+ *
+ * Copyright 2019 (c) - Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include <urcu/list.h>
+#include <urcu/hlist.h>
+
+#include <helper.h>
+#include <lttng/ust-events.h>
+
+struct lttng_event_enabler {
+ struct lttng_enabler base;
+ struct cds_list_head node; /* per-session list of enablers */
+ struct lttng_channel *chan;
+ /*
+ * Unused, but kept around to make it explicit that the tracer can do
+ * it.
+ */
+ struct lttng_ctx *ctx;
+};
+
+struct lttng_trigger_enabler {
+ struct lttng_enabler base;
+ uint64_t id;
+ struct cds_list_head node; /* per-app list of trigger enablers */
+ struct lttng_trigger_group *group; /* weak ref */
+};
+
+static inline
+struct lttng_enabler *lttng_event_enabler_as_enabler(
+ struct lttng_event_enabler *event_enabler)
+{
+ return &event_enabler->base;
+}
+
+static inline
+struct lttng_enabler *lttng_trigger_enabler_as_enabler(
+ struct lttng_trigger_enabler *trigger_enabler)
+{
+ return &trigger_enabler->base;
+}
+
+/* TODO doc */
+LTTNG_HIDDEN
+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);
+
+/* TODO doc */
+LTTNG_HIDDEN
+void lttng_event_enabler_destroy(struct lttng_event_enabler *enabler);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_event_enabler_enable(struct lttng_event_enabler *enabler);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_event_enabler_disable(struct lttng_event_enabler *enabler);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_event_enabler_attach_bytecode(struct lttng_event_enabler *enabler,
+ struct lttng_ust_filter_bytecode_node *bytecode);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_event_enabler_attach_context(struct lttng_event_enabler *enabler,
+ struct lttng_ust_context *ctx);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *enabler,
+ struct lttng_ust_excluder_node *excluder);
+
+/* TODO doc */
+LTTNG_HIDDEN
+void lttng_enabler_link_bytecode(const struct lttng_event_desc *event_desc,
+ struct lttng_ctx **ctx,
+ struct cds_list_head *bytecode_runtime_head,
+ struct lttng_enabler *enabler);
+
+/* TODO doc */
+LTTNG_HIDDEN
+struct lttng_trigger_group *lttng_trigger_group_create(void);
+
+/* TODO doc */
+LTTNG_HIDDEN
+void lttng_trigger_group_destroy(
+ struct lttng_trigger_group *trigger_group);
+
+/* TODO doc */
+LTTNG_HIDDEN
+struct lttng_trigger_enabler *lttng_trigger_enabler_create(
+ struct lttng_trigger_group *trigger_group,
+ enum lttng_enabler_format_type format_type,
+ struct lttng_ust_trigger *trigger_param);
+
+/* TODO doc */
+LTTNG_HIDDEN
+void lttng_trigger_enabler_destroy(struct lttng_trigger_enabler *trigger_enabler);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_trigger_enabler_enable(struct lttng_trigger_enabler *trigger_enabler);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_trigger_enabler_disable(struct lttng_trigger_enabler *trigger_enabler);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_trigger_enabler_attach_bytecode(
+ struct lttng_trigger_enabler *trigger_enabler,
+ struct lttng_ust_filter_bytecode_node *bytecode);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_trigger_enabler_attach_exclusion(
+ struct lttng_trigger_enabler *trigger_enabler,
+ struct lttng_ust_excluder_node *excluder);
+
+/* TODO doc */
+LTTNG_HIDDEN
+void lttng_free_trigger_filter_runtime(struct lttng_trigger *trigger);
+
+/* TODO doc */
+LTTNG_HIDDEN
+int lttng_fix_pending_triggers(void);
+
+#endif /* _LTTNG_UST_EVENTS_INTERNAL_H */