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 <francis.deslauriers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
struct lttng_session *session;
struct cds_hlist_head *head;
struct lttng_event *event;
struct lttng_session *session;
struct cds_hlist_head *head;
struct lttng_event *event;
/* Get handle on list of sessions. */
sessionsp = _lttng_get_sessions();
/* Get handle on list of sessions. */
sessionsp = _lttng_get_sessions();
cds_list_del(&desc->head);
else
cds_list_del(&desc->lazy_init_head);
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);
+
struct lttng_ust_tracepoint_probe *probes;
int refcount; /* Number of times armed. 0 if disarmed. */
int callsite_refcount; /* how many libs use this tracepoint */
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 cds_hlist_node hlist; /* hash table node */
struct cds_list_head node; /* lib list of callsites node */
struct lttng_ust_tracepoint *tp;
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] */
};
/* coverity[+alloc] */
struct cds_hlist_node *node;
struct tracepoint_entry *e;
size_t name_len = strlen(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) {
uint32_t hash;
if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
return ERR_PTR(-EEXIST); /* Already there */
}
}
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);
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->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->probes = NULL;
e->refcount = 0;
e->callsite_refcount = 0;
- e->signature = signature;
cds_hlist_add_head(&e->hlist, head);
return e;
}
cds_hlist_add_head(&e->hlist, head);
return e;
}
if (!tp_entry)
return;
tp_entry->callsite_refcount++;
if (!tp_entry)
return;
tp_entry->callsite_refcount++;
+ e->tp_entry_callsite_ref = true;
tp_entry = get_tracepoint(e->tp->name);
if (tp_entry) {
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);
}
if (tp_entry->callsite_refcount == 0)
disable_tracepoint(e->tp);
}
if (strncmp(name, tp->name, LTTNG_UST_SYM_NAME_LEN - 1))
continue;
if (tp_entry) {
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);
set_tracepoint(&tp_entry, tp,
!!tp_entry->refcount);
} else {
disable_tracepoint(tp);
+ e->tp_entry_callsite_ref = false;
struct lttng_ust_tracepoint_probe *old;
entry = get_tracepoint(name);
struct lttng_ust_tracepoint_probe *old;
entry = get_tracepoint(name);
+ 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;
entry = add_tracepoint(name, signature);
if (IS_ERR(entry))
return (struct lttng_ust_tracepoint_probe *)entry;