[ltt-dev] [PATCH 1/2] Add a data pointer to all tracepoint probe callbacks
Mathieu Desnoyers
compudj at krystal.dyndns.org
Thu Sep 2 09:52:05 EDT 2010
* Nils Carlson (nils.carlson at ericsson.com) wrote:
> RCU now dereferences an array of probe structs containing data pointers and
> function pointers, and passes the data pointer as the first argument to the
> probe.
>
> Due to this change void prototypes are no longer allowed, which has incurred
> changes to libust-initializer.c .
>
> This patch also fixes a problem where non-existent tracepoints are present
> in the __tracepoints section and with a name pointer pointing at NULL.
Thanks!
Acked-by: Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
> ---
> include/ust/tracepoint.h | 68 +++++++++++++++++++++---------
> include/ust/ust_trace.h | 5 +-
> lgpl-relicensing.txt | 1 +
> libust-initializer.c | 5 +-
> libust/tracepoint.c | 103 ++++++++++++++++++++++++++-------------------
> 5 files changed, 113 insertions(+), 69 deletions(-)
>
> diff --git a/include/ust/tracepoint.h b/include/ust/tracepoint.h
> index 1a91b79..9c7c091 100644
> --- a/include/ust/tracepoint.h
> +++ b/include/ust/tracepoint.h
> @@ -33,10 +33,15 @@
> struct module;
> struct tracepoint;
>
> +struct probe {
> + void *func;
> + void *data;
> +};
> +
> struct tracepoint {
> const char *name; /* Tracepoint name */
> DEFINE_IMV(char, state); /* State. */
> - void **funcs;
> + struct probe *probes;
> } __attribute__((aligned(32))); /*
> * Aligned on 32 bytes because it is
> * globally visible and gcc happily
> @@ -58,16 +63,20 @@ struct tracepoint {
> */
> #define __DO_TRACE(tp, proto, args) \
> do { \
> - void **it_func; \
> + struct probe *it_probe_ptr; \
> + void *it_func; \
> + void *__data; \
> \
> - rcu_read_lock(); /*ust rcu_read_lock_sched_notrace(); */ \
> - it_func = rcu_dereference((tp)->funcs); \
> - if (it_func) { \
> + rcu_read_lock(); \
> + it_probe_ptr = rcu_dereference((tp)->probes); \
> + if (it_probe_ptr) { \
> do { \
> - ((void(*)(proto))(*it_func))(args); \
> - } while (*(++it_func)); \
> + it_func = (it_probe_ptr)->func; \
> + __data = (it_probe_ptr)->data; \
> + ((void(*)(proto))(it_func))(args); \
> + } while ((++it_probe_ptr)->func); \
> } \
> - rcu_read_unlock(); /*ust rcu_read_unlock_sched_notrace(); */ \
> + rcu_read_unlock(); \
> } while (0)
>
> #define __CHECK_TRACE(name, generic, proto, args) \
> @@ -93,37 +102,47 @@ struct tracepoint {
> * If generic is true, a variable read is used.
> * If generic is false, immediate values are used.
> */
> -#define DECLARE_TRACE(name, proto, args) \
> +#define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \
> extern struct tracepoint __tracepoint_##name; \
> static inline void trace_##name(proto) \
> { \
> - __CHECK_TRACE(name, 0, TP_PROTO(proto), TP_ARGS(args)); \
> + __CHECK_TRACE(name, 0, TP_PROTO(data_proto), \
> + TP_ARGS(data_args)); \
> } \
> static inline void _trace_##name(proto) \
> { \
> - __CHECK_TRACE(name, 1, TP_PROTO(proto), TP_ARGS(args)); \
> + __CHECK_TRACE(name, 1, TP_PROTO(data_proto), \
> + TP_ARGS(data_args)); \
> } \
> - static inline int register_trace_##name(void (*probe)(proto)) \
> + static inline int \
> + register_trace_##name(void (*probe)(data_proto), void *data) \
> { \
> - return tracepoint_probe_register(#name, (void *)probe); \
> + return tracepoint_probe_register(#name, (void *)probe, \
> + data); \
> + \
> } \
> - static inline int unregister_trace_##name(void (*probe)(proto)) \
> + static inline int \
> + unregister_trace_##name(void (*probe)(data_proto), void *data) \
> { \
> - return tracepoint_probe_unregister(#name, (void *)probe);\
> + return tracepoint_probe_unregister(#name, (void *)probe, \
> + data); \
> }
>
> -#define DEFINE_TRACE(name) \
> +#define DEFINE_TRACE_FN(name, reg, unreg) \
> static const char __tpstrtab_##name[] \
> __attribute__((section("__tracepoints_strings"))) = #name; \
> struct tracepoint __tracepoint_##name \
> __attribute__((section("__tracepoints"), aligned(32))) = \
> { __tpstrtab_##name, 0, NULL }
>
> +#define DEFINE_TRACE(name) \
> + DEFINE_TRACE_FN(name, NULL, NULL);
> +
> extern void tracepoint_update_probe_range(struct tracepoint *begin,
> struct tracepoint *end);
>
> #else /* !CONFIG_TRACEPOINTS */
> -#define DECLARE_TRACE(name, proto, args) \
> +#define __DECLARE_TRACE(name, proto, args) \
> static inline void trace_##name(proto) \
> { } \
> static inline void _trace_##name(proto) \
> @@ -146,20 +165,27 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
> { }
> #endif /* CONFIG_TRACEPOINTS */
>
> +#define DECLARE_TRACE(name, proto, args) \
> + __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \
> + PARAMS(void *__data, proto), \
> + PARAMS(__data, args))
> +
> /*
> * Connect a probe to a tracepoint.
> * Internal API, should not be used directly.
> */
> -extern int tracepoint_probe_register(const char *name, void *probe);
> +extern int tracepoint_probe_register(const char *name, void *probe, void *data);
>
> /*
> * Disconnect a probe from a tracepoint.
> * Internal API, should not be used directly.
> */
> -extern int tracepoint_probe_unregister(const char *name, void *probe);
> +extern int tracepoint_probe_unregister(const char *name, void *probe, void *data);
>
> -extern int tracepoint_probe_register_noupdate(const char *name, void *probe);
> -extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe);
> +extern int tracepoint_probe_register_noupdate(const char *name, void *probe,
> + void *data);
> +extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
> + void *data);
> extern void tracepoint_probe_update_all(void);
>
> struct tracepoint_iter {
> diff --git a/include/ust/ust_trace.h b/include/ust/ust_trace.h
> index 098c5f8..e1b0257 100644
> --- a/include/ust/ust_trace.h
> +++ b/include/ust/ust_trace.h
> @@ -58,7 +58,7 @@
> struct trace_raw_##name { \
> tstruct \
> }; \
> - static void trace_printf_##name(proto) \
> + static void trace_printf_##name(void *dummy, proto) \
> { \
> struct trace_raw_##name entry_struct, *__entry; \
> __entry = &entry_struct; \
> @@ -68,8 +68,9 @@
> } \
> static void __attribute__((constructor)) init_##name() \
> { \
> + void *dummy; \
> printf("connecting tracepoint " #name "\n"); \
> - register_trace_##name(trace_printf_##name); \
> + register_trace_##name(trace_printf_##name, dummy); \
> }
>
>
> diff --git a/lgpl-relicensing.txt b/lgpl-relicensing.txt
> index 0393851..753f453 100644
> --- a/lgpl-relicensing.txt
> +++ b/lgpl-relicensing.txt
> @@ -10,6 +10,7 @@ Steven Rostedt <rostedt at goodmis.org>
> Frederic Weisbecker <fweisbec at gmail.com>
> Xiao Guangrong <xiaogunagrong at cn.fujitsu.com>
> Josh Stone <jistone at redhat.com>
> +Lai Jiangshan <laijs at cn.fujitsu.com>
>
> The following copyright holders have agreed to LGPLv2.1+ re-licensing
> of their contributions to linux/include/stringify.h.
> diff --git a/libust-initializer.c b/libust-initializer.c
> index ec39932..390218e 100644
> --- a/libust-initializer.c
> +++ b/libust-initializer.c
> @@ -18,13 +18,14 @@
> * avoid this.
> */
>
> -DECLARE_TRACE(ust_dummytp, TP_PROTO(void), TP_ARGS());
> +DECLARE_TRACE(ust_dummytp, TP_PROTO(int anint), TP_ARGS(anint));
> DEFINE_TRACE(ust_dummytp);
>
> void dummy_libust_initializer_func(void)
> {
> + int i;
> trace_mark(ust, dummymark, MARK_NOARGS);
> - trace_ust_dummytp();
> + trace_ust_dummytp(i);
> }
>
> MARKER_LIB;
> diff --git a/libust/tracepoint.c b/libust/tracepoint.c
> index 6155e29..620a009 100644
> --- a/libust/tracepoint.c
> +++ b/libust/tracepoint.c
> @@ -59,7 +59,7 @@ static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
> */
> struct tracepoint_entry {
> struct hlist_node hlist;
> - void **funcs;
> + struct probe *probes;
> int refcount; /* Number of times armed. 0 if disarmed. */
> char name[0];
> };
> @@ -69,12 +69,12 @@ struct tp_probes {
> //ust// struct rcu_head rcu;
> struct list_head list;
> } u;
> - void *probes[0];
> + struct probe probes[0];
> };
>
> static inline void *allocate_probes(int count)
> {
> - struct tp_probes *p = malloc(count * sizeof(void *)
> + struct tp_probes *p = malloc(count * sizeof(struct probe)
> + sizeof(struct tp_probes));
> return p == NULL ? NULL : p->probes;
> }
> @@ -99,27 +99,29 @@ static void debug_print_probes(struct tracepoint_entry *entry)
> {
> int i;
>
> - if (!tracepoint_debug || !entry->funcs)
> + if (!tracepoint_debug || !entry->probes)
> return;
>
> - for (i = 0; entry->funcs[i]; i++)
> - DBG("Probe %d : %p", i, entry->funcs[i]);
> + for (i = 0; entry->probes[i].func; i++)
> + DBG("Probe %d : %p", i, entry->probes[i].func);
> }
>
> static void *
> -tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
> +tracepoint_entry_add_probe(struct tracepoint_entry *entry,
> + void *probe, void *data)
> {
> int nr_probes = 0;
> - void **old, **new;
> + struct probe *old, *new;
>
> WARN_ON(!probe);
>
> debug_print_probes(entry);
> - old = entry->funcs;
> + old = entry->probes;
> if (old) {
> /* (N -> N+1), (N != 0, 1) probes */
> - for (nr_probes = 0; old[nr_probes]; nr_probes++)
> - if (old[nr_probes] == probe)
> + for (nr_probes = 0; old[nr_probes].func; nr_probes++)
> + if (old[nr_probes].func == probe &&
> + old[nr_probes].data == data)
> return ERR_PTR(-EEXIST);
> }
> /* + 2 : one for new probe, one for NULL func */
> @@ -127,36 +129,40 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
> if (new == NULL)
> return ERR_PTR(-ENOMEM);
> if (old)
> - memcpy(new, old, nr_probes * sizeof(void *));
> - new[nr_probes] = probe;
> - new[nr_probes + 1] = NULL;
> + memcpy(new, old, nr_probes * sizeof(struct probe));
> + new[nr_probes].func = probe;
> + new[nr_probes].data = data;
> + new[nr_probes + 1].func = NULL;
> entry->refcount = nr_probes + 1;
> - entry->funcs = new;
> + entry->probes = new;
> debug_print_probes(entry);
> return old;
> }
>
> static void *
> -tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
> +tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe,
> + void *data)
> {
> int nr_probes = 0, nr_del = 0, i;
> - void **old, **new;
> + struct probe *old, *new;
>
> - old = entry->funcs;
> + old = entry->probes;
>
> if (!old)
> return ERR_PTR(-ENOENT);
>
> debug_print_probes(entry);
> /* (N -> M), (N > 1, M >= 0) probes */
> - for (nr_probes = 0; old[nr_probes]; nr_probes++) {
> - if ((!probe || old[nr_probes] == probe))
> + 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 (nr_probes - nr_del == 0) {
> /* N -> 0, (N > 1) */
> - entry->funcs = NULL;
> + entry->probes = NULL;
> entry->refcount = 0;
> debug_print_probes(entry);
> return old;
> @@ -167,12 +173,13 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
> new = allocate_probes(nr_probes - nr_del + 1);
> if (new == NULL)
> return ERR_PTR(-ENOMEM);
> - for (i = 0; old[i]; i++)
> - if ((probe && old[i] != probe))
> + for (i = 0; old[i].func; i++)
> + if (probe &&
> + (old[i].func != probe || old[i].data != data))
> new[j++] = old[i];
> - new[nr_probes - nr_del] = NULL;
> + new[nr_probes - nr_del].func = NULL;
> entry->refcount = nr_probes - nr_del;
> - entry->funcs = new;
> + entry->probes = new;
> }
> debug_print_probes(entry);
> return old;
> @@ -225,7 +232,7 @@ static struct tracepoint_entry *add_tracepoint(const char *name)
> if (!e)
> return ERR_PTR(-ENOMEM);
> memcpy(&e->name[0], name, name_len);
> - e->funcs = NULL;
> + e->probes = NULL;
> e->refcount = 0;
> hlist_add_head(&e->hlist, head);
> return e;
> @@ -256,7 +263,7 @@ static void set_tracepoint(struct tracepoint_entry **entry,
> * include/linux/tracepoints.h. A matching smp_read_barrier_depends()
> * is used.
> */
> - rcu_assign_pointer(elem->funcs, (*entry)->funcs);
> + rcu_assign_pointer(elem->probes, (*entry)->probes);
> elem->state__imv = active;
> }
>
> @@ -269,7 +276,7 @@ static void set_tracepoint(struct tracepoint_entry **entry,
> static void disable_tracepoint(struct tracepoint *elem)
> {
> elem->state__imv = 0;
> - rcu_assign_pointer(elem->funcs, NULL);
> + rcu_assign_pointer(elem->probes, NULL);
> }
>
> /**
> @@ -280,13 +287,17 @@ static void disable_tracepoint(struct tracepoint *elem)
> * Updates the probe callback corresponding to a range of tracepoints.
> */
> void tracepoint_update_probe_range(struct tracepoint *begin,
> - struct tracepoint *end)
> + struct tracepoint *end)
> {
> struct tracepoint *iter;
> struct tracepoint_entry *mark_entry;
>
> pthread_mutex_lock(&tracepoints_mutex);
> for (iter = begin; iter < end; iter++) {
> + if (!iter->name) {
> + disable_tracepoint(iter);
> + continue;
> + }
> mark_entry = get_tracepoint(iter->name);
> if (mark_entry) {
> set_tracepoint(&mark_entry, iter,
> @@ -324,18 +335,19 @@ static void tracepoint_update_probes(void)
> //ust// module_imv_update();
> }
>
> -static void *tracepoint_add_probe(const char *name, void *probe)
> +static struct probe *
> +tracepoint_add_probe(const char *name, void *probe, void *data)
> {
> struct tracepoint_entry *entry;
> - void *old;
> + struct probe *old;
>
> entry = get_tracepoint(name);
> if (!entry) {
> entry = add_tracepoint(name);
> if (IS_ERR(entry))
> - return entry;
> + return (struct probe *)entry;
> }
> - old = tracepoint_entry_add_probe(entry, probe);
> + old = tracepoint_entry_add_probe(entry, probe, data);
> if (IS_ERR(old) && !entry->refcount)
> remove_tracepoint(entry);
> return old;
> @@ -349,12 +361,12 @@ static void *tracepoint_add_probe(const char *name, void *probe)
> * Returns 0 if ok, error value on error.
> * The probe address must at least be aligned on the architecture pointer size.
> */
> -int tracepoint_probe_register(const char *name, void *probe)
> +int tracepoint_probe_register(const char *name, void *probe, void *data)
> {
> void *old;
>
> pthread_mutex_lock(&tracepoints_mutex);
> - old = tracepoint_add_probe(name, probe);
> + old = tracepoint_add_probe(name, probe, data);
> pthread_mutex_unlock(&tracepoints_mutex);
> if (IS_ERR(old))
> return PTR_ERR(old);
> @@ -365,7 +377,7 @@ int tracepoint_probe_register(const char *name, void *probe)
> }
> //ust// EXPORT_SYMBOL_GPL(tracepoint_probe_register);
>
> -static void *tracepoint_remove_probe(const char *name, void *probe)
> +static void *tracepoint_remove_probe(const char *name, void *probe, void *data)
> {
> struct tracepoint_entry *entry;
> void *old;
> @@ -373,7 +385,7 @@ static void *tracepoint_remove_probe(const char *name, void *probe)
> entry = get_tracepoint(name);
> if (!entry)
> return ERR_PTR(-ENOENT);
> - old = tracepoint_entry_remove_probe(entry, probe);
> + old = tracepoint_entry_remove_probe(entry, probe, data);
> if (IS_ERR(old))
> return old;
> if (!entry->refcount)
> @@ -385,18 +397,19 @@ static void *tracepoint_remove_probe(const char *name, void *probe)
> * tracepoint_probe_unregister - Disconnect a probe from a tracepoint
> * @name: tracepoint name
> * @probe: probe function pointer
> + * @probe: probe data pointer
> *
> * We do not need to call a synchronize_sched to make sure the probes have
> * finished running before doing a module unload, because the module unload
> * itself uses stop_machine(), which insures that every preempt disabled section
> * have finished.
> */
> -int tracepoint_probe_unregister(const char *name, void *probe)
> +int tracepoint_probe_unregister(const char *name, void *probe, void *data)
> {
> void *old;
>
> pthread_mutex_lock(&tracepoints_mutex);
> - old = tracepoint_remove_probe(name, probe);
> + old = tracepoint_remove_probe(name, probe, data);
> pthread_mutex_unlock(&tracepoints_mutex);
> if (IS_ERR(old))
> return PTR_ERR(old);
> @@ -427,12 +440,13 @@ static void tracepoint_add_old_probes(void *old)
> *
> * caller must call tracepoint_probe_update_all()
> */
> -int tracepoint_probe_register_noupdate(const char *name, void *probe)
> +int tracepoint_probe_register_noupdate(const char *name, void *probe,
> + void *data)
> {
> void *old;
>
> pthread_mutex_lock(&tracepoints_mutex);
> - old = tracepoint_add_probe(name, probe);
> + old = tracepoint_add_probe(name, probe, data);
> if (IS_ERR(old)) {
> pthread_mutex_unlock(&tracepoints_mutex);
> return PTR_ERR(old);
> @@ -450,12 +464,13 @@ int tracepoint_probe_register_noupdate(const char *name, void *probe)
> *
> * caller must call tracepoint_probe_update_all()
> */
> -int tracepoint_probe_unregister_noupdate(const char *name, void *probe)
> +int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
> + void *data)
> {
> void *old;
>
> pthread_mutex_lock(&tracepoints_mutex);
> - old = tracepoint_remove_probe(name, probe);
> + old = tracepoint_remove_probe(name, probe, data);
> if (IS_ERR(old)) {
> pthread_mutex_unlock(&tracepoints_mutex);
> return PTR_ERR(old);
> @@ -662,7 +677,7 @@ int tracepoint_register_lib(struct tracepoint *tracepoints_start, int tracepoint
> lib_update_tracepoints();
>
> DBG("just registered a tracepoints section from %p and having %d tracepoints", tracepoints_start, tracepoints_count);
> -
> +
> return 0;
> }
>
> --
> 1.7.1
>
>
> _______________________________________________
> ltt-dev mailing list
> ltt-dev at lists.casi.polymtl.ca
> http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
>
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
More information about the lttng-dev
mailing list