X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Ftracepoint.c;h=14b8231f879fca9d3aa8e3bde5a6a661cbb6b4c2;hb=b33b46f7161604cb9168e9bbc854413cf18269be;hp=00c471969b4394f16b9ec2e13bb520e10e78fe4b;hpb=d6297168f9042cdc550507bb5e97cee7037c34d3;p=lttng-ust.git diff --git a/liblttng-ust/tracepoint.c b/liblttng-ust/tracepoint.c index 00c47196..14b8231f 100644 --- a/liblttng-ust/tracepoint.c +++ b/liblttng-ust/tracepoint.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include /* for LTTNG_UST_SYM_NAME_LEN */ @@ -42,10 +43,17 @@ #include "jhash.h" #include "error.h" +/* Test compiler support for weak symbols with hidden visibility. */ +int __tracepoint_test_symbol1 __attribute__((weak, visibility("hidden"))); +void *__tracepoint_test_symbol2 __attribute__((weak, visibility("hidden"))); +struct { + char a[24]; +} __tracepoint_test_symbol3 __attribute__((weak, visibility("hidden"))); + /* 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. @@ -85,6 +93,9 @@ static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; static CDS_LIST_HEAD(old_probes); static int need_update; +static CDS_LIST_HEAD(release_queue); +static int release_queue_need_update; + /* * Note about RCU : * It is used to to delay the free of multiple probes array until a quiescent @@ -93,7 +104,7 @@ static int need_update; */ 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; @@ -106,7 +117,7 @@ struct tp_probes { /* 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]; }; /* @@ -120,14 +131,15 @@ 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 tracepoint *tp; + 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; } @@ -158,7 +170,7 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void (*probe)(void), void *data) { int nr_probes = 0; - struct tracepoint_probe *old, *new; + struct lttng_ust_tracepoint_probe *old, *new; if (!probe) { WARN_ON(1); @@ -178,7 +190,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; @@ -193,7 +206,7 @@ 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; @@ -316,7 +329,7 @@ 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(strncmp((*entry)->name, elem->name, LTTNG_UST_SYM_NAME_LEN - 1) != 0); /* @@ -345,7 +358,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); } /* @@ -354,9 +367,9 @@ 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); } @@ -364,7 +377,7 @@ static void disable_tracepoint(struct tracepoint *elem) * Add the callsite to the callsite hash table. Must be called with * tracepoint mutex held. */ -static void add_callsite(struct tracepoint_lib * lib, struct tracepoint *tp) +static void add_callsite(struct tracepoint_lib * lib, struct lttng_ust_tracepoint *tp) { struct cds_hlist_head *head; struct callsite_entry *e; @@ -435,7 +448,7 @@ static void tracepoint_sync_callsites(const char *name) hash = jhash(name, name_len, 0); head = &callsite_table[hash & (CALLSITE_TABLE_SIZE - 1)]; cds_hlist_for_each_entry(e, node, head, hlist) { - struct tracepoint *tp = e->tp; + struct lttng_ust_tracepoint *tp = e->tp; if (strncmp(name, tp->name, LTTNG_UST_SYM_NAME_LEN - 1)) continue; @@ -456,10 +469,10 @@ static void tracepoint_sync_callsites(const char *name) * 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++) { @@ -487,9 +500,9 @@ static void lib_update_tracepoints(struct tracepoint_lib *lib) static void lib_register_callsites(struct tracepoint_lib *lib) { - struct tracepoint * const *begin; - struct tracepoint * const *end; - struct tracepoint * const *iter; + 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; @@ -524,18 +537,18 @@ static void tracepoint_update_probes(void) lib_update_tracepoints(lib); } -static struct tracepoint_probe * +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, 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) @@ -543,6 +556,16 @@ tracepoint_add_probe(const char *name, void (*probe)(void), void *data, return old; } +static void tracepoint_release_queue_add_old_probes(void *old) +{ + release_queue_need_update = 1; + if (old) { + struct tp_probes *tp_probes = caa_container_of(old, + struct tp_probes, probes[0]); + cds_list_add(&tp_probes->u.list, &release_queue); + } +} + /** * __tracepoint_probe_register - Connect a probe to a tracepoint * @name: tracepoint name @@ -574,6 +597,33 @@ end: return ret; } +/* + * Caller needs to invoke __tracepoint_probe_release_queue() after + * calling __tracepoint_probe_register_queue_release() one or multiple + * times to ensure it does not leak memory. + */ +int __tracepoint_probe_register_queue_release(const char *name, + void (*probe)(void), void *data, const char *signature) +{ + void *old; + int ret = 0; + + DBG("Registering probe to tracepoint %s. Queuing release.", 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_sync_callsites(name); + tracepoint_release_queue_add_old_probes(old); +end: + pthread_mutex_unlock(&tracepoint_mutex); + return ret; +} + static void *tracepoint_remove_probe(const char *name, void (*probe)(void), void *data) { @@ -618,6 +668,57 @@ end: return ret; } +/* + * Caller needs to invoke __tracepoint_probe_release_queue() after + * calling __tracepoint_probe_unregister_queue_release() one or multiple + * times to ensure it does not leak memory. + */ +int __tracepoint_probe_unregister_queue_release(const char *name, + void (*probe)(void), void *data) +{ + void *old; + int ret = 0; + + DBG("Un-registering probe from tracepoint %s. Queuing release.", name); + + 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); + tracepoint_release_queue_add_old_probes(old); +end: + pthread_mutex_unlock(&tracepoint_mutex); + return ret; +} + +void __tracepoint_probe_prune_release_queue(void) +{ + CDS_LIST_HEAD(release_probes); + struct tp_probes *pos, *next; + + DBG("Release queue of unregistered tracepoint probes."); + + pthread_mutex_lock(&tracepoint_mutex); + if (!release_queue_need_update) + goto end; + if (!cds_list_empty(&release_queue)) + cds_list_replace_init(&release_queue, &release_probes); + release_queue_need_update = 0; + + /* Wait for grace period between all sync_callsites and free. */ + synchronize_rcu(); + + cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) { + cds_list_del(&pos->u.list); + free(pos); + } +end: + pthread_mutex_unlock(&tracepoint_mutex); +} + static void tracepoint_add_old_probes(void *old) { need_update = 1; @@ -698,24 +799,26 @@ void tracepoint_probe_update_all(void) need_update = 0; tracepoint_update_probes(); + /* Wait for grace period between update_probes and free. */ + synchronize_rcu(); cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) { cds_list_del(&pos->u.list); - 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) @@ -724,7 +827,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; @@ -773,7 +876,7 @@ lib_added: 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; @@ -799,11 +902,34 @@ int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start) return 0; } +/* + * Report in debug message whether the compiler correctly supports weak + * hidden symbols. This test checks that the address associated with two + * weak symbols with hidden visibility is the same when declared within + * two compile units part of the same module. + */ +static void check_weak_hidden(void) +{ + DBG("Your compiler treats weak symbols with hidden visibility for integer objects as %s between compile units part of the same module.", + &__tracepoint_test_symbol1 == lttng_ust_tp_check_weak_hidden1() ? + "SAME address" : + "DIFFERENT addresses"); + DBG("Your compiler treats weak symbols with hidden visibility for pointer objects as %s between compile units part of the same module.", + &__tracepoint_test_symbol2 == lttng_ust_tp_check_weak_hidden2() ? + "SAME address" : + "DIFFERENT addresses"); + DBG("Your compiler treats weak symbols with hidden visibility for 24-byte structure objects as %s between compile units part of the same module.", + &__tracepoint_test_symbol3 == lttng_ust_tp_check_weak_hidden3() ? + "SAME address" : + "DIFFERENT addresses"); +} + void init_tracepoint(void) { if (uatomic_xchg(&initialized, 1) == 1) return; init_usterr(); + check_weak_hidden(); } void exit_tracepoint(void)