Implement support for overlapping wildcard/events
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 16 Nov 2012 15:19:32 +0000 (10:19 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 22 Nov 2012 18:56:09 +0000 (13:56 -0500)
Reviewed-by: David Goulet <dgoulet@efficios.com>
Reviewed-by: Christian Babeux <christian.babeux@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
include/lttng/ust-events.h
include/lttng/ust-tracepoint-event.h
liblttng-ust/lttng-events.c
liblttng-ust/lttng-filter.c
liblttng-ust/lttng-probes.c
liblttng-ust/lttng-ust-abi.c

index 4a7d67f26d8914c88bffc3e2c29ad6909776149c..5010a66e3e89d5c426f1bbe0f77d93d7026b9efd 100644 (file)
@@ -244,37 +244,26 @@ struct lttng_probe_desc {
 
 /* Data structures used by the tracer. */
 
-/*
- * Entry describing a per-session active wildcard, along with the event
- * attribute and channel information configuring the events that need to
- * be enabled.
- */
-struct session_wildcard {
-       struct lttng_channel *chan;
-       struct lttng_ctx *ctx;  /* TODO */
-       struct lttng_ust_event event_param;
-       struct cds_list_head events;    /* list of events enabled */
-       struct cds_list_head list;      /* per-session list of wildcards */
-       struct cds_list_head session_list; /* node of session wildcard list */
-       struct wildcard_entry *entry;
-       /* list of struct lttng_ust_filter_bytecode_node */
-       struct cds_list_head filter_bytecode;
-       unsigned int enabled:1;
+enum lttng_enabler_type {
+       LTTNG_ENABLER_WILDCARD,
+       LTTNG_ENABLER_EVENT,
 };
 
 /*
- * Entry describing an active wildcard (per name) for all sessions.
+ * Enabler field, within whatever object is enabling an event. Target of
+ * backward reference.
  */
-struct wildcard_entry {
-       /* node of global wildcards list */
-       struct cds_list_head list;
-       /* head of session list to which this wildcard apply */
-       struct cds_list_head session_list;
-       enum lttng_ust_loglevel_type loglevel_type;
-       /* list of struct lttng_ust_filter_bytecode_node */
-       struct cds_list_head filter_bytecode;
-       int loglevel;
-       char name[0];
+struct lttng_enabler {
+       enum lttng_enabler_type type;
+
+       /* head list of struct lttng_ust_filter_bytecode_node */
+       struct cds_list_head filter_bytecode_head;
+       struct cds_list_head node;      /* per-session list of enablers */
+
+       struct lttng_ust_event event_param;
+       struct lttng_channel *chan;
+       struct lttng_ctx *ctx;
+       unsigned int enabled:1;
 };
 
 struct tp_list_entry {
@@ -303,13 +292,22 @@ struct lttng_event;
 struct lttng_ust_filter_bytecode_node {
        struct cds_list_head node;
        struct lttng_ust_filter_bytecode bc;
+       struct lttng_enabler *enabler;
 };
 
 struct lttng_bytecode_runtime {
        /* Associated bytecode */
        struct lttng_ust_filter_bytecode_node *bc;
        int (*filter)(void *filter_data, const char *filter_stack_data);
-       struct cds_list_head node;
+       struct cds_list_head node;      /* list of bytecode runtime in event */
+};
+
+/*
+ * Objects in a linked-list of enablers, owned by an event.
+ */
+struct lttng_enabler_ref {
+       struct cds_list_head node;              /* enabler ref list */
+       struct lttng_enabler *ref;              /* backward ref */
 };
 
 /*
@@ -326,20 +324,22 @@ struct lttng_event {
        struct lttng_channel *chan;
        int enabled;
        const struct lttng_event_desc *desc;
-       void *filter_unused;
+       void *_deprecated1;
        struct lttng_ctx *ctx;
        enum lttng_ust_instrumentation instrumentation;
        union {
        } u;
-       struct cds_list_head list;              /* Event list */
-       struct cds_list_head wildcard_list;     /* Event list for wildcard */
-       struct ust_pending_probe *pending_probe;
+       struct cds_list_head node;              /* Event list in session */
+       struct cds_list_head _deprecated2;
+       void *_deprecated3;
        unsigned int metadata_dumped:1;
+
        /* LTTng-UST 2.1 starts here */
-       /* list of struct lttng_ust_filter_bytecode_node */
-       struct cds_list_head filter_bytecode;
-       /* list of struct lttng_bytecode_runtime */
-       struct cds_list_head bytecode_runtime;
+       /* list of struct lttng_bytecode_runtime, sorted by seqnum */
+       struct cds_list_head bytecode_runtime_head;
+
+       /* Backward references: list of lttng_enabler_ref (ref to enablers) */
+       struct cds_list_head enablers_ref_head;
 };
 
 struct channel;
@@ -405,7 +405,7 @@ struct lttng_channel {
        int objd;                       /* Object associated to channel */
        unsigned int free_event_id;     /* Next event ID to allocate */
        unsigned int used_event_id;     /* Max allocated event IDs */
-       struct cds_list_head list;      /* Channel list */
+       struct cds_list_head node;      /* Channel list in session */
        struct lttng_channel_ops *ops;
        int header_type;                /* 0: unset, 1: compact, 2: large */
        struct lttng_ust_shm_handle *handle;    /* shared-memory handle */
@@ -417,23 +417,34 @@ struct lttng_channel {
        unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
 };
 
+#define LTTNG_UST_EVENT_HT_BITS                6
+#define LTTNG_UST_EVENT_HT_SIZE                (1U << LTTNG_UST_EVENT_HT_BITS)
+
+struct lttng_ust_event_ht {
+       struct cds_hlist_head table[LTTNG_UST_EVENT_HT_SIZE];
+};
+
 /*
  * IMPORTANT: this structure is part of the ABI between the probe and
  * UST. Fields need to be only added at the end, never reordered, never
  * removed.
  */
 struct lttng_session {
-       int active;                     /* Is trace session active ? */
-       int been_active;                /* Has trace session been active ? */
-       int objd;                       /* Object associated to session */
-       struct lttng_channel *metadata; /* Metadata channel */
-       struct cds_list_head chan;      /* Channel list head */
-       struct cds_list_head events;    /* Event list head */
-       struct cds_list_head wildcards; /* Wildcard list head */
-       struct cds_list_head list;      /* Session list */
-       unsigned int free_chan_id;      /* Next chan ID to allocate */
+       int active;                             /* Is trace session active ? */
+       int been_active;                        /* Been active ? */
+       int objd;                               /* Object associated */
+       struct lttng_channel *metadata;         /* Metadata channel */
+       struct cds_list_head chan_head;         /* Channel list head */
+       struct cds_list_head events_head;       /* list of events */
+       struct cds_list_head _deprecated1;
+       struct cds_list_head node;              /* Session list */
+       unsigned int free_chan_id;              /* Next chan ID to allocate */
        unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
        unsigned int metadata_dumped:1;
+
+       /* New UST 2.1 */
+       /* List of enablers */
+       struct cds_list_head enablers_head;
 };
 
 struct lttng_transport {
@@ -464,14 +475,21 @@ struct lttng_channel *lttng_global_channel_create(struct lttng_session *session,
                                       int **shm_fd, int **wait_fd,
                                       uint64_t **memory_map_size);
 
-int lttng_event_create(struct lttng_channel *chan,
-               struct lttng_ust_event *event_param,
-               struct lttng_event **event);
-
 int lttng_channel_enable(struct lttng_channel *channel);
 int lttng_channel_disable(struct lttng_channel *channel);
-int lttng_event_enable(struct lttng_event *event);
-int lttng_event_disable(struct lttng_event *event);
+
+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_attach_context(struct lttng_ust_context *context_param,
+               struct lttng_ctx **ctx, struct lttng_session *session);
 
 void lttng_transport_register(struct lttng_transport *transport);
 void lttng_transport_unregister(struct lttng_transport *transport);
@@ -480,7 +498,7 @@ void synchronize_trace(void);
 
 int lttng_probe_register(struct lttng_probe_desc *desc);
 void lttng_probe_unregister(struct lttng_probe_desc *desc);
-int pending_probe_fix_events(const struct lttng_event_desc *desc);
+int lttng_fix_pending_event_desc(const struct lttng_event_desc *desc);
 const struct lttng_event_desc *lttng_event_get(const char *name);
 void lttng_event_put(const struct lttng_event_desc *desc);
 int lttng_probes_init(void);
@@ -512,26 +530,12 @@ void lttng_probes_prune_field_list(struct lttng_ust_field_list *list);
 struct lttng_ust_field_iter *
        lttng_ust_field_list_get_iter_next(struct lttng_ust_field_list *list);
 
-int lttng_wildcard_enable(struct session_wildcard *wildcard);
-int lttng_wildcard_disable(struct session_wildcard *wildcard);
-int lttng_wildcard_create(struct lttng_channel *chan,
-       struct lttng_ust_event *event_param,
-       struct session_wildcard **sl);
-int lttng_loglevel_match(const struct lttng_event_desc *desc,
-               enum lttng_ust_loglevel_type req_type,
-               int req_loglevel);
-void lttng_probes_create_wildcard_events(struct wildcard_entry *entry,
-                               struct session_wildcard *wildcard);
-int lttng_filter_event_attach_bytecode(struct lttng_event *event,
-                struct lttng_ust_filter_bytecode_node *filter);
-int lttng_filter_wildcard_attach_bytecode(struct session_wildcard *wildcard,
-                struct lttng_ust_filter_bytecode_node *filter);
 void lttng_filter_event_link_bytecode(struct lttng_event *event);
-void lttng_filter_event_link_wildcard_bytecode(struct lttng_event *event,
-               struct session_wildcard *wildcard);
-void lttng_filter_wildcard_link_bytecode(struct session_wildcard *wildcard);
-void lttng_free_event_filter_bytecode(struct lttng_event *event);
-void lttng_free_wildcard_filter_bytecode(struct session_wildcard *wildcard);
+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);
+
+struct cds_list_head *lttng_get_probe_list_head(void);
 
 #endif /* _LTTNG_UST_EVENTS_H */
index 0be3395be7d72996dc7a33645ceabd6048396f9c..a9de4a7aeae020dac741a6cd951d305d4c62e157 100644 (file)
@@ -486,12 +486,12 @@ void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args))         \
                return;                                                       \
        if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled)))                 \
                return;                                                       \
-       if (caa_unlikely(!cds_list_empty(&__event->bytecode_runtime))) {      \
+       if (caa_unlikely(!cds_list_empty(&__event->bytecode_runtime_head))) { \
                struct lttng_bytecode_runtime *bc_runtime;                    \
                                                                              \
                __event_prepare_filter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \
                        _TP_ARGS_DATA_VAR(_args));                            \
-               cds_list_for_each_entry_rcu(bc_runtime, &__event->bytecode_runtime, node) { \
+               cds_list_for_each_entry_rcu(bc_runtime, &__event->bytecode_runtime_head, node) { \
                        if (caa_likely(!bc_runtime->filter(bc_runtime,        \
                                        __stackvar.__filter_stack_data)))     \
                                return;                                       \
index 24b5c666fd8628557ce77f8f04afa1c296e78752..95082ceda6fadd21827db61cde7f56945c3dcdcf 100644 (file)
@@ -75,31 +75,7 @@ void ust_unlock(void)
 
 static CDS_LIST_HEAD(sessions);
 
-/*
- * Wildcard list, containing the active wildcards.
- * Protected by ust lock.
- */
-static CDS_LIST_HEAD(wildcard_list);
-
-/*
- * Pending probes hash table, containing the registered ltt events for
- * which tracepoint probes are still missing. Protected by the sessions
- * mutex.
- */
-#define PENDING_PROBE_HASH_BITS                6
-#define PENDING_PROBE_HASH_SIZE                (1 << PENDING_PROBE_HASH_BITS)
-static struct cds_hlist_head pending_probe_table[PENDING_PROBE_HASH_SIZE];
-
-struct ust_pending_probe {
-       struct lttng_event *event;
-       struct cds_hlist_node node;
-       enum lttng_ust_loglevel_type loglevel_type;
-       int loglevel;
-       char name[];
-};
-
 static void _lttng_event_destroy(struct lttng_event *event);
-static void _lttng_wildcard_destroy(struct session_wildcard *sw);
 static void _lttng_channel_destroy(struct lttng_channel *chan);
 static int _lttng_event_unregister(struct lttng_event *event);
 static
@@ -109,26 +85,31 @@ int _lttng_event_metadata_statedump(struct lttng_session *session,
 static
 int _lttng_session_metadata_statedump(struct lttng_session *session);
 
-int lttng_loglevel_match(const struct lttng_event_desc *desc,
+static
+void lttng_session_lazy_sync_enablers(struct lttng_session *session);
+static
+void lttng_session_sync_enablers(struct lttng_session *session);
+static
+void lttng_enabler_destroy(struct lttng_enabler *enabler);
+
+static
+int lttng_loglevel_match(int loglevel,
+               unsigned int has_loglevel,
                enum lttng_ust_loglevel_type req_type,
                int req_loglevel)
 {
-       int ev_loglevel;
-
        if (req_type == LTTNG_UST_LOGLEVEL_ALL)
                return 1;
-       if (!desc->loglevel)
-               ev_loglevel = TRACE_DEFAULT;
-       else
-               ev_loglevel = *(*desc->loglevel);
+       if (!has_loglevel)
+               loglevel = TRACE_DEFAULT;
        switch (req_type) {
        case LTTNG_UST_LOGLEVEL_RANGE:
-               if (ev_loglevel <= req_loglevel || req_loglevel == -1)
+               if (loglevel <= req_loglevel || req_loglevel == -1)
                        return 1;
                else
                        return 0;
        case LTTNG_UST_LOGLEVEL_SINGLE:
-               if (ev_loglevel == req_loglevel || req_loglevel == -1)
+               if (loglevel == req_loglevel || req_loglevel == -1)
                        return 1;
                else
                        return 0;
@@ -138,175 +119,6 @@ int lttng_loglevel_match(const struct lttng_event_desc *desc,
        }
 }
 
-/*
- * Return wildcard for a given event name if the event name match the
- * one of the wildcards.
- * Must be called with ust lock held.
- * Returns NULL if not present.
- */
-static
-struct wildcard_entry *match_wildcard(const struct lttng_event_desc *desc)
-{
-       struct wildcard_entry *e;
-
-       cds_list_for_each_entry(e, &wildcard_list, list) {
-               /* If only contain '*' */
-               if (strlen(e->name) == 1)
-                       goto possible_match;
-               /* Compare excluding final '*' */
-               if (!strncmp(desc->name, e->name, strlen(e->name) - 1))
-                       goto possible_match;
-               continue;       /* goto next, no match */
-       possible_match:
-               if (lttng_loglevel_match(desc,
-                               e->loglevel_type,
-                               e->loglevel)) {
-                       return e;
-               }
-               /* no match, loop to next */
-       }
-       return NULL;
-}
-
-/*
- * called at event creation if probe is missing.
- * called with session mutex held.
- */
-static
-int add_pending_probe(struct lttng_event *event, const char *name,
-               enum lttng_ust_loglevel_type loglevel_type,
-               int loglevel)
-{
-       struct cds_hlist_head *head;
-       struct ust_pending_probe *e;
-       size_t name_len = strlen(name) + 1;
-       uint32_t hash;
-
-       if (name_len > LTTNG_UST_SYM_NAME_LEN) {
-               WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN);
-               name_len = LTTNG_UST_SYM_NAME_LEN;
-       }
-       hash = jhash(name, name_len - 1, 0);
-       head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)];
-       e = zmalloc(sizeof(struct ust_pending_probe) + name_len);
-       if (!e)
-               return -ENOMEM;
-       memcpy(&e->name[0], name, name_len);
-       e->name[name_len - 1] = '\0';
-       e->loglevel_type = loglevel_type;
-       e->loglevel = loglevel;
-       cds_hlist_add_head(&e->node, head);
-       e->event = event;
-       event->pending_probe = e;
-       return 0;
-}
-
-/*
- * remove a pending probe. called when at event teardown and when an
- * event is fixed (probe is loaded).
- * called with session mutex held.
- */
-static
-void remove_pending_probe(struct ust_pending_probe *e)
-{
-       if (!e)
-               return;
-       cds_hlist_del(&e->node);
-       free(e);
-}
-
-/*
- * Called at library load: connect the probe on the events pending on
- * probe load.
- * called with session mutex held.
- */
-int pending_probe_fix_events(const struct lttng_event_desc *desc)
-{
-       struct cds_hlist_head *head;
-       struct cds_hlist_node *node, *p;
-       struct ust_pending_probe *e;
-       const char *name = desc->name;
-       int ret = 0;
-       struct lttng_ust_event event_param;
-       size_t name_len = strlen(name) + 1;
-       uint32_t hash;
-
-       /* Wildcard */
-       {
-               struct wildcard_entry *wildcard;
-
-               //FIXME: should iterate on all match for filter.
-               //FIXME: should re-use pending event if present rather
-               //than create duplicate.
-               wildcard = match_wildcard(desc);
-               if (strcmp(desc->name, "lttng_ust:metadata") && wildcard) {
-                       struct session_wildcard *sw;
-
-                       cds_list_for_each_entry(sw, &wildcard->session_list,
-                                       session_list) {
-                               struct lttng_event *ev;
-                               int ret;
-
-                               memcpy(&event_param, &sw->event_param,
-                                               sizeof(event_param));
-                               strncpy(event_param.name,
-                                       desc->name,
-                                       sizeof(event_param.name));
-                               event_param.name[sizeof(event_param.name) - 1] = '\0';
-                               /* create event */
-                               ret = lttng_event_create(sw->chan,
-                                       &event_param, &ev);
-                               if (ret) {
-                                       DBG("Error creating event");
-                                       continue;
-                               }
-                               cds_list_add(&ev->wildcard_list,
-                                       &sw->events);
-                               lttng_filter_event_link_wildcard_bytecode(ev,
-                                       sw);
-                       }
-               }
-       }
-
-       if (name_len > LTTNG_UST_SYM_NAME_LEN) {
-               WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN);
-               name_len = LTTNG_UST_SYM_NAME_LEN;
-       }
-       hash = jhash(name, name_len - 1, 0);
-       head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)];
-       cds_hlist_for_each_entry_safe(e, node, p, head, node) {
-               struct lttng_event *event;
-               struct lttng_channel *chan;
-
-               if (!lttng_loglevel_match(desc,
-                               e->loglevel_type,
-                               e->loglevel)) {
-                       continue;
-               }
-               if (strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) {
-                       continue;
-               }
-               /* TODO: wildcard same as pending event: duplicate */
-               /* TODO: Should apply filter though */
-               event = e->event;
-               chan = event->chan;
-               assert(!event->desc);
-               event->desc = desc;
-               event->pending_probe = NULL;
-               remove_pending_probe(e);
-               ret |= __tracepoint_probe_register(name,
-                               event->desc->probe_callback,
-                               event, event->desc->signature);
-               if (ret)
-                       continue;
-               event->id = chan->free_event_id++;
-               ret |= _lttng_event_metadata_statedump(chan->session, chan,
-                               event);
-               lttng_filter_event_link_bytecode(event);
-       }
-       return ret;
-}
-
 void synchronize_trace(void)
 {
        synchronize_rcu();
@@ -320,14 +132,14 @@ struct lttng_session *lttng_session_create(void)
        session = zmalloc(sizeof(struct lttng_session));
        if (!session)
                return NULL;
-       CDS_INIT_LIST_HEAD(&session->chan);
-       CDS_INIT_LIST_HEAD(&session->events);
-       CDS_INIT_LIST_HEAD(&session->wildcards);
+       CDS_INIT_LIST_HEAD(&session->chan_head);
+       CDS_INIT_LIST_HEAD(&session->events_head);
+       CDS_INIT_LIST_HEAD(&session->enablers_head);
        ret = lttng_ust_uuid_generate(session->uuid);
        if (ret != 0) {
                session->uuid[0] = '\0';
        }
-       cds_list_add(&session->list, &sessions);
+       cds_list_add(&session->node, &sessions);
        return session;
 }
 
@@ -335,22 +147,24 @@ void lttng_session_destroy(struct lttng_session *session)
 {
        struct lttng_channel *chan, *tmpchan;
        struct lttng_event *event, *tmpevent;
-       struct session_wildcard *wildcard, *tmpwildcard;
+       struct lttng_enabler *enabler, *tmpenabler;
        int ret;
 
        CMM_ACCESS_ONCE(session->active) = 0;
-       cds_list_for_each_entry(event, &session->events, list) {
+       cds_list_for_each_entry(event, &session->events_head, node) {
                ret = _lttng_event_unregister(event);
                WARN_ON(ret);
        }
        synchronize_trace();    /* Wait for in-flight events to complete */
-       cds_list_for_each_entry_safe(wildcard, tmpwildcard, &session->wildcards, list)
-               _lttng_wildcard_destroy(wildcard);
-       cds_list_for_each_entry_safe(event, tmpevent, &session->events, list)
+       cds_list_for_each_entry_safe(enabler, tmpenabler,
+                       &session->enablers_head, node)
+               lttng_enabler_destroy(enabler);
+       cds_list_for_each_entry_safe(event, tmpevent,
+                       &session->events_head, node)
                _lttng_event_destroy(event);
-       cds_list_for_each_entry_safe(chan, tmpchan, &session->chan, list)
+       cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node)
                _lttng_channel_destroy(chan);
-       cds_list_del(&session->list);
+       cds_list_del(&session->node);
        free(session);
 }
 
@@ -364,11 +178,14 @@ int lttng_session_enable(struct lttng_session *session)
                goto end;
        }
 
+       /* We need to sync enablers with session before activation. */
+       lttng_session_sync_enablers(session);
+
        /*
         * Snapshot the number of events per channel to know the type of header
         * we need to use.
         */
-       cds_list_for_each_entry(chan, &session->chan, list) {
+       cds_list_for_each_entry(chan, &session->chan_head, node) {
                if (chan->header_type)
                        continue;               /* don't change it if session stop/restart */
                if (chan->free_event_id < 31)
@@ -483,7 +300,7 @@ struct lttng_channel *lttng_channel_create(struct lttng_session *session,
                goto create_error;
        chan->enabled = 1;
        chan->ops = &transport->ops;
-       cds_list_add(&chan->list, &session->chan);
+       cds_list_add(&chan->node, &session->chan_head);
        return chan;
 
 create_error:
@@ -498,7 +315,7 @@ active:
 static
 void _lttng_channel_destroy(struct lttng_channel *chan)
 {
-       cds_list_del(&chan->list);
+       cds_list_del(&chan->node);
        lttng_destroy_context(chan->ctx);
        chan->ops->channel_destroy(chan);
 }
@@ -506,11 +323,11 @@ void _lttng_channel_destroy(struct lttng_channel *chan)
 /*
  * Supports event creation while tracing session is active.
  */
-int lttng_event_create(struct lttng_channel *chan,
-               struct lttng_ust_event *event_param,
-               struct lttng_event **_event)
+static
+int lttng_event_create(const struct lttng_event_desc *desc,
+               struct lttng_channel *chan)
 {
-       const struct lttng_event_desc *desc = NULL;     /* silence gcc */
+       const char *event_name = desc->name;
        struct lttng_event *event;
        int ret = 0;
 
@@ -518,15 +335,14 @@ int lttng_event_create(struct lttng_channel *chan,
                ret = -ENOMEM;
                goto full;
        }
-       //FIXME: re-use event if already registered by wildcard or
-       //if we have a pending probe.... (CHECK)
        /*
         * This is O(n^2) (for each event, the loop is called at event
         * creation). Might require a hash if we have lots of events.
         */
-       cds_list_for_each_entry(event, &chan->session->events, list) {
-               if (event->desc && !strncmp(event->desc->name,
-                               event_param->name,
+       cds_list_for_each_entry(event, &chan->session->events_head, node) {
+               assert(event->desc);
+               if (!strncmp(event->desc->name,
+                               desc->name,
                                LTTNG_UST_SYM_NAME_LEN - 1)) {
                        ret = -EEXIST;
                        goto exist;
@@ -536,135 +352,272 @@ int lttng_event_create(struct lttng_channel *chan,
        /*
         * Check if loglevel match. Refuse to connect event if not.
         */
-       if (event_param->instrumentation == LTTNG_UST_TRACEPOINT) {
-               desc = lttng_event_get(event_param->name);
-               if (desc) {
-                       if (!lttng_loglevel_match(desc,
-                                       event_param->loglevel_type,
-                                       event_param->loglevel)) {
-                               ret = -EPERM;
-                               goto no_loglevel_match;
-                       }
-               }
-               /*
-                * If descriptor is not there, it will be added to
-                * pending probes.
-                */
-       }
        event = zmalloc(sizeof(struct lttng_event));
        if (!event) {
                ret = -ENOMEM;
                goto cache_error;
        }
        event->chan = chan;
+
        /*
         * used_event_id counts the maximum number of event IDs that can
         * register if all probes register.
         */
        chan->used_event_id++;
        event->enabled = 1;
-       CDS_INIT_LIST_HEAD(&event->filter_bytecode);
-       CDS_INIT_LIST_HEAD(&event->bytecode_runtime);
-       event->instrumentation = event_param->instrumentation;
+       CDS_INIT_LIST_HEAD(&event->bytecode_runtime_head);
+       CDS_INIT_LIST_HEAD(&event->enablers_ref_head);
+       event->desc = desc;
        /* Populate lttng_event structure before tracepoint registration. */
        cmm_smp_wmb();
-       switch (event_param->instrumentation) {
-       case LTTNG_UST_TRACEPOINT:
-               event->desc = desc;
-               if (event->desc) {
-                       ret = __tracepoint_probe_register(event_param->name,
-                                       event->desc->probe_callback,
-                                       event, event->desc->signature);
-                       if (ret)
-                               goto register_error;
-                       event->id = chan->free_event_id++;
-               } else {
-                       /*
-                        * If the probe is not present, event->desc stays NULL,
-                        * waiting for the probe to register, and the event->id
-                        * stays unallocated.
-                        */
-                       ret = add_pending_probe(event, event_param->name,
-                                       event_param->loglevel_type,
-                                       event_param->loglevel);
-                       if (ret)
-                               goto add_pending_error;
-               }
-               break;
-       default:
-               WARN_ON_ONCE(1);
-       }
-       if (event->desc) {
-               ret = _lttng_event_metadata_statedump(chan->session, chan, event);
-               if (ret)
-                       goto statedump_error;
-       }
-       cds_list_add(&event->list, &chan->session->events);
-       *_event = event;
+       ret = __tracepoint_probe_register(event_name,
+                       desc->probe_callback,
+                       event, desc->signature);
+       if (ret)
+               goto register_error;
+       event->id = chan->free_event_id++;
+       ret = _lttng_event_metadata_statedump(chan->session, chan, event);
+       if (ret)
+               goto statedump_error;
+       cds_list_add(&event->node, &chan->session->events_head);
        return 0;
 
 statedump_error:
-       if (event->desc) {
-               WARN_ON_ONCE(__tracepoint_probe_unregister(event_param->name,
-                                       event->desc->probe_callback,
-                                       event));
-               lttng_event_put(event->desc);
-       }
-add_pending_error:
+       WARN_ON_ONCE(__tracepoint_probe_unregister(event_name,
+                               desc->probe_callback,
+                               event));
+       lttng_event_put(event->desc);
 register_error:
        free(event);
 cache_error:
-no_loglevel_match:
 exist:
 full:
        return ret;
 }
 
+static
+int lttng_desc_match_wildcard_enabler(const struct lttng_event_desc *desc,
+               struct lttng_enabler *enabler)
+{
+       int loglevel = 0;
+       unsigned int has_loglevel;
+
+       assert(enabler->type == LTTNG_ENABLER_WILDCARD);
+       /* Compare excluding final '*' */
+       if (strncmp(desc->name, enabler->event_param.name,
+                       strlen(enabler->event_param.name) - 1))
+               return 0;
+       if (desc->loglevel) {
+               loglevel = *(*desc->loglevel);
+               has_loglevel = 1;
+       }
+       if (!lttng_loglevel_match(loglevel,
+                       has_loglevel,
+                       enabler->event_param.loglevel_type,
+                       enabler->event_param.loglevel))
+               return 0;
+       return 1;
+}
+
+static
+int lttng_desc_match_event_enabler(const struct lttng_event_desc *desc,
+               struct lttng_enabler *enabler)
+{
+       int loglevel = 0;
+       unsigned int has_loglevel = 0;
+
+       assert(enabler->type == LTTNG_ENABLER_EVENT);
+       if (strcmp(desc->name, enabler->event_param.name))
+               return 0;
+       if (desc->loglevel) {
+               loglevel = *(*desc->loglevel);
+               has_loglevel = 1;
+       }
+       if (!lttng_loglevel_match(loglevel,
+                       has_loglevel,
+                       enabler->event_param.loglevel_type,
+                       enabler->event_param.loglevel))
+               return 0;
+       return 1;
+}
+
+static
+int lttng_desc_match_enabler(const struct lttng_event_desc *desc,
+               struct lttng_enabler *enabler)
+{
+       switch (enabler->type) {
+       case LTTNG_ENABLER_WILDCARD:
+               return lttng_desc_match_wildcard_enabler(desc, enabler);
+       case LTTNG_ENABLER_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)
+{
+       return lttng_desc_match_enabler(event->desc, enabler);
+}
+
+static
+struct lttng_enabler_ref * lttng_event_enabler_ref(struct lttng_event *event,
+               struct lttng_enabler *enabler)
+{
+       struct lttng_enabler_ref *enabler_ref;
+
+       cds_list_for_each_entry(enabler_ref,
+                       &event->enablers_ref_head, node) {
+               if (enabler_ref->ref == enabler)
+                       return enabler_ref;
+       }
+       return NULL;
+}
+
 /*
- * Only used internally at session destruction.
+ * Create struct lttng_event if it is missing and present in the list of
+ * tracepoint probes.
  */
-int _lttng_event_unregister(struct lttng_event *event)
+static
+void lttng_create_event_if_missing(struct lttng_enabler *enabler)
 {
-       int ret = -EINVAL;
-
-       switch (event->instrumentation) {
-       case LTTNG_UST_TRACEPOINT:
-               if (event->desc) {
-                       ret = __tracepoint_probe_unregister(event->desc->name,
-                                                         event->desc->probe_callback,
-                                                         event);
-                       if (ret)
-                               return ret;
-               } else {
-                       remove_pending_probe(event->pending_probe);
-                       ret = 0;
+       struct lttng_session *session = enabler->chan->session;
+       struct lttng_probe_desc *probe_desc;
+       const struct lttng_event_desc *desc;
+       struct lttng_event *event;
+       int i;
+       struct cds_list_head *probe_list;
+
+       probe_list = lttng_get_probe_list_head();
+       /*
+        * For each probe event, if we find that a probe event matches
+        * our enabler, create an associated lttng_event if not
+        * already present.
+        */
+       cds_list_for_each_entry(probe_desc, probe_list, head) {
+               for (i = 0; i < probe_desc->nr_events; i++) {
+                       int found = 0, ret;
+
+                       desc = probe_desc->event_desc[i];
+                       if (!lttng_desc_match_enabler(desc, enabler))
+                               continue;
+
+                       /*
+                        * For each event in session event list,
+                        * check if already created.
+                        */
+                       cds_list_for_each_entry(event,
+                                       &session->events_head, node) {
+                               if (event->desc == desc)
+                                       found = 1;
+                       }
+                       if (found)
+                               continue;
+
+                       /*
+                        * We need to create an event for this
+                        * event probe.
+                        */
+                       ret = lttng_event_create(probe_desc->event_desc[i],
+                                       enabler->chan);
+                       if (ret) {
+                               DBG("Unable to create event %s\n",
+                                       probe_desc->event_desc[i]->name);
+                       }
                }
-               break;
-       default:
-               WARN_ON_ONCE(1);
        }
-       return ret;
 }
 
 /*
- * Only used internally at session destruction.
+ * Create events associated with an enabler (if not already present),
+ * and add backward reference from the event to the enabler.
  */
 static
-void _lttng_event_destroy(struct lttng_event *event)
+int lttng_enabler_ref_events(struct lttng_enabler *enabler)
 {
-       switch (event->instrumentation) {
-       case LTTNG_UST_TRACEPOINT:
-               if (event->desc) {
-                       lttng_event_put(event->desc);
+       struct lttng_session *session = enabler->chan->session;
+       struct lttng_event *event;
+
+       /* First ensure that probe events are created for this enabler. */
+       lttng_create_event_if_missing(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))
+                       continue;
+
+               enabler_ref = lttng_event_enabler_ref(event, enabler);
+               if (!enabler_ref) {
+                       /*
+                        * If no backward ref, create it.
+                        * Add backward ref from event to enabler.
+                        */
+                       enabler_ref = zmalloc(sizeof(*enabler_ref));
+                       if (!enabler_ref)
+                               return -ENOMEM;
+                       enabler_ref->ref = enabler;
+                       cds_list_add(&enabler_ref->node,
+                               &event->enablers_ref_head);
                }
-               break;
-       default:
-               WARN_ON_ONCE(1);
+
+               /*
+                * Link filter bytecodes if not linked yet.
+                */
+               lttng_enabler_event_link_bytecode(event, enabler);
+
+               /* TODO: merge event context. */
+       }
+       return 0;
+}
+
+/*
+ * Called at library load: connect the probe on all enablers matching
+ * this event.
+ * called with session mutex held.
+ * TODO: currently, for each desc added, we iterate on all event desc
+ * (inefficient). We should create specific code that only target the
+ * added desc.
+ */
+int lttng_fix_pending_event_desc(const struct lttng_event_desc *desc)
+{
+       struct lttng_session *session;
+
+       cds_list_for_each_entry(session, &sessions, node) {
+               lttng_session_lazy_sync_enablers(session);
        }
-       cds_list_del(&event->list);
+       return 0;
+}
+
+/*
+ * Only used internally at session destruction.
+ */
+int _lttng_event_unregister(struct lttng_event *event)
+{
+       return __tracepoint_probe_unregister(event->desc->name,
+                                         event->desc->probe_callback,
+                                         event);
+}
+
+/*
+ * Only used internally at session destruction.
+ */
+static
+void _lttng_event_destroy(struct lttng_event *event)
+{
+       struct lttng_enabler_ref *enabler_ref, *tmp_enabler_ref;
+
+       lttng_event_put(event->desc);
+       cds_list_del(&event->node);
        lttng_destroy_context(event->ctx);
        lttng_free_event_filter_runtime(event);
-       lttng_free_event_filter_bytecode(event);
+       /* Free event enabler refs */
+       cds_list_for_each_entry_safe(enabler_ref, tmp_enabler_ref,
+                       &event->enablers_ref_head, node)
+               free(enabler_ref);
        free(event);
 }
 
@@ -1275,13 +1228,13 @@ int _lttng_session_metadata_statedump(struct lttng_session *session)
                goto end;
 
 skip_session:
-       cds_list_for_each_entry(chan, &session->chan, list) {
+       cds_list_for_each_entry(chan, &session->chan_head, node) {
                ret = _lttng_channel_metadata_statedump(session, chan);
                if (ret)
                        goto end;
        }
 
-       cds_list_for_each_entry(event, &session->events, list) {
+       cds_list_for_each_entry(event, &session->events_head, node) {
                ret = _lttng_event_metadata_statedump(session, event->chan, event);
                if (ret)
                        goto end;
@@ -1295,221 +1248,171 @@ void lttng_ust_events_exit(void)
 {
        struct lttng_session *session, *tmpsession;
 
-       cds_list_for_each_entry_safe(session, tmpsession, &sessions, list)
+       cds_list_for_each_entry_safe(session, tmpsession, &sessions, node)
                lttng_session_destroy(session);
 }
 
-/* WILDCARDS */
-
-static
-int wildcard_same_loglevel(struct wildcard_entry *e,
-       enum lttng_ust_loglevel_type loglevel_type,
-       int loglevel)
+/*
+ * Enabler management.
+ */
+struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type,
+               struct lttng_ust_event *event_param,
+               struct lttng_channel *chan)
 {
-       if (e->loglevel_type == loglevel_type && e->loglevel == loglevel)
-               return 1;
-       else
-               return 0;
+       struct lttng_enabler *enabler;
+
+       enabler = zmalloc(sizeof(*enabler));
+       if (!enabler)
+               return NULL;
+       enabler->type = type;
+       CDS_INIT_LIST_HEAD(&enabler->filter_bytecode_head);
+       memcpy(&enabler->event_param, event_param,
+               sizeof(enabler->event_param));
+       enabler->chan = chan;
+       /* ctx left NULL */
+       enabler->enabled = 1;
+       cds_list_add(&enabler->node, &enabler->chan->session->enablers_head);
+       lttng_session_lazy_sync_enablers(enabler->chan->session);
+       return enabler;
 }
 
-#if 0
-static
-int wildcard_is_within(struct wildcard_entry *e,
-       enum lttng_ust_loglevel_type loglevel_type,
-       int loglevel)
+int lttng_enabler_enable(struct lttng_enabler *enabler)
 {
-       if (e->loglevel_type == LTTNG_UST_LOGLEVEL_ALL
-                       || e->loglevel == -1)
-               return 1;
-       switch (e->loglevel_type) {
-       case LTTNG_UST_LOGLEVEL_RANGE:
-               switch (loglevel_type) {
-               case LTTNG_UST_LOGLEVEL_RANGE:
-                       if (e->loglevel >= loglevel)
-                               return 1;
-                       else
-                               return 0;
-               case LTTNG_UST_LOGLEVEL_SINGLE:
-                       if (e->loglevel <= 0 && loglevel == 0)
-                               return 1;
-                       else
-                               return 0;
-               }
-       case LTTNG_UST_LOGLEVEL_SINGLE:
-               switch (loglevel_type) {
-               case LTTNG_UST_LOGLEVEL_RANGE:
-                       if (loglevel <= 0)
-                               return 1;
-                       else
-                               return 0;
-               case LTTNG_UST_LOGLEVEL_SINGLE:
-                       if (e->loglevel == loglevel)
-                               return 1;
-                       else
-                               return 0;
-               }
-       }
+       enabler->enabled = 1;
+       lttng_session_lazy_sync_enablers(enabler->chan->session);
+       return 0;
 }
-#endif
 
-/*
- * Add the wildcard to the wildcard list. Must be called with
- * ust lock held.
- */
-static
-struct session_wildcard *add_wildcard(struct lttng_channel *chan,
-       struct lttng_ust_event *event_param)
+int lttng_enabler_disable(struct lttng_enabler *enabler)
 {
-       struct wildcard_entry *e;
-       struct session_wildcard *sw;
-       size_t name_len = strlen(event_param->name) + 1;
-       int found = 0;
+       if (enabler->chan == enabler->chan->session->metadata)
+               return -EPERM;
+       enabler->enabled = 0;
+       lttng_session_lazy_sync_enablers(enabler->chan->session);
+       return 0;
+}
 
-       //FIXME: ensure that wildcard re-use pending events, or
-       //re-use actual events, applying its filter on top.
+int 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);
+       return 0;
+}
 
+int lttng_attach_context(struct lttng_ust_context *context_param,
+               struct lttng_ctx **ctx, struct lttng_session *session)
+{
        /*
-        * Try to find global wildcard entry. Given that this is shared
-        * across all sessions, we need to check for exact loglevel
-        * match, not just whether contained within the existing ones.
+        * We cannot attach a context after trace has been started for a
+        * session because the metadata does not allow expressing this
+        * information outside of the original channel scope.
         */
-       cds_list_for_each_entry(e, &wildcard_list, list) {
-               if (!strncmp(event_param->name, e->name,
-                               LTTNG_UST_SYM_NAME_LEN - 1)) {
-                       if (wildcard_same_loglevel(e,
-                                       event_param->loglevel_type,
-                                       event_param->loglevel)) {
-                               found = 1;
-                               break;
-                       }
-               }
-       }
-
-       if (!found) {
-               /*
-                * Create global wildcard entry if not found. Using
-                * zmalloc here to allocate a variable length element.
-                * Could cause some memory fragmentation if overused.
-                */
-               e = zmalloc(sizeof(struct wildcard_entry) + name_len);
-               if (!e)
-                       return ERR_PTR(-ENOMEM);
-               memcpy(&e->name[0], event_param->name, name_len);
-               e->loglevel_type = event_param->loglevel_type;
-               e->loglevel = event_param->loglevel;
-               CDS_INIT_LIST_HEAD(&e->filter_bytecode);
-               cds_list_add(&e->list, &wildcard_list);
-               CDS_INIT_LIST_HEAD(&e->session_list);
-       }
+       if (session->been_active)
+               return -EPERM;
 
-       /* session wildcard */
-       cds_list_for_each_entry(sw, &e->session_list, session_list) {
-               if (chan == sw->chan) {
-                       DBG("wildcard %s busy for this channel",
-                               event_param->name);
-                       return ERR_PTR(-EEXIST);        /* Already there */
-               }
+       switch (context_param->ctx) {
+       case LTTNG_UST_CONTEXT_PTHREAD_ID:
+               return lttng_add_pthread_id_to_ctx(ctx);
+       case LTTNG_UST_CONTEXT_VTID:
+               return lttng_add_vtid_to_ctx(ctx);
+       case LTTNG_UST_CONTEXT_VPID:
+               return lttng_add_vpid_to_ctx(ctx);
+       case LTTNG_UST_CONTEXT_PROCNAME:
+               return lttng_add_procname_to_ctx(ctx);
+       default:
+               return -EINVAL;
        }
-       sw = zmalloc(sizeof(struct session_wildcard));
-       if (!sw)
-               return ERR_PTR(-ENOMEM);
-       sw->chan = chan;
-       sw->enabled = 1;
-       memcpy(&sw->event_param, event_param, sizeof(sw->event_param));
-       sw->event_param.instrumentation = LTTNG_UST_TRACEPOINT;
-       sw->event_param.loglevel_type = event_param->loglevel_type;
-       sw->event_param.loglevel = event_param->loglevel;
-       CDS_INIT_LIST_HEAD(&sw->filter_bytecode);
-       CDS_INIT_LIST_HEAD(&sw->events);
-       cds_list_add(&sw->list, &chan->session->wildcards);
-       cds_list_add(&sw->session_list, &e->session_list);
-       sw->entry = e;
-       lttng_probes_create_wildcard_events(e, sw);
-       return sw;
 }
 
-/*
- * Remove the wildcard from the wildcard list. Must be called with
- * ust_lock held. Only called at session teardown.
- */
-static
-void _remove_wildcard(struct session_wildcard *wildcard)
+int lttng_enabler_attach_context(struct lttng_enabler *enabler,
+               struct lttng_ust_context *context_param)
 {
-       struct lttng_event *ev, *tmp;
+#if 0  // disabled for now.
+       struct lttng_session *session = enabler->chan->session;
+       int ret;
 
-       /*
-        * Just remove the events owned (for enable/disable) by this
-        * wildcard from the list. The session teardown will take care
-        * of freeing the event memory.
-        */
-       cds_list_for_each_entry_safe(ev, tmp, &wildcard->events,
-                       wildcard_list) {
-               cds_list_del(&ev->wildcard_list);
-       }
-       cds_list_del(&wildcard->session_list);
-       cds_list_del(&wildcard->list);
-       if (cds_list_empty(&wildcard->entry->session_list)) {
-               cds_list_del(&wildcard->entry->list);
-               free(wildcard->entry);
-       }
-       lttng_free_wildcard_filter_bytecode(wildcard);
-       free(wildcard);
+       ret = lttng_attach_context(context_param, &enabler->ctx,
+                       session);
+       if (ret)
+               return ret;
+       lttng_session_lazy_sync_enablers(enabler->chan->session);
+#endif
+       return -ENOSYS;
 }
 
-int lttng_wildcard_create(struct lttng_channel *chan,
-       struct lttng_ust_event *event_param,
-       struct session_wildcard **_sw)
+static
+void lttng_enabler_destroy(struct lttng_enabler *enabler)
 {
-       struct session_wildcard *sw;
+       struct lttng_ust_filter_bytecode_node *filter_node, *tmp_filter_node;
 
-       sw = add_wildcard(chan, event_param);
-       if (!sw || IS_ERR(sw)) {
-               return PTR_ERR(sw);
+       /* Destroy filter bytecode */
+       cds_list_for_each_entry_safe(filter_node, tmp_filter_node,
+                       &enabler->filter_bytecode_head, node) {
+               free(filter_node);
        }
-       *_sw = sw;
-       return 0;
+
+       /* Destroy contexts */
+       lttng_destroy_context(enabler->ctx);
+
+       cds_list_del(&enabler->node);
+       free(enabler);
 }
 
+/*
+ * lttng_session_sync_enablers should be called just before starting a
+ * session.
+ */
 static
-void _lttng_wildcard_destroy(struct session_wildcard *sw)
+void lttng_session_sync_enablers(struct lttng_session *session)
 {
-       _remove_wildcard(sw);
-}
+       struct lttng_enabler *enabler;
+       struct lttng_event *event;
 
-int lttng_wildcard_enable(struct session_wildcard *wildcard)
-{
-       struct lttng_event *ev;
-       int ret;
+       cds_list_for_each_entry(enabler, &session->enablers_head, node)
+               lttng_enabler_ref_events(enabler);
+       /*
+        * For each event, if at least one of its enablers is enabled,
+        * we enable the event, else we disable it.
+        */
+       cds_list_for_each_entry(event, &session->events_head, node) {
+               struct lttng_enabler_ref *enabler_ref;
+               struct lttng_bytecode_runtime *runtime;
+               int enabled = 0;
+
+               /* Enable events */
+               cds_list_for_each_entry(enabler_ref,
+                               &event->enablers_ref_head, node) {
+                       if (enabler_ref->ref->enabled) {
+                               enabled = 1;
+                               break;
+                       }
+               }
+               event->enabled = enabled;
 
-       if (wildcard->enabled)
-               return -EEXIST;
-       cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
-               ret = lttng_event_enable(ev);
-               if (ret) {
-                       DBG("Error: enable error.\n");
-                       return ret;
+               /* Enable filters */
+               cds_list_for_each_entry(runtime,
+                               &event->bytecode_runtime_head, node) {
+                       lttng_filter_sync_state(runtime);
                }
+
        }
-       wildcard->enabled = 1;
-       return 0;
 }
 
-int lttng_wildcard_disable(struct session_wildcard *wildcard)
+/*
+ * Apply enablers to session events, adding events to session if need
+ * be. It is required after each modification applied to an active
+ * session, and right before session "start".
+ * "lazy" sync means we only sync if required.
+ */
+static
+void lttng_session_lazy_sync_enablers(struct lttng_session *session)
 {
-       struct lttng_event *ev;
-       int ret;
-
-       if (!wildcard->enabled)
-               return -EEXIST;
-       cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
-               ret = lttng_event_disable(ev);
-               if (ret) {
-                       DBG("Error: disable error.\n");
-                       return ret;
-               }
-       }
-       wildcard->enabled = 0;
-       return 0;
+       /* We can skip if session is not active */
+       if (!session->active)
+               return;
+       lttng_session_sync_enablers(session);
 }
 
 /*
index c298addf904ef9f856f728ab2d4a81208943591c..4714dad2ad50c1d7d09e0cc3450ee7366c06bbc7 100644 (file)
@@ -220,7 +220,8 @@ int bytecode_is_linked(struct lttng_ust_filter_bytecode_node *filter_bytecode,
 {
        struct lttng_bytecode_runtime *bc_runtime;
 
-       cds_list_for_each_entry(bc_runtime, &event->bytecode_runtime, node) {
+       cds_list_for_each_entry(bc_runtime,
+                       &event->bytecode_runtime_head, node) {
                if (bc_runtime->bc == filter_bytecode)
                        return 1;
        }
@@ -233,7 +234,8 @@ int bytecode_is_linked(struct lttng_ust_filter_bytecode_node *filter_bytecode,
  */
 static
 int _lttng_filter_event_link_bytecode(struct lttng_event *event,
-               struct lttng_ust_filter_bytecode_node *filter_bytecode)
+               struct lttng_ust_filter_bytecode_node *filter_bytecode,
+               struct cds_list_head *insert_loc)
 {
        int ret, offset, next_offset;
        struct bytecode_runtime *runtime = NULL;
@@ -241,9 +243,6 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event,
 
        if (!filter_bytecode)
                return 0;
-       /* Event is not connected to any description */
-       if (!event->desc)
-               return 0;
        /* Bytecode already linked */
        if (bytecode_is_linked(filter_bytecode, event))
                return 0;
@@ -290,104 +289,95 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event,
                goto link_error;
        }
        runtime->p.filter = lttng_filter_interpret_bytecode;
-       /* TODO: add with prio */
-       cds_list_add_rcu(&runtime->p.node, &event->bytecode_runtime);
+       cds_list_add_rcu(&runtime->p.node, insert_loc);
        dbg_printf("Linking successful.\n");
        return 0;
 
 link_error:
        runtime->p.filter = lttng_filter_false;
-       /* TODO: add with prio */
-       cds_list_add_rcu(&runtime->p.node, &event->bytecode_runtime);
+       cds_list_add_rcu(&runtime->p.node, insert_loc);
        dbg_printf("Linking failed.\n");
        return ret;
 }
 
-void lttng_filter_event_link_bytecode(struct lttng_event *event)
+void lttng_filter_sync_state(struct lttng_bytecode_runtime *runtime)
 {
-       struct lttng_ust_filter_bytecode_node *filter_bytecode;
-       int ret;
-
-       cds_list_for_each_entry(filter_bytecode, &event->filter_bytecode, node) {
-               dbg_printf("linking bytecode\n");
-               ret = _lttng_filter_event_link_bytecode(event, filter_bytecode);
-               if (ret) {
-                       dbg_printf("[lttng filter] warning: cannot link event bytecode\n");
-               }
-       }
-}
+       struct lttng_ust_filter_bytecode_node *bc = runtime->bc;
 
-void lttng_filter_event_link_wildcard_bytecode(struct lttng_event *event,
-               struct session_wildcard *wildcard)
-{
-       struct lttng_ust_filter_bytecode_node *filter_bytecode;
-       int ret;
-
-       cds_list_for_each_entry(filter_bytecode, &wildcard->filter_bytecode, node) {
-               dbg_printf("linking bytecode\n");
-               ret = _lttng_filter_event_link_bytecode(event, filter_bytecode);
-               if (ret) {
-                       dbg_printf("[lttng filter] error linking wildcard bytecode\n");
-               }
-       }
+       if (bc->enabler->enabled)
+               runtime->filter = lttng_filter_interpret_bytecode;
+       else
+               runtime->filter = lttng_filter_false;
 }
 
 /*
- * Link bytecode to all events for a wildcard.
- * The "is_linked" check in _lttng_filter_event_link_bytecode() ensures
- * that we don't link the same bytecode to an event more than once.
+ * Link bytecode for all enablers referenced by an event.
  */
-void lttng_filter_wildcard_link_bytecode(struct session_wildcard *wildcard)
+void lttng_enabler_event_link_bytecode(struct lttng_event *event,
+               struct lttng_enabler *enabler)
 {
-       struct lttng_event *event;
-
-       if (cds_list_empty(&wildcard->filter_bytecode))
-               return;
-       cds_list_for_each_entry(event, &wildcard->events, wildcard_list) {
+       struct lttng_ust_filter_bytecode_node *bc;
+       struct lttng_bytecode_runtime *runtime;
+
+       /* Can only be called for events with desc attached */
+       assert(event->desc);
+
+       /* Link each bytecode. */
+       cds_list_for_each_entry(bc, &enabler->filter_bytecode_head, node) {
+               int found = 0, ret;
+               struct cds_list_head *insert_loc;
+
+               cds_list_for_each_entry(runtime,
+                               &event->bytecode_runtime_head, node) {
+                       if (runtime->bc == bc) {
+                               found = 1;
+                               break;
+                       }
+               }
+               /* Skip bytecode already linked */
+               if (found)
+                       continue;
+
+               /*
+                * Insert at specified priority (seqnum) in increasing
+                * order.
+                */
+               cds_list_for_each_entry_reverse(runtime,
+                               &event->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;
+       add_within:
                dbg_printf("linking bytecode\n");
-               lttng_filter_event_link_wildcard_bytecode(event, wildcard);
+               ret = _lttng_filter_event_link_bytecode(event, bc,
+                               insert_loc);
+               if (ret) {
+                       dbg_printf("[lttng filter] warning: cannot link event bytecode\n");
+               }
        }
-       return;
-}
-
-/*
- * Need to attach filter to an event before starting tracing for the
- * session. We own the filter_bytecode if we return success.
- */
-int lttng_filter_event_attach_bytecode(struct lttng_event *event,
-               struct lttng_ust_filter_bytecode_node *filter_bytecode)
-{
-       cds_list_add(&filter_bytecode->node, &event->filter_bytecode);
-       return 0;
 }
 
 /*
- * Need to attach filter to a wildcard before starting tracing for the
- * session. We own the filter_bytecode if we return success.
+ * We own the filter_bytecode if we return success.
  */
-int lttng_filter_wildcard_attach_bytecode(struct session_wildcard *wildcard,
+int lttng_filter_enabler_attach_bytecode(struct lttng_enabler *enabler,
                struct lttng_ust_filter_bytecode_node *filter_bytecode)
 {
-       cds_list_add(&filter_bytecode->node, &wildcard->filter_bytecode);
+       cds_list_add(&filter_bytecode->node, &enabler->filter_bytecode_head);
        return 0;
 }
 
-void lttng_free_event_filter_bytecode(struct lttng_event *event)
-{
-       struct lttng_ust_filter_bytecode_node *filter_bytecode, *tmp;
-
-       cds_list_for_each_entry_safe(filter_bytecode, tmp,
-                       &event->filter_bytecode, node) {
-               free(filter_bytecode);
-       }
-}
-
-void lttng_free_wildcard_filter_bytecode(struct session_wildcard *wildcard)
+void lttng_free_enabler_filter_bytecode(struct lttng_enabler *enabler)
 {
        struct lttng_ust_filter_bytecode_node *filter_bytecode, *tmp;
 
        cds_list_for_each_entry_safe(filter_bytecode, tmp,
-                       &wildcard->filter_bytecode, node) {
+                       &enabler->filter_bytecode_head, node) {
                free(filter_bytecode);
        }
 }
@@ -397,7 +387,7 @@ void lttng_free_event_filter_runtime(struct lttng_event *event)
        struct bytecode_runtime *runtime, *tmp;
 
        cds_list_for_each_entry_safe(runtime, tmp,
-                       &event->bytecode_runtime, p.node) {
+                       &event->bytecode_runtime_head, p.node) {
                free(runtime);
        }
 }
index e473b9890c9395f73121736a6dc6333399e373a1..9d7d83ceab716c62687bef3801ab0b59c6a56a0d 100644 (file)
 /*
  * probe list is protected by ust_lock()/ust_unlock().
  */
-static CDS_LIST_HEAD(probe_list);
+CDS_LIST_HEAD(probe_list);
+
+struct cds_list_head *lttng_get_probe_list_head(void)
+{
+       return &probe_list;
+}
 
 static
 const struct lttng_probe_desc *find_provider(const char *provider)
@@ -116,7 +121,7 @@ desc_added:
                ed = desc->event_desc[i];
                DBG("Registered event probe \"%s\" with signature \"%s\"",
                        ed->name, ed->signature);
-               ret = pending_probe_fix_events(ed);
+               ret = lttng_fix_pending_event_desc(ed);
                assert(!ret);
        }
 end:
@@ -366,58 +371,3 @@ struct lttng_ust_field_iter *
                                struct tp_field_list_entry, head);
        return &entry->field;
 }
-
-/*
- * marshall all probes/all events and create those that fit the
- * wildcard. Add them to the events list as created.
- */
-void lttng_probes_create_wildcard_events(struct wildcard_entry *entry,
-                               struct session_wildcard *wildcard)
-{
-       struct lttng_probe_desc *probe_desc;
-       struct lttng_ust_event event_param;
-       int i;
-
-       cds_list_for_each_entry(probe_desc, &probe_list, head) {
-               for (i = 0; i < probe_desc->nr_events; i++) {
-                       const struct lttng_event_desc *event_desc;
-                       int match = 0;
-
-                       event_desc = probe_desc->event_desc[i];
-                       /* compare excluding final '*' */
-                       assert(strlen(entry->name) > 0);
-                       if (strcmp(event_desc->name, "lttng_ust:metadata")
-                                       && (strlen(entry->name) == 1
-                                               || !strncmp(event_desc->name, entry->name,
-                                                       strlen(entry->name) - 1))) {
-                               if (lttng_loglevel_match(event_desc,
-                                       entry->loglevel_type,
-                                               entry->loglevel)) {
-                                       match = 1;
-                               }
-                       }
-                       if (match) {
-                               struct lttng_event *ev;
-                               int ret;
-
-                               memcpy(&event_param, &wildcard->event_param,
-                                               sizeof(event_param));
-                               strncpy(event_param.name,
-                                       event_desc->name,
-                                       sizeof(event_param.name));
-                               event_param.name[sizeof(event_param.name) - 1] = '\0';
-                               /* create event */
-                               ret = lttng_event_create(wildcard->chan,
-                                       &event_param, &ev);
-                               if (ret) {
-                                       DBG("Error creating event");
-                                       continue;
-                               }
-                               cds_list_add(&ev->wildcard_list,
-                                       &wildcard->events);
-                       }
-               }
-       }
-       lttng_filter_wildcard_link_bytecode(wildcard);
-}
-
index 9b0143cd7bc70b29fd3b1525ad670ef61fbc0fc3..529ff4385b5803c93b434c73b4da7e6c7bd0c75d 100644 (file)
@@ -239,8 +239,7 @@ static const struct lttng_ust_objd_ops lttng_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_metadata_ops;
-static const struct lttng_ust_objd_ops lttng_event_ops;
-static const struct lttng_ust_objd_ops lttng_wildcard_ops;
+static const struct lttng_ust_objd_ops lttng_enabler_ops;
 static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops;
 static const struct lttng_ust_objd_ops lttng_tracepoint_list_ops;
 static const struct lttng_ust_objd_ops lttng_tracepoint_field_list_ops;
@@ -296,21 +295,7 @@ long lttng_abi_add_context(int objd,
        struct lttng_ust_context *context_param,
        struct lttng_ctx **ctx, struct lttng_session *session)
 {
-       if (session->been_active)
-               return -EPERM;
-
-       switch (context_param->ctx) {
-       case LTTNG_UST_CONTEXT_PTHREAD_ID:
-               return lttng_add_pthread_id_to_ctx(ctx);
-       case LTTNG_UST_CONTEXT_VTID:
-               return lttng_add_vtid_to_ctx(ctx);
-       case LTTNG_UST_CONTEXT_VPID:
-               return lttng_add_vpid_to_ctx(ctx);
-       case LTTNG_UST_CONTEXT_PROCNAME:
-               return lttng_add_procname_to_ctx(ctx);
-       default:
-               return -EINVAL;
-       }
+       return lttng_attach_context(context_param, ctx, session);
 }
 
 /**
@@ -370,22 +355,22 @@ static const struct lttng_ust_objd_ops lttng_ops = {
 static
 void lttng_metadata_create_events(int channel_objd)
 {
-       struct lttng_channel *channel = objd_private(channel_objd);
+       struct lttng_channel *chan = objd_private(channel_objd);
+       struct lttng_enabler *enabler;
        static struct lttng_ust_event metadata_params = {
                .instrumentation = LTTNG_UST_TRACEPOINT,
                .name = "lttng_ust:metadata",
                .loglevel_type = LTTNG_UST_LOGLEVEL_ALL,
                .loglevel = TRACE_DEFAULT,
        };
-       struct lttng_event *event;
-       int ret;
 
        /*
         * We tolerate no failure path after event creation. It will stay
         * invariant for the rest of the session.
         */
-       ret = lttng_event_create(channel, &metadata_params, &event);
-       if (ret < 0) {
+       enabler = lttng_enabler_create(LTTNG_ENABLER_EVENT,
+                               &metadata_params, chan);
+       if (!enabler) {
                goto create_error;
        }
        return;
@@ -761,16 +746,17 @@ alloc_error:
 }
 
 static
-int lttng_abi_create_event(int channel_objd,
+int lttng_abi_create_enabler(int channel_objd,
                           struct lttng_ust_event *event_param,
-                          void *owner)
+                          void *owner,
+                          enum lttng_enabler_type type)
 {
        struct lttng_channel *channel = objd_private(channel_objd);
-       struct lttng_event *event;
+       struct lttng_enabler *enabler;
        int event_objd, ret;
 
        event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
-       event_objd = objd_alloc(NULL, &lttng_event_ops, owner);
+       event_objd = objd_alloc(NULL, &lttng_enabler_ops, owner);
        if (event_objd < 0) {
                ret = event_objd;
                goto objd_error;
@@ -779,11 +765,12 @@ int lttng_abi_create_event(int channel_objd,
         * We tolerate no failure path after event creation. It will stay
         * invariant for the rest of the session.
         */
-       ret = lttng_event_create(channel, event_param, &event);
-       if (ret < 0) {
+       enabler = lttng_enabler_create(type, event_param, channel);
+       if (!enabler) {
+               ret = -ENOMEM;
                goto event_error;
        }
-       objd_set_private(event_objd, event);
+       objd_set_private(event_objd, enabler);
        /* The event holds a reference on the channel */
        objd_ref(channel_objd);
        return event_objd;
@@ -799,45 +786,6 @@ objd_error:
        return ret;
 }
 
-static
-int lttng_abi_create_wildcard(int channel_objd,
-                             struct lttng_ust_event *event_param,
-                             void *owner)
-{
-       struct lttng_channel *channel = objd_private(channel_objd);
-       struct session_wildcard *wildcard;
-       int wildcard_objd, ret;
-
-       event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
-       wildcard_objd = objd_alloc(NULL, &lttng_wildcard_ops, owner);
-       if (wildcard_objd < 0) {
-               ret = wildcard_objd;
-               goto objd_error;
-       }
-       /*
-        * We tolerate no failure path after wildcard creation. It will
-        * stay invariant for the rest of the session.
-        */
-       ret = lttng_wildcard_create(channel, event_param, &wildcard);
-       if (ret < 0) {
-               goto wildcard_error;
-       }
-       objd_set_private(wildcard_objd, wildcard);
-       /* The wildcard holds a reference on the channel */
-       objd_ref(channel_objd);
-       return wildcard_objd;
-
-wildcard_error:
-       {
-               int err;
-
-               err = lttng_ust_objd_unref(wildcard_objd);
-               assert(!err);
-       }
-objd_error:
-       return ret;
-}
-
 /**
  *     lttng_channel_cmd - lttng control through object descriptors
  *
@@ -883,11 +831,11 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg,
                        (struct lttng_ust_event *) arg;
                if (event_param->name[strlen(event_param->name) - 1] == '*') {
                        /* If ends with wildcard, create wildcard. */
-                       return lttng_abi_create_wildcard(objd, event_param,
-                                                       owner);
+                       return lttng_abi_create_enabler(objd, event_param,
+                                       owner, LTTNG_ENABLER_WILDCARD);
                } else {
-                       return lttng_abi_create_event(objd, event_param,
-                                                       owner);
+                       return lttng_abi_create_enabler(objd, event_param,
+                                       owner, LTTNG_ENABLER_EVENT);
                }
        }
        case LTTNG_UST_CONTEXT:
@@ -942,36 +890,6 @@ long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg,
        }
 }
 
-#if 0
-/**
- *     lttng_channel_poll - lttng stream addition/removal monitoring
- *
- *     @file: the file
- *     @wait: poll table
- */
-unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
-{
-       struct lttng_channel *channel = file->private_data;
-       unsigned int mask = 0;
-
-       if (file->f_mode & FMODE_READ) {
-               poll_wait_set_exclusive(wait);
-               poll_wait(file, channel->ops->get_hp_wait_queue(channel->chan),
-                         wait);
-
-               if (channel->ops->is_disabled(channel->chan))
-                       return POLLERR;
-               if (channel->ops->is_finalized(channel->chan))
-                       return POLLHUP;
-               if (channel->ops->buffer_has_read_closed_stream(channel->chan))
-                       return POLLIN | POLLRDNORM;
-               return 0;
-       }
-       return mask;
-
-}
-#endif //0
-
 static
 int lttng_channel_release(int objd)
 {
@@ -984,7 +902,6 @@ int lttng_channel_release(int objd)
 
 static const struct lttng_ust_objd_ops lttng_channel_ops = {
        .release = lttng_channel_release,
-       //.poll = lttng_channel_poll,
        .cmd = lttng_channel_cmd,
 };
 
@@ -1053,72 +970,7 @@ static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops = {
 };
 
 /**
- *     lttng_event_cmd - lttng control through object descriptors
- *
- *     @objd: the object descriptor
- *     @cmd: the command
- *     @arg: command arg
- *     @uargs: UST arguments (internal)
- *     @owner: objd owner
- *
- *     This object descriptor implements lttng commands:
- *     LTTNG_UST_CONTEXT
- *             Prepend a context field to each record of this event
- *     LTTNG_UST_ENABLE
- *             Enable recording for this event (weak enable)
- *     LTTNG_UST_DISABLE
- *             Disable recording for this event (strong disable)
- *     LTTNG_UST_FILTER
- *             Attach a filter to an event.
- */
-static
-long lttng_event_cmd(int objd, unsigned int cmd, unsigned long arg,
-       union ust_args *uargs, void *owner)
-{
-       struct lttng_event *event = objd_private(objd);
-
-       switch (cmd) {
-       case LTTNG_UST_CONTEXT:
-               return lttng_abi_add_context(objd,
-                               (struct lttng_ust_context *) arg,
-                               &event->ctx, event->chan->session);
-       case LTTNG_UST_ENABLE:
-               return lttng_event_enable(event);
-       case LTTNG_UST_DISABLE:
-               return lttng_event_disable(event);
-       case LTTNG_UST_FILTER:
-       {
-               int ret;
-               ret = lttng_filter_event_attach_bytecode(event,
-                               (struct lttng_ust_filter_bytecode_node *) arg);
-               if (ret)
-                       return ret;
-               lttng_filter_event_link_bytecode(event);
-               return 0;
-       }
-       default:
-               return -EINVAL;
-       }
-}
-
-static
-int lttng_event_release(int objd)
-{
-       struct lttng_event *event = objd_private(objd);
-
-       if (event)
-               return lttng_ust_objd_unref(event->chan->objd);
-       return 0;
-}
-
-/* TODO: filter control ioctl */
-static const struct lttng_ust_objd_ops lttng_event_ops = {
-       .release = lttng_event_release,
-       .cmd = lttng_event_cmd,
-};
-
-/**
- *     lttng_wildcard_cmd - lttng control through object descriptors
+ *     lttng_enabler_cmd - lttng control through object descriptors
  *
  *     @objd: the object descriptor
  *     @cmd: the command
@@ -1129,41 +981,36 @@ static const struct lttng_ust_objd_ops lttng_event_ops = {
  *     This object descriptor implements lttng commands:
  *     LTTNG_UST_CONTEXT
  *             Prepend a context field to each record of events of this
- *             wildcard.
+ *             enabler.
  *     LTTNG_UST_ENABLE
- *             Enable recording for these wildcard events (weak enable)
+ *             Enable recording for this enabler
  *     LTTNG_UST_DISABLE
- *             Disable recording for these wildcard events (strong disable)
+ *             Disable recording for this enabler
  *     LTTNG_UST_FILTER
- *             Attach a filter to a wildcard.
+ *             Attach a filter to an enabler.
  */
 static
-long lttng_wildcard_cmd(int objd, unsigned int cmd, unsigned long arg,
+long lttng_enabler_cmd(int objd, unsigned int cmd, unsigned long arg,
        union ust_args *uargs, void *owner)
 {
-       struct session_wildcard *wildcard = objd_private(objd);
+       struct lttng_enabler *enabler = objd_private(objd);
 
        switch (cmd) {
        case LTTNG_UST_CONTEXT:
-               return -ENOSYS; /* not implemented yet */
-#if 0
-               return lttng_abi_add_context(objd,
-                               (struct lttng_ust_context *) arg,
-                               &wildcard->ctx, wildcard->chan->session);
-#endif
+               return lttng_enabler_attach_context(enabler,
+                               (struct lttng_ust_context *) arg);
        case LTTNG_UST_ENABLE:
-               return lttng_wildcard_enable(wildcard);
+               return lttng_enabler_enable(enabler);
        case LTTNG_UST_DISABLE:
-               return lttng_wildcard_disable(wildcard);
+               return lttng_enabler_disable(enabler);
        case LTTNG_UST_FILTER:
        {
                int ret;
 
-               ret = lttng_filter_wildcard_attach_bytecode(wildcard,
+               ret = lttng_enabler_attach_bytecode(enabler,
                                (struct lttng_ust_filter_bytecode_node *) arg);
                if (ret)
                        return ret;
-               lttng_filter_wildcard_link_bytecode(wildcard);
                return 0;
        }
        default:
@@ -1172,19 +1019,18 @@ long lttng_wildcard_cmd(int objd, unsigned int cmd, unsigned long arg,
 }
 
 static
-int lttng_wildcard_release(int objd)
+int lttng_enabler_release(int objd)
 {
-       struct session_wildcard *wildcard = objd_private(objd);
+       struct lttng_enabler *enabler = objd_private(objd);
 
-       if (wildcard)
-               return lttng_ust_objd_unref(wildcard->chan->objd);
+       if (enabler)
+               return lttng_ust_objd_unref(enabler->chan->objd);
        return 0;
 }
 
-/* TODO: filter control ioctl */
-static const struct lttng_ust_objd_ops lttng_wildcard_ops = {
-       .release = lttng_wildcard_release,
-       .cmd = lttng_wildcard_cmd,
+static const struct lttng_ust_objd_ops lttng_enabler_ops = {
+       .release = lttng_enabler_release,
+       .cmd = lttng_enabler_cmd,
 };
 
 void lttng_ust_abi_exit(void)
This page took 0.051155 seconds and 4 git commands to generate.