From 2c05c691a10f3130f9339a15369140ad6ca70f85 Mon Sep 17 00:00:00 2001 From: Francis Deslauriers Date: Fri, 9 Feb 2018 15:15:25 -0500 Subject: [PATCH] Support unloading of probe providers With this commit, it's now possible to dlclose() a library containing an actively used probe provider. The destructor of such library will now iterate over all the sessions and over all probe definitions to unregister them from the respective callsites in the process. Signed-off-by: Francis Deslauriers Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-events.c | 2 +- liblttng-ust/lttng-probes.c | 5 ++++- liblttng-ust/tracepoint.c | 43 +++++++++++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index e130ec62..255c4b95 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -798,7 +798,7 @@ void lttng_probe_provider_unregister_events(struct lttng_probe_desc *provider_de struct lttng_session *session; struct cds_hlist_head *head; struct lttng_event *event; - int i; + unsigned int i, j; /* Get handle on list of sessions. */ sessionsp = _lttng_get_sessions(); diff --git a/liblttng-ust/lttng-probes.c b/liblttng-ust/lttng-probes.c index a09497f8..862b19e7 100644 --- a/liblttng-ust/lttng-probes.c +++ b/liblttng-ust/lttng-probes.c @@ -226,7 +226,10 @@ void lttng_probe_unregister(struct lttng_probe_desc *desc) cds_list_del(&desc->head); else cds_list_del(&desc->lazy_init_head); - DBG("just unregistered probe %s", desc->provider); + + lttng_probe_provider_unregister_events(desc); + DBG("just unregistered probes of provider %s", desc->provider); + ust_unlock(); } diff --git a/liblttng-ust/tracepoint.c b/liblttng-ust/tracepoint.c index 14b8231f..2c25d462 100644 --- a/liblttng-ust/tracepoint.c +++ b/liblttng-ust/tracepoint.c @@ -107,8 +107,8 @@ struct tracepoint_entry { struct lttng_ust_tracepoint_probe *probes; int refcount; /* Number of times armed. 0 if disarmed. */ int callsite_refcount; /* how many libs use this tracepoint */ - const char *signature; - char name[0]; + char *signature; + char *name; }; struct tp_probes { @@ -132,6 +132,7 @@ struct callsite_entry { struct cds_hlist_node hlist; /* hash table node */ struct cds_list_head node; /* lib list of callsites node */ struct lttng_ust_tracepoint *tp; + bool tp_entry_callsite_ref; /* Has a tp_entry took a ref on this callsite */ }; /* coverity[+alloc] */ @@ -284,6 +285,8 @@ static struct tracepoint_entry *add_tracepoint(const char *name, struct cds_hlist_node *node; struct tracepoint_entry *e; size_t name_len = strlen(name); + size_t sig_len = strlen(signature); + size_t sig_off, name_off; uint32_t hash; if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { @@ -298,19 +301,29 @@ static struct tracepoint_entry *add_tracepoint(const char *name, return ERR_PTR(-EEXIST); /* Already there */ } } + /* - * Using zmalloc here to allocate a variable length element. Could - * cause some memory fragmentation if overused. + * Using zmalloc here to allocate a variable length elements: name and + * signature. Could cause some memory fragmentation if overused. */ - e = zmalloc(sizeof(struct tracepoint_entry) + name_len + 1); + name_off = sizeof(struct tracepoint_entry); + sig_off = name_off + name_len + 1; + + e = zmalloc(sizeof(struct tracepoint_entry) + name_len + 1 + sig_len + 1); if (!e) return ERR_PTR(-ENOMEM); - memcpy(&e->name[0], name, name_len + 1); + e->name = (char *) e + name_off; + memcpy(e->name, name, name_len + 1); e->name[name_len] = '\0'; + + e->signature = (char *) e + sig_off; + memcpy(e->signature, signature, sig_len + 1); + e->signature[sig_len] = '\0'; + e->probes = NULL; e->refcount = 0; e->callsite_refcount = 0; - e->signature = signature; + cds_hlist_add_head(&e->hlist, head); return e; } @@ -405,6 +418,7 @@ static void add_callsite(struct tracepoint_lib * lib, struct lttng_ust_tracepoin if (!tp_entry) return; tp_entry->callsite_refcount++; + e->tp_entry_callsite_ref = true; } /* @@ -417,7 +431,8 @@ static void remove_callsite(struct callsite_entry *e) tp_entry = get_tracepoint(e->tp->name); if (tp_entry) { - tp_entry->callsite_refcount--; + if (e->tp_entry_callsite_ref) + tp_entry->callsite_refcount--; if (tp_entry->callsite_refcount == 0) disable_tracepoint(e->tp); } @@ -453,10 +468,15 @@ static void tracepoint_sync_callsites(const char *name) if (strncmp(name, tp->name, LTTNG_UST_SYM_NAME_LEN - 1)) continue; if (tp_entry) { + if (!e->tp_entry_callsite_ref) { + tp_entry->callsite_refcount++; + e->tp_entry_callsite_ref = true; + } set_tracepoint(&tp_entry, tp, !!tp_entry->refcount); } else { disable_tracepoint(tp); + e->tp_entry_callsite_ref = false; } } } @@ -545,7 +565,12 @@ tracepoint_add_probe(const char *name, void (*probe)(void), void *data, struct lttng_ust_tracepoint_probe *old; entry = get_tracepoint(name); - if (!entry) { + if (entry) { + if (strcmp(entry->signature, signature) != 0) { + ERR("Tracepoint and probe signature do not match."); + return ERR_PTR(-EINVAL); + } + } else { entry = add_tracepoint(name, signature); if (IS_ERR(entry)) return (struct lttng_ust_tracepoint_probe *)entry; -- 2.34.1