* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define _GNU_SOURCE
+#define _LGPL_SOURCE
#include <stdio.h>
#include <urcu/list.h>
#include <urcu/hlist.h>
#include <stddef.h>
#include <inttypes.h>
#include <time.h>
+#include <stdbool.h>
#include <lttng/ust-endian.h>
#include "clock.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"
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);
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);
_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);
const char *enum_name = desc->name;
struct lttng_enum *_enum;
struct cds_hlist_head *head;
- struct cds_hlist_node *node;
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)];
- cds_hlist_for_each_entry(_enum, node, head, hlist) {
- assert(_enum->desc);
- if (!strncmp(_enum->desc->name, desc->name,
- LTTNG_UST_SYM_NAME_LEN - 1)) {
- ret = -EEXIST;
- goto exist;
- }
+
+ _enum = lttng_ust_enum_get_from_desc(session, desc);
+ if (_enum) {
+ ret = -EEXIST;
+ goto exist;
}
notify_socket = lttng_get_notify_socket(session->owner);
const struct lttng_enum_desc *enum_desc;
int ret;
- enum_desc = type->u.basic.enumeration.desc;
+ enum_desc = type->u.legacy.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_enum_nestable:
+ {
+ const struct lttng_enum_desc *enum_desc;
+ int ret;
+
+ enum_desc = type->u.enum_nestable.desc;
ret = lttng_enum_create(enum_desc, session);
if (ret && ret != -EEXIST) {
DBG("Unable to create enum error: (%d)", ret);
int ret;
tag_field_generic = lttng_ust_dynamic_type_tag_field();
- enum_desc = tag_field_generic->type.u.basic.enumeration.desc;
+ enum_desc = tag_field_generic->type.u.enum_nestable.desc;
ret = lttng_enum_create(enum_desc, session);
if (ret && ret != -EEXIST) {
DBG("Unable to create enum error: (%d)", 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)
{
/* Set transient enabler state to "enabled" */
session->tstate = 1;
+ /* 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.
}
}
- /* We need to sync enablers with session before activation. */
- lttng_session_sync_enablers(session);
-
/* Set atomically the state to "active" */
CMM_ACCESS_ONCE(session->active) = 1;
CMM_ACCESS_ONCE(session->been_active) = 1;
- session->statedump_pending = 1;
- lttng_ust_sockinfo_session_enabled(session->owner);
+ ret = lttng_session_statedump(session);
+ if (ret)
+ return ret;
end:
return ret;
}
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;
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)
- && chan == event->chan) {
- ret = -EEXIST;
- goto exist;
- }
- }
notify_socket = lttng_get_notify_socket(session->owner);
if (notify_socket < 0) {
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;
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->format_type == LTTNG_ENABLER_FORMAT_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);
int loglevel = 0;
unsigned int has_loglevel = 0;
- assert(enabler->type == LTTNG_ENABLER_EVENT);
+ assert(enabler->format_type == LTTNG_ENABLER_FORMAT_EVENT);
if (strcmp(desc->name, enabler->event_param.name))
return 0;
if (desc->loglevel) {
int lttng_desc_match_enabler(const struct lttng_event_desc *desc,
struct lttng_enabler *enabler)
{
- struct lttng_ust_excluder_node *excluder;
-
- /* If 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 found, 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 && excluder_name[len - 1] == '*') {
- found = !strncmp(desc->name, excluder_name,
- len - 1);
- } else {
- found = !strncmp(desc->name, excluder_name,
- LTTNG_UST_SYM_NAME_LEN - 1);
- }
- if (found) {
- return 0;
+ switch (enabler->format_type) {
+ case LTTNG_ENABLER_FORMAT_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;
}
- switch (enabler->type) {
- case LTTNG_ENABLER_WILDCARD:
- return lttng_desc_match_wildcard_enabler(desc, enabler);
- case LTTNG_ENABLER_EVENT:
+ case LTTNG_ENABLER_FORMAT_EVENT:
return lttng_desc_match_event_enabler(desc, enabler);
default:
return -EINVAL;
*/
cds_list_for_each_entry(probe_desc, probe_list, head) {
for (i = 0; i < probe_desc->nr_events; i++) {
- int found = 0, ret;
+ int ret;
+ bool found = false;
struct cds_hlist_head *head;
struct cds_hlist_node *node;
const char *event_name;
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
- && event->chan == enabler->chan)
- found = 1;
+ && event->chan == enabler->chan) {
+ found = true;
+ break;
+ }
}
if (found)
continue;
}
}
+/*
+ * 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]);
+ switch (field->type.atype) {
+ case atype_enum:
+ enum_desc = field->type.u.legacy.basic.enumeration.desc;
+ break;
+ case atype_enum_nestable:
+ enum_desc = field->type.u.enum_nestable.desc;
+ break;
+ default:
+ continue;
+ }
+ 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.
struct lttng_session *session = enabler->chan->session;
struct lttng_event *event;
+ if (!enabler->enabled)
+ goto end;
+
/* First ensure that probe events are created for this enabler. */
lttng_create_event_if_missing(enabler);
/* TODO: merge event context. */
}
+end:
return 0;
}
{
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 */
void _lttng_enum_destroy(struct lttng_enum *_enum)
{
cds_list_del(&_enum->node);
+ cds_hlist_del(&_enum->hlist);
free(_enum);
}
/*
* Enabler management.
*/
-struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type,
+struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_format_type format_type,
struct lttng_ust_event *event_param,
struct lttng_channel *chan)
{
enabler = zmalloc(sizeof(*enabler));
if (!enabler)
return NULL;
- enabler->type = type;
+ enabler->format_type = format_type;
CDS_INIT_LIST_HEAD(&enabler->filter_bytecode_head);
CDS_INIT_LIST_HEAD(&enabler->excluder_head);
memcpy(&enabler->event_param, event_param,
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_TIME_NS:
+ return lttng_add_time_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;
}
lttng_filter_sync_state(runtime);
}
}
+ __tracepoint_probe_prune_release_queue();
}
/*