X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Fltt-probes.c;h=9dc2356088e8b7a69bcb36f1180384266bae654f;hb=ff412fb523eeacd9f2b698ccefc4f716ace9afd0;hp=b683b81bb24107a769cbdfe3eaeedb0be1ac85c7;hpb=3431ca3eea9bfaab6ced44922beb9e6bb7a2abc1;p=lttng-ust.git diff --git a/liblttng-ust/ltt-probes.c b/liblttng-ust/ltt-probes.c index b683b81b..9dc23560 100644 --- a/liblttng-ust/ltt-probes.c +++ b/liblttng-ust/ltt-probes.c @@ -34,6 +34,12 @@ static CDS_LIST_HEAD(probe_list); #define LOGLEVEL_TABLE_SIZE (1 << LOGLEVEL_HASH_BITS) static struct cds_hlist_head loglevel_table[LOGLEVEL_TABLE_SIZE]; +/* + * Wildcard list, containing the active wildcards. + * Protected by ust lock. + */ +static CDS_LIST_HEAD(wildcard_list); + static const struct lttng_probe_desc *find_provider(const char *provider) { @@ -54,7 +60,8 @@ const struct lttng_event_desc *find_event(const char *name) cds_list_for_each_entry(probe_desc, &probe_list, head) { for (i = 0; i < probe_desc->nr_events; i++) { - if (!strcmp(probe_desc->event_desc[i]->name, name)) + if (!strncmp(probe_desc->event_desc[i]->name, name, + LTTNG_UST_SYM_NAME_LEN - 1)) return probe_desc->event_desc[i]; } } @@ -221,11 +228,17 @@ struct loglevel_entry *get_loglevel(const char *name) struct cds_hlist_head *head; struct cds_hlist_node *node; struct loglevel_entry *e; - uint32_t hash = jhash(name, strlen(name), 0); + size_t name_len = strlen(name); + uint32_t hash; + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating loglevel name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1); + name_len = LTTNG_UST_SYM_NAME_LEN - 1; + } + hash = jhash(name, name_len, 0); head = &loglevel_table[hash & (LOGLEVEL_TABLE_SIZE - 1)]; cds_hlist_for_each_entry(e, node, head, hlist) { - if (!strcmp(name, e->name)) + if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) return e; } return NULL; @@ -268,7 +281,8 @@ void _probes_create_loglevel_events(struct loglevel_entry *entry, if (atoll(entry->name) == ev_ll->value) { match = 1; } - } else if (!strcmp(ev_ll->identifier, entry->name)) { + } else if (!strncmp(ev_ll->identifier, entry->name, + LTTNG_UST_SYM_NAME_LEN - 1)) { match = 1; } @@ -308,14 +322,19 @@ struct session_loglevel *add_loglevel(const char *name, struct cds_hlist_node *node; struct loglevel_entry *e; struct session_loglevel *sl; - size_t name_len = strlen(name) + 1; - uint32_t hash = jhash(name, name_len-1, 0); int found = 0; + size_t name_len = strlen(name); + uint32_t hash; + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating loglevel name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1); + name_len = LTTNG_UST_SYM_NAME_LEN - 1; + } + hash = jhash(name, name_len, 0); /* loglevel entry */ head = &loglevel_table[hash & (LOGLEVEL_TABLE_SIZE - 1)]; cds_hlist_for_each_entry(e, node, head, hlist) { - if (!strcmp(name, e->name)) { + if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) { found = 1; break; } @@ -326,10 +345,11 @@ struct session_loglevel *add_loglevel(const char *name, * Using zmalloc here to allocate a variable length element. Could * cause some memory fragmentation if overused. */ - e = zmalloc(sizeof(struct loglevel_entry) + name_len); + e = zmalloc(sizeof(struct loglevel_entry) + name_len + 1); if (!e) return ERR_PTR(-ENOMEM); - memcpy(&e->name[0], name, name_len); + memcpy(&e->name[0], name, name_len + 1); + e->name[name_len] = '\0'; cds_hlist_add_head(&e->hlist, head); CDS_INIT_LIST_HEAD(&e->session_list); } @@ -369,8 +389,9 @@ void _remove_loglevel(struct session_loglevel *loglevel) * loglevel from the list. The session teardown will take care * of freeing the event memory. */ - cds_list_for_each_entry_safe(ev, tmp, &loglevel->events, list) { - cds_list_del(&ev->list); + cds_list_for_each_entry_safe(ev, tmp, &loglevel->events, + loglevel_list) { + cds_list_del(&ev->loglevel_list); } cds_list_del(&loglevel->session_list); cds_list_del(&loglevel->list); @@ -388,7 +409,7 @@ int ltt_loglevel_enable(struct session_loglevel *loglevel) if (loglevel->enabled) return -EEXIST; - cds_list_for_each_entry(ev, &loglevel->events, list) { + cds_list_for_each_entry(ev, &loglevel->events, loglevel_list) { ret = ltt_event_enable(ev); if (ret) { DBG("Error: enable error.\n"); @@ -406,7 +427,7 @@ int ltt_loglevel_disable(struct session_loglevel *loglevel) if (!loglevel->enabled) return -EEXIST; - cds_list_for_each_entry(ev, &loglevel->events, list) { + cds_list_for_each_entry(ev, &loglevel->events, loglevel_list) { ret = ltt_event_disable(ev); if (ret) { DBG("Error: disable error.\n"); @@ -416,3 +437,194 @@ int ltt_loglevel_disable(struct session_loglevel *loglevel) loglevel->enabled = 0; return 0; } + +/* WILDCARDS */ + +/* + * 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. + */ +struct wildcard_entry *match_wildcard(const char *name) +{ + struct wildcard_entry *e; + + cds_list_for_each_entry(e, &wildcard_list, list) { + /* If only contain '*' */ + if (strlen(e->name) == 1) + return e; + /* Compare excluding final '*' */ + if (!strncmp(name, e->name, strlen(e->name) - 1)) + return e; + } + return NULL; +} + +/* + * marshall all probes/all events and create those that fit the + * wildcard. Add them to the events list as created. + */ +static +void _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))) { + match = 1; + } + if (match) { + struct ltt_event *ev; + int ret; + + memcpy(&event_param, &wildcard->event_param, + sizeof(event_param)); + memcpy(event_param.name, + event_desc->name, + sizeof(event_param.name)); + /* create event */ + ret = ltt_event_create(wildcard->chan, + &event_param, NULL, + &ev); + if (ret) { + DBG("Error creating event"); + continue; + } + cds_list_add(&ev->wildcard_list, + &wildcard->events); + } + } + } +} + +/* + * Add the wildcard to the wildcard hash table. Must be called with + * ust lock held. + */ +struct session_wildcard *add_wildcard(const char *name, + struct ltt_channel *chan, + struct lttng_ust_event *event_param) +{ + struct wildcard_entry *e; + struct session_wildcard *sw; + size_t name_len = strlen(name) + 1; + int found = 0; + + /* wildcard entry */ + cds_list_for_each_entry(e, &wildcard_list, list) { + if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) { + found = 1; + break; + } + } + + if (!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], name, name_len); + cds_list_add(&e->list, &wildcard_list); + CDS_INIT_LIST_HEAD(&e->session_list); + } + + /* session wildcard */ + cds_list_for_each_entry(sw, &e->session_list, session_list) { + if (chan == sw->chan) { + DBG("wildcard %s busy for this channel", name); + return ERR_PTR(-EEXIST); /* Already there */ + } + } + 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; + 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; + _probes_create_wildcard_events(e, sw); + return sw; +} + +/* + * Remove the wildcard from the wildcard hash table. Must be called with + * ust_lock held. Only called at session teardown. + */ +void _remove_wildcard(struct session_wildcard *wildcard) +{ + struct ltt_event *ev, *tmp; + + /* + * 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); + } + free(wildcard); +} + +int ltt_wildcard_enable(struct session_wildcard *wildcard) +{ + struct ltt_event *ev; + int ret; + + if (wildcard->enabled) + return -EEXIST; + cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) { + ret = ltt_event_enable(ev); + if (ret) { + DBG("Error: enable error.\n"); + return ret; + } + } + wildcard->enabled = 1; + return 0; +} + +int ltt_wildcard_disable(struct session_wildcard *wildcard) +{ + struct ltt_event *ev; + int ret; + + if (!wildcard->enabled) + return -EEXIST; + cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) { + ret = ltt_event_disable(ev); + if (ret) { + DBG("Error: disable error.\n"); + return ret; + } + } + wildcard->enabled = 0; + return 0; +}