X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-events.c;h=7afee7fc4043ac58a1be6a46df6852a93e10882c;hb=8306baea3da8b1f429e14218b1ef7413ee56ed19;hp=78a4f7603de5003fc6af44f47feafdc9d887b669;hpb=7e2e405c27a467896a9310d492640a624fdd8c4e;p=lttng-ust.git diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 78a4f760..7afee7fc 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -21,6 +21,7 @@ */ #define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include "clock.h" @@ -45,39 +47,37 @@ #include #include -#include +#include #include +#include +#include #include "error.h" #include "compat.h" #include "lttng-ust-uuid.h" #include "tracepoint-internal.h" +#include "string-utils.h" #include "lttng-tracer.h" #include "lttng-tracer-core.h" +#include "lttng-ust-statedump.h" #include "wait.h" #include "../libringbuffer/shm.h" #include "jhash.h" /* - * The sessions mutex is the centralized mutex across UST tracing - * control and probe registration. All operations within this file are - * called by the communication thread, under ust_lock protection. + * All operations within this file are called by the communication + * thread, under ust_lock protection. */ -static pthread_mutex_t sessions_mutex = PTHREAD_MUTEX_INITIALIZER; -void ust_lock(void) -{ - pthread_mutex_lock(&sessions_mutex); -} +static CDS_LIST_HEAD(sessions); -void ust_unlock(void) +struct cds_list_head *_lttng_get_sessions(void) { - pthread_mutex_unlock(&sessions_mutex); + return &sessions; } -static CDS_LIST_HEAD(sessions); - static void _lttng_event_destroy(struct lttng_event *event); +static void _lttng_enum_destroy(struct lttng_enum *_enum); static void lttng_session_lazy_sync_enablers(struct lttng_session *session); @@ -106,24 +106,27 @@ int lttng_loglevel_match(int loglevel, enum lttng_ust_loglevel_type req_type, int req_loglevel) { - if (req_type == LTTNG_UST_LOGLEVEL_ALL) - return 1; if (!has_loglevel) loglevel = TRACE_DEFAULT; switch (req_type) { case LTTNG_UST_LOGLEVEL_RANGE: - if (loglevel <= req_loglevel || req_loglevel == -1) + if (loglevel <= req_loglevel + || (req_loglevel == -1 && loglevel <= TRACE_DEBUG)) return 1; else return 0; case LTTNG_UST_LOGLEVEL_SINGLE: - if (loglevel == req_loglevel || req_loglevel == -1) + if (loglevel == req_loglevel + || (req_loglevel == -1 && loglevel <= TRACE_DEBUG)) return 1; else return 0; case LTTNG_UST_LOGLEVEL_ALL: default: - return 1; + if (loglevel <= TRACE_DEBUG) + return 1; + else + return 0; } } @@ -140,11 +143,18 @@ struct lttng_session *lttng_session_create(void) session = zmalloc(sizeof(struct lttng_session)); if (!session) return NULL; + if (lttng_session_context_init(&session->ctx)) { + free(session); + return NULL; + } CDS_INIT_LIST_HEAD(&session->chan_head); CDS_INIT_LIST_HEAD(&session->events_head); + CDS_INIT_LIST_HEAD(&session->enums_head); CDS_INIT_LIST_HEAD(&session->enablers_head); for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++) CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]); + for (i = 0; i < LTTNG_UST_ENUM_HT_SIZE; i++) + CDS_INIT_HLIST_HEAD(&session->enums_ht.table[i]); cds_list_add(&session->node, &sessions); return session; } @@ -177,7 +187,7 @@ void register_event(struct lttng_event *event) assert(event->registered == 0); desc = event->desc; - ret = __tracepoint_probe_register(desc->name, + ret = __tracepoint_probe_register_queue_release(desc->name, desc->probe_callback, event, desc->signature); WARN_ON_ONCE(ret); @@ -193,7 +203,7 @@ void unregister_event(struct lttng_event *event) assert(event->registered == 1); desc = event->desc; - ret = __tracepoint_probe_unregister(desc->name, + ret = __tracepoint_probe_unregister_queue_release(desc->name, desc->probe_callback, event); WARN_ON_ONCE(ret); @@ -215,6 +225,7 @@ void lttng_session_destroy(struct lttng_session *session) { struct lttng_channel *chan, *tmpchan; struct lttng_event *event, *tmpevent; + struct lttng_enum *_enum, *tmp_enum; struct lttng_enabler *enabler, *tmpenabler; CMM_ACCESS_ONCE(session->active) = 0; @@ -222,18 +233,170 @@ void lttng_session_destroy(struct lttng_session *session) _lttng_event_unregister(event); } synchronize_trace(); /* Wait for in-flight events to complete */ + __tracepoint_probe_prune_release_queue(); 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(_enum, tmp_enum, + &session->enums_head, node) + _lttng_enum_destroy(_enum); cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node) _lttng_channel_unmap(chan); cds_list_del(&session->node); + lttng_destroy_context(session->ctx); free(session); } +static +int lttng_enum_create(const struct lttng_enum_desc *desc, + struct lttng_session *session) +{ + const char *enum_name = desc->name; + struct lttng_enum *_enum; + struct cds_hlist_head *head; + int ret = 0; + size_t name_len = strlen(enum_name); + uint32_t hash; + int notify_socket; + + /* Check if this enum is already registered for this session. */ + hash = jhash(enum_name, name_len, 0); + head = &session->enums_ht.table[hash & (LTTNG_UST_ENUM_HT_SIZE - 1)]; + + _enum = lttng_ust_enum_get_from_desc(session, desc); + if (_enum) { + ret = -EEXIST; + goto exist; + } + + notify_socket = lttng_get_notify_socket(session->owner); + if (notify_socket < 0) { + ret = notify_socket; + goto socket_error; + } + + _enum = zmalloc(sizeof(*_enum)); + if (!_enum) { + ret = -ENOMEM; + goto cache_error; + } + _enum->session = session; + _enum->desc = desc; + + ret = ustcomm_register_enum(notify_socket, + session->objd, + enum_name, + desc->nr_entries, + desc->entries, + &_enum->id); + if (ret < 0) { + DBG("Error (%d) registering enumeration to sessiond", ret); + goto sessiond_register_error; + } + cds_list_add(&_enum->node, &session->enums_head); + cds_hlist_add_head(&_enum->hlist, head); + return 0; + +sessiond_register_error: + free(_enum); +cache_error: +socket_error: +exist: + return ret; +} + +static +int lttng_create_enum_check(const struct lttng_type *type, + struct lttng_session *session) +{ + switch (type->atype) { + case atype_enum: + { + const struct lttng_enum_desc *enum_desc; + int ret; + + enum_desc = type->u.basic.enumeration.desc; + ret = lttng_enum_create(enum_desc, session); + if (ret && ret != -EEXIST) { + DBG("Unable to create enum error: (%d)", ret); + return ret; + } + break; + } + case atype_dynamic: + { + const struct lttng_event_field *tag_field_generic; + const struct lttng_enum_desc *enum_desc; + int ret; + + tag_field_generic = lttng_ust_dynamic_type_tag_field(); + enum_desc = tag_field_generic->type.u.basic.enumeration.desc; + ret = lttng_enum_create(enum_desc, session); + if (ret && ret != -EEXIST) { + DBG("Unable to create enum error: (%d)", ret); + return ret; + } + break; + } + default: + /* TODO: nested types when they become supported. */ + break; + } + return 0; +} + +static +int lttng_create_all_event_enums(size_t nr_fields, + const struct lttng_event_field *event_fields, + struct lttng_session *session) +{ + size_t i; + int ret; + + /* For each field, ensure enum is part of the session. */ + for (i = 0; i < nr_fields; i++) { + const struct lttng_type *type = &event_fields[i].type; + + ret = lttng_create_enum_check(type, session); + if (ret) + return ret; + } + return 0; +} + +static +int lttng_create_all_ctx_enums(size_t nr_fields, + const struct lttng_ctx_field *ctx_fields, + struct lttng_session *session) +{ + size_t i; + int ret; + + /* For each field, ensure enum is part of the session. */ + for (i = 0; i < nr_fields; i++) { + const struct lttng_type *type = &ctx_fields[i].event_field.type; + + ret = lttng_create_enum_check(type, session); + if (ret) + return ret; + } + return 0; +} + +/* + * Ensure that a state-dump will be performed for this session at the end + * of the current handle_message(). + */ +int lttng_session_statedump(struct lttng_session *session) +{ + session->statedump_pending = 1; + lttng_ust_sockinfo_session_enabled(session->owner); + return 0; +} + int lttng_session_enable(struct lttng_session *session) { int ret = 0; @@ -251,6 +414,7 @@ int lttng_session_enable(struct lttng_session *session) /* Set transient enabler state to "enabled" */ session->tstate = 1; + /* We need to sync enablers with session before activation. */ lttng_session_sync_enablers(session); @@ -260,8 +424,9 @@ int lttng_session_enable(struct lttng_session *session) */ cds_list_for_each_entry(chan, &session->chan_head, node) { const struct lttng_ctx *ctx; - const struct lttng_event_field *fields = NULL; + const struct lttng_ctx_field *fields = NULL; size_t nr_fields = 0; + uint32_t chan_id; /* don't change it if session stop/restart */ if (chan->header_type) @@ -269,24 +434,40 @@ int lttng_session_enable(struct lttng_session *session) ctx = chan->ctx; if (ctx) { nr_fields = ctx->nr_fields; - fields = &ctx->fields->event_field; + fields = ctx->fields; + ret = lttng_create_all_ctx_enums(nr_fields, fields, + session); + if (ret < 0) { + DBG("Error (%d) adding enum to session", ret); + return ret; + } } ret = ustcomm_register_channel(notify_socket, + session, session->objd, chan->objd, nr_fields, fields, - &chan->id, + &chan_id, &chan->header_type); if (ret) { DBG("Error (%d) registering channel to sessiond", ret); return ret; } + if (chan_id != chan->id) { + DBG("Error: channel registration id (%u) does not match id assigned at creation (%u)", + chan_id, chan->id); + return -EINVAL; + } } /* Set atomically the state to "active" */ CMM_ACCESS_ONCE(session->active) = 1; CMM_ACCESS_ONCE(session->been_active) = 1; + + ret = lttng_session_statedump(session); + if (ret) + return ret; end: return ret; } @@ -354,7 +535,6 @@ int lttng_event_create(const struct lttng_event_desc *desc, struct lttng_event *event; struct lttng_session *session = chan->session; struct cds_hlist_head *head; - struct cds_hlist_node *node; int ret = 0; size_t name_len = strlen(event_name); uint32_t hash; @@ -363,15 +543,6 @@ int lttng_event_create(const struct lttng_event_desc *desc, hash = jhash(event_name, name_len, 0); head = &chan->session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; - cds_hlist_for_each_entry(event, node, head, hlist) { - assert(event->desc); - if (!strncmp(event->desc->name, - desc->name, - LTTNG_UST_SYM_NAME_LEN - 1)) { - ret = -EEXIST; - goto exist; - } - } notify_socket = lttng_get_notify_socket(session->owner); if (notify_socket < 0) { @@ -379,6 +550,13 @@ int lttng_event_create(const struct lttng_event_desc *desc, goto socket_error; } + ret = lttng_create_all_event_enums(desc->nr_fields, desc->fields, + session); + if (ret < 0) { + DBG("Error (%d) adding enum to session", ret); + goto create_enum_error; + } + /* * Check if loglevel match. Refuse to connect event if not. */ @@ -407,6 +585,7 @@ int lttng_event_create(const struct lttng_event_desc *desc, /* Fetch event ID from sessiond */ ret = ustcomm_register_event(notify_socket, + session, session->objd, chan->objd, event_name, @@ -421,8 +600,6 @@ int lttng_event_create(const struct lttng_event_desc *desc, goto sessiond_register_error; } - /* Populate lttng_event structure before tracepoint registration. */ - cmm_smp_wmb(); cds_list_add(&event->node, &chan->session->events_head); cds_hlist_add_head(&event->hlist, head); return 0; @@ -430,22 +607,21 @@ int lttng_event_create(const struct lttng_event_desc *desc, sessiond_register_error: free(event); cache_error: +create_enum_error: socket_error: -exist: return ret; } static -int lttng_desc_match_wildcard_enabler(const struct lttng_event_desc *desc, +int lttng_desc_match_star_glob_enabler(const struct lttng_event_desc *desc, struct lttng_enabler *enabler) { int loglevel = 0; unsigned int has_loglevel = 0; - assert(enabler->type == LTTNG_ENABLER_WILDCARD); - /* Compare excluding final '*' */ - if (strncmp(desc->name, enabler->event_param.name, - strlen(enabler->event_param.name) - 1)) + assert(enabler->type == LTTNG_ENABLER_STAR_GLOB); + if (!strutils_star_glob_match(enabler->event_param.name, SIZE_MAX, + desc->name, SIZE_MAX)) return 0; if (desc->loglevel) { loglevel = *(*desc->loglevel); @@ -486,8 +662,34 @@ 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_STAR_GLOB: + { + struct lttng_ust_excluder_node *excluder; + + if (!lttng_desc_match_star_glob_enabler(desc, enabler)) { + return 0; + } + + /* + * If the matching event matches with an excluder, + * return 'does not match' + */ + cds_list_for_each_entry(excluder, &enabler->excluder_head, node) { + int count; + + for (count = 0; count < excluder->excluder.count; count++) { + int len; + char *excluder_name; + + excluder_name = (char *) (excluder->excluder.names) + + count * LTTNG_UST_SYM_NAME_LEN; + len = strnlen(excluder_name, LTTNG_UST_SYM_NAME_LEN); + if (len > 0 && strutils_star_glob_match(excluder_name, len, desc->name, SIZE_MAX)) + return 0; + } + } + return 1; + } case LTTNG_ENABLER_EVENT: return lttng_desc_match_event_enabler(desc, enabler); default: @@ -499,7 +701,11 @@ static int lttng_event_match_enabler(struct lttng_event *event, struct lttng_enabler *enabler) { - return lttng_desc_match_enabler(event->desc, enabler); + if (lttng_desc_match_enabler(event->desc, enabler) + && event->chan == enabler->chan) + return 1; + else + return 0; } static @@ -557,7 +763,8 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler) hash = jhash(event_name, name_len, 0); head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; cds_hlist_for_each_entry(event, node, head, hlist) { - if (event->desc == desc) + if (event->desc == desc + && event->chan == enabler->chan) found = 1; } if (found) @@ -577,6 +784,111 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler) } } +/* + * Iterate over all the UST sessions to unregister and destroy all probes from + * the probe provider descriptor received as argument. Must me called with the + * ust_lock held. + */ +void lttng_probe_provider_unregister_events(struct lttng_probe_desc *provider_desc) +{ + struct cds_hlist_node *node, *tmp_node; + struct cds_list_head *sessionsp; + struct lttng_session *session; + struct cds_hlist_head *head; + struct lttng_event *event; + unsigned int i, j; + + /* Get handle on list of sessions. */ + sessionsp = _lttng_get_sessions(); + + /* + * Iterate over all events in the probe provider descriptions and sessions + * to queue the unregistration of the events. + */ + for (i = 0; i < provider_desc->nr_events; i++) { + const struct lttng_event_desc *event_desc; + const char *event_name; + size_t name_len; + uint32_t hash; + + event_desc = provider_desc->event_desc[i]; + event_name = event_desc->name; + name_len = strlen(event_name); + hash = jhash(event_name, name_len, 0); + + /* Iterate over all session to find the current event description. */ + cds_list_for_each_entry(session, sessionsp, node) { + /* + * Get the list of events in the hashtable bucket and iterate to + * find the event matching this descriptor. + */ + head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; + cds_hlist_for_each_entry(event, node, head, hlist) { + if (event_desc == event->desc) { + /* Queue the unregistration of this event. */ + _lttng_event_unregister(event); + break; + } + } + } + } + + /* Wait for grace period. */ + synchronize_trace(); + /* Prune the unregistration queue. */ + __tracepoint_probe_prune_release_queue(); + + /* + * It is now safe to destroy the events and remove them from the event list + * and hashtables. + */ + for (i = 0; i < provider_desc->nr_events; i++) { + const struct lttng_event_desc *event_desc; + const char *event_name; + size_t name_len; + uint32_t hash; + + event_desc = provider_desc->event_desc[i]; + event_name = event_desc->name; + name_len = strlen(event_name); + hash = jhash(event_name, name_len, 0); + + /* Iterate over all sessions to find the current event description. */ + cds_list_for_each_entry(session, sessionsp, node) { + /* + * Get the list of events in the hashtable bucket and iterate to + * find the event matching this descriptor. + */ + head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; + cds_hlist_for_each_entry_safe(event, node, tmp_node, head, hlist) { + if (event_desc == event->desc) { + /* Destroy enums of the current event. */ + for (j = 0; j < event->desc->nr_fields; j++) { + const struct lttng_enum_desc *enum_desc; + const struct lttng_event_field *field; + struct lttng_enum *curr_enum; + + field = &(event->desc->fields[j]); + if (field->type.atype != atype_enum) { + continue; + } + + enum_desc = field->type.u.basic.enumeration.desc; + curr_enum = lttng_ust_enum_get_from_desc(session, enum_desc); + if (curr_enum) { + _lttng_enum_destroy(curr_enum); + } + } + + /* Destroy event. */ + _lttng_event_destroy(event); + break; + } + } + } + } +} + /* * Create events associated with an enabler (if not already present), * and add backward reference from the event to the enabler. @@ -624,12 +936,9 @@ int lttng_enabler_ref_events(struct lttng_enabler *enabler) /* * 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. + * Called with session mutex held. */ -int lttng_fix_pending_event_desc(const struct lttng_event_desc *desc) +int lttng_fix_pending_events(void) { struct lttng_session *session; @@ -639,6 +948,34 @@ int lttng_fix_pending_event_desc(const struct lttng_event_desc *desc) return 0; } +/* + * For each session of the owner thread, execute pending statedump. + * Only dump state for the sessions owned by the caller thread, because + * we don't keep ust_lock across the entire iteration. + */ +void lttng_handle_pending_statedump(void *owner) +{ + struct lttng_session *session; + + /* Execute state dump */ + do_lttng_ust_statedump(owner); + + /* Clear pending state dump */ + if (ust_lock()) { + goto end; + } + cds_list_for_each_entry(session, &sessions, node) { + if (session->owner != owner) + continue; + if (!session->statedump_pending) + continue; + session->statedump_pending = 0; + } +end: + ust_unlock(); + return; +} + /* * Only used internally at session destruction. */ @@ -647,7 +984,11 @@ void _lttng_event_destroy(struct lttng_event *event) { struct lttng_enabler_ref *enabler_ref, *tmp_enabler_ref; + /* Remove from event list. */ cds_list_del(&event->node); + /* Remove from event hash table. */ + cds_hlist_del(&event->hlist); + lttng_destroy_context(event->ctx); lttng_free_event_filter_runtime(event); /* Free event enabler refs */ @@ -657,6 +998,14 @@ void _lttng_event_destroy(struct lttng_event *event) free(event); } +static +void _lttng_enum_destroy(struct lttng_enum *_enum) +{ + cds_list_del(&_enum->node); + cds_hlist_del(&_enum->hlist); + free(_enum); +} + void lttng_ust_events_exit(void) { struct lttng_session *session, *tmpsession; @@ -679,11 +1028,12 @@ struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type, return NULL; enabler->type = type; CDS_INIT_LIST_HEAD(&enabler->filter_bytecode_head); + CDS_INIT_LIST_HEAD(&enabler->excluder_head); memcpy(&enabler->event_param, event_param, sizeof(enabler->event_param)); enabler->chan = chan; /* ctx left NULL */ - enabler->enabled = 1; + enabler->enabled = 0; cds_list_add(&enabler->node, &enabler->chan->session->enablers_head); lttng_session_lazy_sync_enablers(enabler->chan->session); return enabler; @@ -712,7 +1062,17 @@ int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler, return 0; } +int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler, + struct lttng_ust_excluder_node *excluder) +{ + excluder->enabler = enabler; + cds_list_add_tail(&excluder->node, &enabler->excluder_head); + lttng_session_lazy_sync_enablers(enabler->chan->session); + return 0; +} + int lttng_attach_context(struct lttng_ust_context *context_param, + union ust_args *uargs, struct lttng_ctx **ctx, struct lttng_session *session) { /* @@ -726,12 +1086,56 @@ int lttng_attach_context(struct lttng_ust_context *context_param, switch (context_param->ctx) { case LTTNG_UST_CONTEXT_PTHREAD_ID: return lttng_add_pthread_id_to_ctx(ctx); + case LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER: + { + struct lttng_ust_perf_counter_ctx *perf_ctx_param; + + perf_ctx_param = &context_param->u.perf_counter; + return lttng_add_perf_counter_to_ctx( + perf_ctx_param->type, + perf_ctx_param->config, + perf_ctx_param->name, + 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); + case LTTNG_UST_CONTEXT_IP: + return lttng_add_ip_to_ctx(ctx); + case LTTNG_UST_CONTEXT_CPU_ID: + return lttng_add_cpu_id_to_ctx(ctx); + case LTTNG_UST_CONTEXT_APP_CONTEXT: + return lttng_ust_add_app_context_to_ctx_rcu(uargs->app_context.ctxname, + ctx); + case LTTNG_UST_CONTEXT_CGROUP_NS: + return lttng_add_cgroup_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_IPC_NS: + return lttng_add_ipc_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_MNT_NS: + return lttng_add_mnt_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_NET_NS: + return lttng_add_net_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_PID_NS: + return lttng_add_pid_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_USER_NS: + return lttng_add_user_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_UTS_NS: + return lttng_add_uts_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VUID: + return lttng_add_vuid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VEUID: + return lttng_add_veuid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VSUID: + return lttng_add_vsuid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VGID: + return lttng_add_vgid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VEGID: + return lttng_add_vegid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VSGID: + return lttng_add_vsgid_to_ctx(ctx); default: return -EINVAL; } @@ -757,6 +1161,7 @@ static void lttng_enabler_destroy(struct lttng_enabler *enabler) { struct lttng_ust_filter_bytecode_node *filter_node, *tmp_filter_node; + struct lttng_ust_excluder_node *excluder_node, *tmp_excluder_node; /* Destroy filter bytecode */ cds_list_for_each_entry_safe(filter_node, tmp_filter_node, @@ -764,6 +1169,12 @@ void lttng_enabler_destroy(struct lttng_enabler *enabler) free(filter_node); } + /* Destroy excluders */ + cds_list_for_each_entry_safe(excluder_node, tmp_excluder_node, + &enabler->excluder_head, node) { + free(excluder_node); + } + /* Destroy contexts */ lttng_destroy_context(enabler->ctx); @@ -839,6 +1250,7 @@ void lttng_session_sync_enablers(struct lttng_session *session) lttng_filter_sync_state(runtime); } } + __tracepoint_probe_prune_release_queue(); } /* @@ -855,3 +1267,44 @@ void lttng_session_lazy_sync_enablers(struct lttng_session *session) return; lttng_session_sync_enablers(session); } + +/* + * Update all sessions with the given app context. + * Called with ust lock held. + * This is invoked when an application context gets loaded/unloaded. It + * ensures the context callbacks are in sync with the application + * context (either app context callbacks, or dummy callbacks). + */ +void lttng_ust_context_set_session_provider(const char *name, + size_t (*get_size)(struct lttng_ctx_field *field, size_t offset), + void (*record)(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan), + void (*get_value)(struct lttng_ctx_field *field, + struct lttng_ctx_value *value)) +{ + struct lttng_session *session; + + cds_list_for_each_entry(session, &sessions, node) { + struct lttng_channel *chan; + struct lttng_event *event; + int ret; + + ret = lttng_ust_context_set_provider_rcu(&session->ctx, + name, get_size, record, get_value); + if (ret) + abort(); + cds_list_for_each_entry(chan, &session->chan_head, node) { + ret = lttng_ust_context_set_provider_rcu(&chan->ctx, + name, get_size, record, get_value); + if (ret) + abort(); + } + cds_list_for_each_entry(event, &session->events_head, node) { + ret = lttng_ust_context_set_provider_rcu(&event->ctx, + name, get_size, record, get_value); + if (ret) + abort(); + } + } +}