From 574a6217af27f0e1ca8998790ce7744684d83168 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 5 Dec 2011 19:54:48 -0500 Subject: [PATCH] loglevels: deal with fixup upon library load Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-events.h | 31 ++++++++++------ liblttng-ust/ltt-events.c | 50 ++++++++++++++++++++------ liblttng-ust/ltt-probes.c | 70 +++++++++++++++++++++++------------- liblttng-ust/lttng-ust-abi.c | 6 ++-- 4 files changed, 109 insertions(+), 48 deletions(-) diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 5867b124..bcc432e7 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -189,19 +189,30 @@ struct tracepoint_loglevel_entry { long value; }; +struct loglevel_entry; + /* - * Entry describing an active loglevel, along with the event attribute - * and channel information configuring the events that need to be - * enabled. + * Entry describing a per-session active loglevel, along with the event + * attribute and channel information configuring the events that need to + * be enabled. */ -struct loglevel_entry { - struct cds_hlist_node hlist; +struct session_loglevel { struct ltt_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 loglevels */ + struct cds_list_head session_list; + struct loglevel_entry *entry; unsigned int enabled:1; +}; + +/* + * Entry describing an active loglevel (per name) for all sessions. + */ +struct loglevel_entry { + struct cds_hlist_node hlist; + struct cds_list_head session_list; char name[0]; }; @@ -411,14 +422,14 @@ struct lttng_ust_tracepoint_iter * lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list *list); struct loglevel_entry *get_loglevel(const char *name); -struct loglevel_entry *add_loglevel(const char *name, +struct session_loglevel *add_loglevel(const char *name, struct ltt_channel *chan, struct lttng_ust_event *event_param); -void _remove_loglevel(struct loglevel_entry *e); -int ltt_loglevel_enable(struct loglevel_entry *loglevel); -int ltt_loglevel_disable(struct loglevel_entry *loglevel); +void _remove_loglevel(struct session_loglevel *loglevel); +int ltt_loglevel_enable(struct session_loglevel *loglevel); +int ltt_loglevel_disable(struct session_loglevel *loglevel); int ltt_loglevel_create(struct ltt_channel *chan, struct lttng_ust_event *event_param, - struct loglevel_entry **_entry); + struct session_loglevel **sl); #endif /* _LTTNG_UST_EVENTS_H */ diff --git a/liblttng-ust/ltt-events.c b/liblttng-ust/ltt-events.c index c754d6ff..e3fd3f79 100644 --- a/liblttng-ust/ltt-events.c +++ b/liblttng-ust/ltt-events.c @@ -74,7 +74,7 @@ struct ust_pending_probe { }; static void _ltt_event_destroy(struct ltt_event *event); -static void _ltt_loglevel_destroy(struct loglevel_entry *entry); +static void _ltt_loglevel_destroy(struct session_loglevel *sl); static void _ltt_channel_destroy(struct ltt_channel *chan); static int _ltt_event_unregister(struct ltt_event *event); static @@ -136,10 +136,38 @@ int pending_probe_fix_events(const struct lttng_event_desc *desc) uint32_t hash = jhash(name, name_len - 1, 0); int ret = 0; - /* TODO: + /* * For this event, we need to lookup the loglevel. If active (in * the active loglevels hash table), we must create the event. */ + if (desc->loglevel) { + const struct tracepoint_loglevel_entry *ev_ll; + struct loglevel_entry *loglevel; + + ev_ll = *desc->loglevel; + loglevel = get_loglevel(ev_ll->identifier); + if (loglevel) { + struct session_loglevel *sl; + + cds_list_for_each_entry(sl, &loglevel->session_list, + session_list) { + struct ltt_event *ev; + int ret; + + /* create event */ + ret = ltt_event_create(sl->chan, + &sl->event_param, NULL, + &ev); + /* + * TODO: report error. + */ + if (ret) + continue; + cds_list_add(&ev->loglevel_list, + &sl->events); + } + } + } head = &pending_probe_table[hash & (PENDING_PROBE_HASH_SIZE - 1)]; cds_hlist_for_each_entry_safe(e, node, p, head, node) { @@ -190,7 +218,7 @@ void ltt_session_destroy(struct ltt_session *session) { struct ltt_channel *chan, *tmpchan; struct ltt_event *event, *tmpevent; - struct loglevel_entry *loglevel, *tmploglevel; + struct session_loglevel *loglevel, *tmploglevel; int ret; CMM_ACCESS_ONCE(session->active) = 0; @@ -360,22 +388,22 @@ void _ltt_channel_destroy(struct ltt_channel *chan) int ltt_loglevel_create(struct ltt_channel *chan, struct lttng_ust_event *event_param, - struct loglevel_entry **_entry) + struct session_loglevel **_sl) { - struct loglevel_entry *entry; + struct session_loglevel *sl; - entry = add_loglevel(event_param->name, chan, event_param); - if (!entry || IS_ERR(entry)) { - return PTR_ERR(entry); + sl = add_loglevel(event_param->name, chan, event_param); + if (!sl || IS_ERR(sl)) { + return PTR_ERR(sl); } - *_entry = entry; + *_sl = sl; return 0; } static -void _ltt_loglevel_destroy(struct loglevel_entry *entry) +void _ltt_loglevel_destroy(struct session_loglevel *sl) { - _remove_loglevel(entry); + _remove_loglevel(sl); } /* diff --git a/liblttng-ust/ltt-probes.c b/liblttng-ust/ltt-probes.c index d2623947..29945128 100644 --- a/liblttng-ust/ltt-probes.c +++ b/liblttng-ust/ltt-probes.c @@ -235,7 +235,8 @@ struct loglevel_entry *get_loglevel(const char *name) * loglevel. Add them to the events list as created. */ static -void _probes_create_loglevel_events(struct loglevel_entry *loglevel) +void _probes_create_loglevel_events(struct loglevel_entry *entry, + struct session_loglevel *loglevel) { struct lttng_probe_desc *probe_desc; int i; @@ -247,7 +248,7 @@ void _probes_create_loglevel_events(struct loglevel_entry *loglevel) if (!(probe_desc->event_desc[i]->loglevel)) continue; ev_ll = *probe_desc->event_desc[i]->loglevel; - if (!strcmp(ev_ll->identifier, loglevel->name)) { + if (!strcmp(ev_ll->identifier, entry->name)) { struct ltt_event *ev; int ret; @@ -263,7 +264,6 @@ void _probes_create_loglevel_events(struct loglevel_entry *loglevel) cds_list_add(&ev->loglevel_list, &loglevel->events); } - } } } @@ -272,46 +272,64 @@ void _probes_create_loglevel_events(struct loglevel_entry *loglevel) * Add the loglevel to the loglevel hash table. Must be called with * ust lock held. */ -struct loglevel_entry *add_loglevel(const char *name, +struct session_loglevel *add_loglevel(const char *name, struct ltt_channel *chan, struct lttng_ust_event *event_param) { struct cds_hlist_head *head; 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; + /* loglevel entry */ head = &loglevel_table[hash & (LOGLEVEL_TABLE_SIZE - 1)]; cds_hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { - DBG("loglevel %s busy", name); + 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 loglevel_entry) + name_len); + if (!e) + return ERR_PTR(-ENOMEM); + memcpy(&e->name[0], name, name_len); + cds_hlist_add_head(&e->hlist, head); + } + + /* session loglevel */ + cds_list_for_each_entry(sl, &e->session_list, session_list) { + if (chan == sl->chan) { + DBG("loglevel %s busy for this channel", name); return ERR_PTR(-EEXIST); /* Already there */ } } - /* - * Using zmalloc here to allocate a variable length element. Could - * cause some memory fragmentation if overused. - */ - e = zmalloc(sizeof(struct loglevel_entry) + name_len); - if (!e) + sl = zmalloc(sizeof(struct session_loglevel)); + if (!sl) return ERR_PTR(-ENOMEM); - memcpy(&e->name[0], name, name_len); - e->chan = chan; - e->enabled = 1; - memcpy(&e->event_param, event_param, sizeof(e->event_param)); - cds_hlist_add_head(&e->hlist, head); - CDS_INIT_LIST_HEAD(&e->events); - _probes_create_loglevel_events(e); - cds_list_add(&e->list, &chan->session->loglevels); - return e; + sl->chan = chan; + sl->enabled = 1; + memcpy(&sl->event_param, event_param, sizeof(sl->event_param)); + CDS_INIT_LIST_HEAD(&sl->events); + cds_list_add(&sl->list, &chan->session->loglevels); + cds_list_add(&sl->session_list, &e->session_list); + _probes_create_loglevel_events(e, sl); + return sl; } /* * Remove the loglevel from the loglevel hash table. Must be called with * ust_lock held. Only called at session teardown. */ -void _remove_loglevel(struct loglevel_entry *loglevel) +void _remove_loglevel(struct session_loglevel *loglevel) { struct ltt_event *ev, *tmp; @@ -323,12 +341,16 @@ void _remove_loglevel(struct loglevel_entry *loglevel) cds_list_for_each_entry_safe(ev, tmp, &loglevel->events, list) { cds_list_del(&ev->list); } - cds_hlist_del(&loglevel->hlist); + cds_list_del(&loglevel->session_list); cds_list_del(&loglevel->list); + if (cds_list_empty(&loglevel->entry->session_list)) { + cds_hlist_del(&loglevel->entry->hlist); + free(loglevel->entry); + } free(loglevel); } -int ltt_loglevel_enable(struct loglevel_entry *loglevel) +int ltt_loglevel_enable(struct session_loglevel *loglevel) { struct ltt_event *ev; int ret; @@ -346,7 +368,7 @@ int ltt_loglevel_enable(struct loglevel_entry *loglevel) return 0; } -int ltt_loglevel_disable(struct loglevel_entry *loglevel) +int ltt_loglevel_disable(struct session_loglevel *loglevel) { struct ltt_event *ev; int ret; diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 548b3a52..25f213bb 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -664,7 +664,7 @@ int lttng_abi_create_loglevel(int channel_objd, struct lttng_ust_event *event_param) { struct ltt_channel *channel = objd_private(channel_objd); - struct loglevel_entry *loglevel; + struct session_loglevel *loglevel; int loglevel_objd, ret; event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; @@ -968,7 +968,7 @@ static const struct lttng_ust_objd_ops lttng_event_ops = { static long lttng_loglevel_cmd(int objd, unsigned int cmd, unsigned long arg) { - struct loglevel_entry *loglevel = objd_private(objd); + struct session_loglevel *loglevel = objd_private(objd); switch (cmd) { case LTTNG_UST_CONTEXT: @@ -990,7 +990,7 @@ long lttng_loglevel_cmd(int objd, unsigned int cmd, unsigned long arg) static int lttng_loglevel_release(int objd) { - struct loglevel_entry *loglevel = objd_private(objd); + struct session_loglevel *loglevel = objd_private(objd); if (loglevel) return lttng_ust_objd_unref(loglevel->chan->objd); -- 2.34.1