X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Ftracepoint.c;h=a93f286364550e1cf29a3388fa2f5b4a09d5adbf;hb=8c82e2da6b17493d879523b80aed11d0d250eef1;hp=f74a43b0ea67076a71c1f03b7b11976a4e3c5849;hpb=ade7037b9b18fc90eb1ab919286aaf6ea3dc96a7;p=lttng-ust.git diff --git a/liblttng-ust/tracepoint.c b/liblttng-ust/tracepoint.c index f74a43b0..a93f2863 100644 --- a/liblttng-ust/tracepoint.c +++ b/liblttng-ust/tracepoint.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -46,23 +47,36 @@ static const int tracepoint_debug; static int initialized; static void (*new_tracepoint_cb)(struct 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_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) @@ -75,12 +89,13 @@ 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; int refcount; /* Number of times armed. 0 if disarmed. */ + const char *signature; char name[0]; }; @@ -202,7 +217,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) @@ -228,9 +243,10 @@ 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; @@ -261,13 +277,14 @@ static struct tracepoint_entry *add_tracepoint(const char *name) e->name[name_len] = '\0'; e->probes = NULL; e->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) { @@ -282,6 +299,23 @@ static void set_tracepoint(struct tracepoint_entry **entry, struct tracepoint *elem, int active) { 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 @@ -357,14 +391,15 @@ static void tracepoint_update_probes(void) } static struct tracepoint_probe * -tracepoint_add_probe(const char *name, void *probe, void *data) +tracepoint_add_probe(const char *name, void *probe, void *data, + const char *signature) { struct tracepoint_entry *entry; struct 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; } @@ -381,19 +416,28 @@ 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 *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 */ 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) @@ -417,20 +461,25 @@ 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) { 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); + pthread_mutex_lock(&tracepoint_mutex); + old = tracepoint_remove_probe(name, probe, data); + if (IS_ERR(old)) { + ret = PTR_ERR(old); + goto end; + } tracepoint_update_probes(); /* may update entry */ release_probes(old); - return 0; +end: + pthread_mutex_unlock(&tracepoint_mutex); + return ret; } static void tracepoint_add_old_probes(void *old) @@ -449,19 +498,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) + 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; } /** @@ -470,32 +523,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, 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); @@ -507,6 +567,8 @@ 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 *)) @@ -552,7 +614,7 @@ int tracepoint_register_lib(struct tracepoint * const *tracepoints_start, pl->tracepoints_start = tracepoints_start; pl->tracepoints_count = tracepoints_count; - ust_lock(); + pthread_mutex_lock(&tracepoint_mutex); /* * We sort the libs by struct lib pointer address. */ @@ -571,10 +633,17 @@ lib_added: /* TODO: update just the loaded lib */ lib_update_tracepoints(); - ust_unlock(); + 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; } @@ -584,7 +653,7 @@ int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start) struct tracepoint_lib *lib; int tracepoints_count; - 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; @@ -609,7 +678,7 @@ found: DBG("just unregistered a tracepoints section from %p", tracepoints_start); end: - ust_unlock(); + pthread_mutex_unlock(&tracepoint_mutex); return 0; }