X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=liblttng-ust%2Ftracepoint.c;h=5fd1126aa42d3b03c5709994aaad61c4ddaa11ae;hb=05523fbf3fa3af6247a048c32d219b07bd65fd1a;hp=3a50df66a08de552256a342987c153dbcdd701e0;hpb=efa2c5917d9fb8dc40114e35b0da6916cc1d0422;p=lttng-ust.git diff --git a/liblttng-ust/tracepoint.c b/liblttng-ust/tracepoint.c index 3a50df66..5fd1126a 100644 --- a/liblttng-ust/tracepoint.c +++ b/liblttng-ust/tracepoint.c @@ -23,47 +23,63 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include /* for LTTNG_UST_SYM_NAME_LEN */ #include #include #include "tracepoint-internal.h" -#include "ltt-tracer-core.h" +#include "lttng-tracer-core.h" #include "jhash.h" #include "error.h" /* Set to 1 to enable tracepoint debug output */ static const int tracepoint_debug; static int initialized; -static void (*new_tracepoint_cb)(struct tracepoint *); +static void (*new_tracepoint_cb)(struct lttng_ust_tracepoint *); + +/* + * tracepoint_mutex nests inside UST mutex. + * + * Note about interaction with fork/clone: UST does not hold the + * tracepoint mutex across fork/clone because it is either: + * - nested within UST mutex, in which case holding the UST mutex across + * fork/clone suffice, + * - taken by a library constructor, which should never race with a + * fork/clone if the application is expected to continue running with + * the same memory layout (no following exec()). + */ +static pthread_mutex_t tracepoint_mutex = PTHREAD_MUTEX_INITIALIZER; /* * libraries that contain tracepoints (struct tracepoint_lib). - * Protected by UST lock. + * Protected by tracepoint mutex. */ static CDS_LIST_HEAD(libs); /* - * The UST lock protects the library tracepoints, the hash table, and + * The tracepoint mutex protects the library tracepoints, the hash table, and * the library list. - * All calls to the tracepoint API must be protected by the UST lock, + * All calls to the tracepoint API must be protected by the tracepoint mutex, * excepts calls to tracepoint_register_lib and - * tracepoint_unregister_lib, which take the UST lock themselves. + * tracepoint_unregister_lib, which take the tracepoint mutex themselves. */ /* * Tracepoint hash table, containing the active tracepoints. - * Protected by ust lock. + * Protected by tracepoint mutex. */ -#define TRACEPOINT_HASH_BITS 6 +#define TRACEPOINT_HASH_BITS 12 #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; @@ -74,29 +90,50 @@ static int need_update; * Note about RCU : * It is used to to delay the free of multiple probes array until a quiescent * state is reached. - * Tracepoint entries modifications are protected by the ust lock. + * Tracepoint entries modifications are protected by the tracepoint mutex. */ struct tracepoint_entry { struct cds_hlist_node hlist; - struct tracepoint_probe *probes; + 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]; }; struct tp_probes { union { struct cds_list_head list; + /* Field below only used for call_rcu scheme */ + /* struct rcu_head head; */ } u; - struct tracepoint_probe probes[0]; + struct lttng_ust_tracepoint_probe probes[0]; +}; + +/* + * Callsite hash table, containing the tracepoint call sites. + * Protected by tracepoint mutex. + */ +#define CALLSITE_HASH_BITS 12 +#define CALLSITE_TABLE_SIZE (1 << CALLSITE_HASH_BITS) +static struct cds_hlist_head callsite_table[CALLSITE_TABLE_SIZE]; + +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; }; +/* coverity[+alloc] */ static void *allocate_probes(int count) { - struct tp_probes *p = zmalloc(count * sizeof(struct tracepoint_probe) - + sizeof(struct tp_probes)); + struct tp_probes *p = + zmalloc(count * sizeof(struct lttng_ust_tracepoint_probe) + + sizeof(struct tp_probes)); return p == NULL ? NULL : p->probes; } +/* coverity[+free : arg-0] */ static void release_probes(void *old) { if (old) { @@ -120,13 +157,15 @@ static void debug_print_probes(struct tracepoint_entry *entry) static void * tracepoint_entry_add_probe(struct tracepoint_entry *entry, - void *probe, void *data) + void (*probe)(void), void *data) { int nr_probes = 0; - struct tracepoint_probe *old, *new; - - WARN_ON(!probe); + struct lttng_ust_tracepoint_probe *old, *new; + if (!probe) { + WARN_ON(1); + return ERR_PTR(-EINVAL); + } debug_print_probes(entry); old = entry->probes; if (old) { @@ -141,7 +180,8 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, if (new == NULL) return ERR_PTR(-ENOMEM); if (old) - memcpy(new, old, nr_probes * sizeof(struct tracepoint_probe)); + memcpy(new, old, + nr_probes * sizeof(struct lttng_ust_tracepoint_probe)); new[nr_probes].func = probe; new[nr_probes].data = data; new[nr_probes + 1].func = NULL; @@ -152,11 +192,11 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, } static void * -tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe, - void *data) +tracepoint_entry_remove_probe(struct tracepoint_entry *entry, + void (*probe)(void), void *data) { int nr_probes = 0, nr_del = 0, i; - struct tracepoint_probe *old, *new; + struct lttng_ust_tracepoint_probe *old, *new; old = entry->probes; @@ -165,11 +205,12 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe, debug_print_probes(entry); /* (N -> M), (N > 1, M >= 0) probes */ - for (nr_probes = 0; old[nr_probes].func; nr_probes++) { - if (!probe || - (old[nr_probes].func == probe && - old[nr_probes].data == data)) - nr_del++; + if (probe) { + for (nr_probes = 0; old[nr_probes].func; nr_probes++) { + if (old[nr_probes].func == probe && + old[nr_probes].data == data) + nr_del++; + } } if (nr_probes - nr_del == 0) { @@ -186,8 +227,7 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe, if (new == NULL) return ERR_PTR(-ENOMEM); for (i = 0; old[i].func; i++) - if (probe && - (old[i].func != probe || old[i].data != data)) + if (old[i].func != probe || old[i].data != data) new[j++] = old[i]; new[nr_probes - nr_del].func = NULL; entry->refcount = nr_probes - nr_del; @@ -199,7 +239,7 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe, /* * Get tracepoint if the tracepoint is present in the tracepoint hash table. - * Must be called with ust lock held. + * Must be called with tracepoint mutex held. * Returns NULL if not present. */ static struct tracepoint_entry *get_tracepoint(const char *name) @@ -207,11 +247,17 @@ static struct tracepoint_entry *get_tracepoint(const char *name) struct cds_hlist_head *head; struct cds_hlist_node *node; struct tracepoint_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 tracepoint 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 = &tracepoint_table[hash & (TRACEPOINT_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; @@ -219,19 +265,25 @@ static struct tracepoint_entry *get_tracepoint(const char *name) /* * Add the tracepoint to the tracepoint hash table. Must be called with - * ust lock held. + * tracepoint mutex held. */ -static struct tracepoint_entry *add_tracepoint(const char *name) +static struct tracepoint_entry *add_tracepoint(const char *name, + const char *signature) { struct cds_hlist_head *head; struct cds_hlist_node *node; struct tracepoint_entry *e; - size_t name_len = strlen(name) + 1; - uint32_t hash = jhash(name, name_len-1, 0); + size_t name_len = strlen(name); + uint32_t hash; + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating tracepoint 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 = &tracepoint_table[hash & (TRACEPOINT_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)) { DBG("tracepoint %s busy", name); return ERR_PTR(-EEXIST); /* Already there */ } @@ -240,19 +292,22 @@ static struct tracepoint_entry *add_tracepoint(const char *name) * Using zmalloc here to allocate a variable length element. Could * cause some memory fragmentation if overused. */ - e = zmalloc(sizeof(struct tracepoint_entry) + name_len); + e = zmalloc(sizeof(struct tracepoint_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'; e->probes = NULL; e->refcount = 0; + e->callsite_refcount = 0; + e->signature = signature; cds_hlist_add_head(&e->hlist, head); return e; } /* * Remove the tracepoint from the tracepoint hash table. Must be called with - * ust_lock held. + * tracepoint mutex held. */ static void remove_tracepoint(struct tracepoint_entry *e) { @@ -264,9 +319,26 @@ static void remove_tracepoint(struct tracepoint_entry *e) * Sets the probe callback corresponding to one tracepoint. */ static void set_tracepoint(struct tracepoint_entry **entry, - struct tracepoint *elem, int active) + struct lttng_ust_tracepoint *elem, int active) { - WARN_ON(strcmp((*entry)->name, elem->name) != 0); + WARN_ON(strncmp((*entry)->name, elem->name, LTTNG_UST_SYM_NAME_LEN - 1) != 0); + /* + * Check that signatures match before connecting a probe to a + * tracepoint. Warn the user if they don't. + */ + if (strcmp(elem->signature, (*entry)->signature) != 0) { + static int warned = 0; + + /* Only print once, don't flood console. */ + if (!warned) { + WARN("Tracepoint signature mismatch, not enabling one or more tracepoints. Ensure that the tracepoint probes prototypes match the application."); + WARN("Tracepoint \"%s\" signatures: call: \"%s\" vs probe: \"%s\".", + elem->name, elem->signature, (*entry)->signature); + warned = 1; + } + /* Don't accept connecting non-matching signatures. */ + return; + } /* * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new @@ -276,7 +348,7 @@ static void set_tracepoint(struct tracepoint_entry **entry, * is used. */ rcu_assign_pointer(elem->probes, (*entry)->probes); - elem->state = active; + CMM_STORE_SHARED(elem->state, active); } /* @@ -285,12 +357,100 @@ static void set_tracepoint(struct tracepoint_entry **entry, * function insures that the original callback is not used anymore. This insured * by preempt_disable around the call site. */ -static void disable_tracepoint(struct tracepoint *elem) +static void disable_tracepoint(struct lttng_ust_tracepoint *elem) { - elem->state = 0; + CMM_STORE_SHARED(elem->state, 0); rcu_assign_pointer(elem->probes, NULL); } +/* + * Add the callsite to the callsite hash table. Must be called with + * tracepoint mutex held. + */ +static void add_callsite(struct tracepoint_lib * lib, struct lttng_ust_tracepoint *tp) +{ + struct cds_hlist_head *head; + struct callsite_entry *e; + const char *name = tp->name; + size_t name_len = strlen(name); + uint32_t hash; + struct tracepoint_entry *tp_entry; + + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating tracepoint 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 = &callsite_table[hash & (CALLSITE_TABLE_SIZE - 1)]; + e = zmalloc(sizeof(struct callsite_entry)); + if (!e) { + PERROR("Unable to add callsite for tracepoint \"%s\"", name); + return; + } + cds_hlist_add_head(&e->hlist, head); + e->tp = tp; + cds_list_add(&e->node, &lib->callsites); + + tp_entry = get_tracepoint(name); + if (!tp_entry) + return; + tp_entry->callsite_refcount++; +} + +/* + * Remove the callsite from the callsite hash table and from lib + * callsite list. Must be called with tracepoint mutex held. + */ +static void remove_callsite(struct callsite_entry *e) +{ + struct tracepoint_entry *tp_entry; + + tp_entry = get_tracepoint(e->tp->name); + if (tp_entry) { + tp_entry->callsite_refcount--; + if (tp_entry->callsite_refcount == 0) + disable_tracepoint(e->tp); + } + cds_hlist_del(&e->hlist); + cds_list_del(&e->node); + free(e); +} + +/* + * Enable/disable all callsites based on the state of a specific + * tracepoint entry. + * Must be called with tracepoint mutex held. + */ +static void tracepoint_sync_callsites(const char *name) +{ + struct cds_hlist_head *head; + struct cds_hlist_node *node; + struct callsite_entry *e; + size_t name_len = strlen(name); + uint32_t hash; + struct tracepoint_entry *tp_entry; + + tp_entry = get_tracepoint(name); + if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) { + WARN("Truncating tracepoint 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 = &callsite_table[hash & (CALLSITE_TABLE_SIZE - 1)]; + cds_hlist_for_each_entry(e, node, head, hlist) { + struct lttng_ust_tracepoint *tp = e->tp; + + if (strncmp(name, tp->name, LTTNG_UST_SYM_NAME_LEN - 1)) + continue; + if (tp_entry) { + set_tracepoint(&tp_entry, tp, + !!tp_entry->refcount); + } else { + disable_tracepoint(tp); + } + } +} + /** * tracepoint_update_probe_range - Update a probe range * @begin: beginning of the range @@ -299,10 +459,10 @@ static void disable_tracepoint(struct tracepoint *elem) * Updates the probe callback corresponding to a range of tracepoints. */ static -void tracepoint_update_probe_range(struct tracepoint * const *begin, - struct tracepoint * const *end) +void tracepoint_update_probe_range(struct lttng_ust_tracepoint * const *begin, + struct lttng_ust_tracepoint * const *end) { - struct tracepoint * const *iter; + struct lttng_ust_tracepoint * const *iter; struct tracepoint_entry *mark_entry; for (iter = begin; iter < end; iter++) { @@ -322,36 +482,63 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin, } } -static void lib_update_tracepoints(void) +static void lib_update_tracepoints(struct tracepoint_lib *lib) { - struct tracepoint_lib *lib; + tracepoint_update_probe_range(lib->tracepoints_start, + lib->tracepoints_start + lib->tracepoints_count); +} - cds_list_for_each_entry(lib, &libs, list) { - tracepoint_update_probe_range(lib->tracepoints_start, - lib->tracepoints_start + lib->tracepoints_count); +static void lib_register_callsites(struct tracepoint_lib *lib) +{ + struct lttng_ust_tracepoint * const *begin; + struct lttng_ust_tracepoint * const *end; + struct lttng_ust_tracepoint * const *iter; + + begin = lib->tracepoints_start; + end = lib->tracepoints_start + lib->tracepoints_count; + + for (iter = begin; iter < end; iter++) { + if (!*iter) + continue; /* skip dummy */ + if (!(*iter)->name) { + continue; + } + add_callsite(lib, *iter); } } +static void lib_unregister_callsites(struct tracepoint_lib *lib) +{ + struct callsite_entry *callsite, *tmp; + + cds_list_for_each_entry_safe(callsite, tmp, &lib->callsites, node) + remove_callsite(callsite); +} + /* * Update probes, removing the faulty probes. */ static void tracepoint_update_probes(void) { + struct tracepoint_lib *lib; + /* tracepoints registered from libraries and executable. */ - lib_update_tracepoints(); + cds_list_for_each_entry(lib, &libs, list) + lib_update_tracepoints(lib); } -static struct tracepoint_probe * -tracepoint_add_probe(const char *name, void *probe, void *data) +static struct lttng_ust_tracepoint_probe * +tracepoint_add_probe(const char *name, void (*probe)(void), void *data, + const char *signature) { struct tracepoint_entry *entry; - struct tracepoint_probe *old; + struct lttng_ust_tracepoint_probe *old; entry = get_tracepoint(name); if (!entry) { - entry = add_tracepoint(name); + entry = add_tracepoint(name, signature); if (IS_ERR(entry)) - return (struct tracepoint_probe *)entry; + return (struct lttng_ust_tracepoint_probe *)entry; } old = tracepoint_entry_add_probe(entry, probe, data); if (IS_ERR(old) && !entry->refcount) @@ -366,22 +553,32 @@ tracepoint_add_probe(const char *name, void *probe, void *data) * * Returns 0 if ok, error value on error. * The probe address must at least be aligned on the architecture pointer size. - * Called with the UST lock held. + * Called with the tracepoint mutex held. */ -int __tracepoint_probe_register(const char *name, void *probe, void *data) +int __tracepoint_probe_register(const char *name, void (*probe)(void), + void *data, const char *signature) { void *old; + int ret = 0; - old = tracepoint_add_probe(name, probe, data); - if (IS_ERR(old)) - return PTR_ERR(old); + DBG("Registering probe to tracepoint %s", name); + + pthread_mutex_lock(&tracepoint_mutex); + old = tracepoint_add_probe(name, probe, data, signature); + if (IS_ERR(old)) { + ret = PTR_ERR(old); + goto end; + } - tracepoint_update_probes(); /* may update entry */ + tracepoint_sync_callsites(name); release_probes(old); - return 0; +end: + pthread_mutex_unlock(&tracepoint_mutex); + return ret; } -static void *tracepoint_remove_probe(const char *name, void *probe, void *data) +static void *tracepoint_remove_probe(const char *name, void (*probe)(void), + void *data) { struct tracepoint_entry *entry; void *old; @@ -402,20 +599,26 @@ static void *tracepoint_remove_probe(const char *name, void *probe, void *data) * @name: tracepoint name * @probe: probe function pointer * @probe: probe data pointer - * - * Called with the UST lock held. */ -int __tracepoint_probe_unregister(const char *name, void *probe, void *data) +int __tracepoint_probe_unregister(const char *name, void (*probe)(void), + void *data) { void *old; + int ret = 0; - old = tracepoint_remove_probe(name, probe, data); - if (IS_ERR(old)) - return PTR_ERR(old); + DBG("Un-registering probe from tracepoint %s", name); - tracepoint_update_probes(); /* may update entry */ + pthread_mutex_lock(&tracepoint_mutex); + old = tracepoint_remove_probe(name, probe, data); + if (IS_ERR(old)) { + ret = PTR_ERR(old); + goto end; + } + tracepoint_sync_callsites(name); release_probes(old); - return 0; +end: + pthread_mutex_unlock(&tracepoint_mutex); + return ret; } static void tracepoint_add_old_probes(void *old) @@ -434,19 +637,23 @@ static void tracepoint_add_old_probes(void *old) * @probe: probe handler * * caller must call tracepoint_probe_update_all() - * Called with the UST lock held. */ -int tracepoint_probe_register_noupdate(const char *name, void *probe, - void *data) +int tracepoint_probe_register_noupdate(const char *name, void (*probe)(void), + void *data, const char *signature) { void *old; + int ret = 0; - old = tracepoint_add_probe(name, probe, data); + pthread_mutex_lock(&tracepoint_mutex); + old = tracepoint_add_probe(name, probe, data, signature); if (IS_ERR(old)) { - return PTR_ERR(old); + ret = PTR_ERR(old); + goto end; } tracepoint_add_old_probes(old); - return 0; +end: + pthread_mutex_unlock(&tracepoint_mutex); + return ret; } /** @@ -455,32 +662,39 @@ int tracepoint_probe_register_noupdate(const char *name, void *probe, * @probe: probe function pointer * * caller must call tracepoint_probe_update_all() - * Called with the UST lock held. + * Called with the tracepoint mutex held. */ -int tracepoint_probe_unregister_noupdate(const char *name, void *probe, +int tracepoint_probe_unregister_noupdate(const char *name, void (*probe)(void), void *data) { void *old; + int ret = 0; + DBG("Un-registering probe from tracepoint %s", name); + + pthread_mutex_lock(&tracepoint_mutex); old = tracepoint_remove_probe(name, probe, data); if (IS_ERR(old)) { - return PTR_ERR(old); + ret = PTR_ERR(old); + goto end; } tracepoint_add_old_probes(old); - return 0; +end: + pthread_mutex_unlock(&tracepoint_mutex); + return ret; } /** * tracepoint_probe_update_all - update tracepoints - * Called with the UST lock held. */ void tracepoint_probe_update_all(void) { CDS_LIST_HEAD(release_probes); struct tp_probes *pos, *next; + pthread_mutex_lock(&tracepoint_mutex); if (!need_update) { - return; + goto end; } if (!cds_list_empty(&old_probes)) cds_list_replace_init(&old_probes, &release_probes); @@ -492,17 +706,20 @@ void tracepoint_probe_update_all(void) synchronize_rcu(); free(pos); } +end: + pthread_mutex_unlock(&tracepoint_mutex); } -void tracepoint_set_new_tracepoint_cb(void (*cb)(struct tracepoint *)) +void tracepoint_set_new_tracepoint_cb(void (*cb)(struct lttng_ust_tracepoint *)) { new_tracepoint_cb = cb; } -static void new_tracepoints(struct tracepoint * const *start, struct tracepoint * const *end) +static void new_tracepoints(struct lttng_ust_tracepoint * const *start, + struct lttng_ust_tracepoint * const *end) { if (new_tracepoint_cb) { - struct tracepoint * const *t; + struct lttng_ust_tracepoint * const *t; for (t = start; t < end; t++) { if (*t) @@ -511,7 +728,7 @@ static void new_tracepoints(struct tracepoint * const *start, struct tracepoint } } -int tracepoint_register_lib(struct tracepoint * const *tracepoints_start, +int tracepoint_register_lib(struct lttng_ust_tracepoint * const *tracepoints_start, int tracepoints_count) { struct tracepoint_lib *pl, *iter; @@ -519,11 +736,15 @@ int tracepoint_register_lib(struct tracepoint * const *tracepoints_start, init_tracepoint(); pl = (struct tracepoint_lib *) zmalloc(sizeof(struct tracepoint_lib)); - + if (!pl) { + PERROR("Unable to register tracepoint lib"); + return -1; + } pl->tracepoints_start = tracepoints_start; pl->tracepoints_count = tracepoints_count; + CDS_INIT_LIST_HEAD(&pl->callsites); - ust_lock(); + pthread_mutex_lock(&tracepoint_mutex); /* * We sort the libs by struct lib pointer address. */ @@ -539,32 +760,46 @@ int tracepoint_register_lib(struct tracepoint * const *tracepoints_start, cds_list_add(&pl->list, &libs); lib_added: new_tracepoints(tracepoints_start, tracepoints_start + tracepoints_count); - - /* TODO: update just the loaded lib */ - lib_update_tracepoints(); - ust_unlock(); + lib_register_callsites(pl); + lib_update_tracepoints(pl); + pthread_mutex_unlock(&tracepoint_mutex); DBG("just registered a tracepoints section from %p and having %d tracepoints", tracepoints_start, tracepoints_count); + if (ust_debug()) { + int i; + + for (i = 0; i < tracepoints_count; i++) { + DBG("registered tracepoint: %s", tracepoints_start[i]->name); + } + } return 0; } -int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start) +int tracepoint_unregister_lib(struct lttng_ust_tracepoint * const *tracepoints_start) { struct tracepoint_lib *lib; - ust_lock(); + pthread_mutex_lock(&tracepoint_mutex); cds_list_for_each_entry(lib, &libs, list) { - if (lib->tracepoints_start == tracepoints_start) { - struct tracepoint_lib *lib2free = lib; - cds_list_del(&lib->list); - free(lib2free); - break; - } - } - ust_unlock(); + if (lib->tracepoints_start != tracepoints_start) + continue; + cds_list_del(&lib->list); + /* + * Unregistering a callsite also decreases the + * callsite reference count of the corresponding + * tracepoint, and disables the tracepoint if + * the reference count drops to zero. + */ + lib_unregister_callsites(lib); + DBG("just unregistered a tracepoints section from %p", + lib->tracepoints_start); + free(lib); + break; + } + pthread_mutex_unlock(&tracepoint_mutex); return 0; } @@ -579,3 +814,25 @@ void exit_tracepoint(void) { initialized = 0; } + +/* + * Create the wrapper symbols. + */ +#undef tp_rcu_read_lock_bp +#undef tp_rcu_read_unlock_bp +#undef tp_rcu_dereference_bp + +void tp_rcu_read_lock_bp(void) +{ + rcu_read_lock_bp(); +} + +void tp_rcu_read_unlock_bp(void) +{ + rcu_read_unlock_bp(); +} + +void *tp_rcu_dereference_sym_bp(void *p) +{ + return rcu_dereference_bp(p); +}