From: Mathieu Desnoyers Date: Fri, 16 Nov 2012 15:19:32 +0000 (-0500) Subject: Implement support for overlapping wildcard/events X-Git-Tag: v2.1.0-rc2~9 X-Git-Url: http://git.liburcu.org/?a=commitdiff_plain;h=e58095efc3a51a505fc533e3e56b9b5ed8743a8b;p=lttng-ust.git Implement support for overlapping wildcard/events Reviewed-by: David Goulet Reviewed-by: Christian Babeux Signed-off-by: Mathieu Desnoyers --- diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 4a7d67f2..5010a66e 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -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 */ diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index 0be3395b..a9de4a7a 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -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; \ diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 24b5c666..95082ced 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -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); } /* diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index c298addf..4714dad2 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -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); } } diff --git a/liblttng-ust/lttng-probes.c b/liblttng-ust/lttng-probes.c index e473b989..9d7d83ce 100644 --- a/liblttng-ust/lttng-probes.c +++ b/liblttng-ust/lttng-probes.c @@ -38,7 +38,12 @@ /* * 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); -} - diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 9b0143cd..529ff438 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -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, <tng_event_ops, owner); + event_objd = objd_alloc(NULL, <tng_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, <tng_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)