summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
6749958)
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.
struct module;
struct tracepoint;
struct module;
struct tracepoint;
+struct probe {
+ void *func;
+ void *data;
+};
+
struct tracepoint {
const char *name; /* Tracepoint name */
DEFINE_IMV(char, state); /* State. */
struct tracepoint {
const char *name; /* Tracepoint name */
DEFINE_IMV(char, state); /* State. */
} __attribute__((aligned(32))); /*
* Aligned on 32 bytes because it is
* globally visible and gcc happily
} __attribute__((aligned(32))); /*
* Aligned on 32 bytes because it is
* globally visible and gcc happily
*/
#define __DO_TRACE(tp, proto, args) \
do { \
*/
#define __DO_TRACE(tp, proto, args) \
do { \
+ 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) { \
- ((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(); */ \
} while (0)
#define __CHECK_TRACE(name, generic, proto, args) \
} while (0)
#define __CHECK_TRACE(name, generic, proto, args) \
* If generic is true, a variable read is used.
* If generic is false, immediate values are used.
*/
* 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) \
{ \
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) \
{ \
} \
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 }
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 */
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) \
static inline void trace_##name(proto) \
{ } \
static inline void _trace_##name(proto) \
{ }
#endif /* CONFIG_TRACEPOINTS */
{ }
#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.
*/
/*
* 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.
*/
/*
* 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 {
extern void tracepoint_probe_update_all(void);
struct tracepoint_iter {
struct trace_raw_##name { \
tstruct \
}; \
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; \
{ \
struct trace_raw_##name entry_struct, *__entry; \
__entry = &entry_struct; \
} \
static void __attribute__((constructor)) init_##name() \
{ \
} \
static void __attribute__((constructor)) init_##name() \
{ \
printf("connecting tracepoint " #name "\n"); \
printf("connecting tracepoint " #name "\n"); \
- register_trace_##name(trace_printf_##name); \
+ register_trace_##name(trace_printf_##name, dummy); \
Frederic Weisbecker <fweisbec@gmail.com>
Xiao Guangrong <xiaogunagrong@cn.fujitsu.com>
Josh Stone <jistone@redhat.com>
Frederic Weisbecker <fweisbec@gmail.com>
Xiao Guangrong <xiaogunagrong@cn.fujitsu.com>
Josh Stone <jistone@redhat.com>
+Lai Jiangshan <laijs@cn.fujitsu.com>
The following copyright holders have agreed to LGPLv2.1+ re-licensing
of their contributions to linux/include/stringify.h.
The following copyright holders have agreed to LGPLv2.1+ re-licensing
of their contributions to linux/include/stringify.h.
-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)
{
DEFINE_TRACE(ust_dummytp);
void dummy_libust_initializer_func(void)
{
trace_mark(ust, dummymark, MARK_NOARGS);
trace_mark(ust, dummymark, MARK_NOARGS);
*/
struct tracepoint_entry {
struct hlist_node hlist;
*/
struct tracepoint_entry {
struct hlist_node hlist;
int refcount; /* Number of times armed. 0 if disarmed. */
char name[0];
};
int refcount; /* Number of times armed. 0 if disarmed. */
char name[0];
};
//ust// struct rcu_head rcu;
struct list_head list;
} u;
//ust// struct rcu_head rcu;
struct list_head list;
} u;
+ struct probe probes[0];
};
static inline void *allocate_probes(int count)
{
};
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;
}
+ sizeof(struct tp_probes));
return p == NULL ? NULL : p->probes;
}
- if (!tracepoint_debug || !entry->funcs)
+ if (!tracepoint_debug || !entry->probes)
- 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);
-tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
+tracepoint_entry_add_probe(struct tracepoint_entry *entry,
+ void *probe, void *data)
+ struct probe *old, *new;
WARN_ON(!probe);
debug_print_probes(entry);
WARN_ON(!probe);
debug_print_probes(entry);
if (old) {
/* (N -> N+1), (N != 0, 1) 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 */
return ERR_PTR(-EEXIST);
}
/* + 2 : one for new probe, one for NULL func */
if (new == NULL)
return ERR_PTR(-ENOMEM);
if (old)
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->refcount = nr_probes + 1;
debug_print_probes(entry);
return old;
}
static void *
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;
{
int nr_probes = 0, nr_del = 0, i;
+ struct probe *old, *new;
if (!old)
return ERR_PTR(-ENOENT);
debug_print_probes(entry);
/* (N -> M), (N > 1, M >= 0) 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) */
nr_del++;
}
if (nr_probes - nr_del == 0) {
/* N -> 0, (N > 1) */
entry->refcount = 0;
debug_print_probes(entry);
return old;
entry->refcount = 0;
debug_print_probes(entry);
return old;
new = allocate_probes(nr_probes - nr_del + 1);
if (new == NULL)
return ERR_PTR(-ENOMEM);
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[nr_probes - nr_del] = NULL;
+ new[nr_probes - nr_del].func = NULL;
entry->refcount = nr_probes - nr_del;
entry->refcount = nr_probes - nr_del;
}
debug_print_probes(entry);
return old;
}
debug_print_probes(entry);
return old;
if (!e)
return ERR_PTR(-ENOMEM);
memcpy(&e->name[0], name, name_len);
if (!e)
return ERR_PTR(-ENOMEM);
memcpy(&e->name[0], name, name_len);
e->refcount = 0;
hlist_add_head(&e->hlist, head);
return e;
e->refcount = 0;
hlist_add_head(&e->hlist, head);
return e;
* include/linux/tracepoints.h. A matching smp_read_barrier_depends()
* is used.
*/
* 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;
}
elem->state__imv = active;
}
static void disable_tracepoint(struct tracepoint *elem)
{
elem->state__imv = 0;
static void disable_tracepoint(struct tracepoint *elem)
{
elem->state__imv = 0;
- rcu_assign_pointer(elem->funcs, NULL);
+ rcu_assign_pointer(elem->probes, NULL);
* Updates the probe callback corresponding to a range of tracepoints.
*/
void tracepoint_update_probe_range(struct tracepoint *begin,
* 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++) {
{
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,
mark_entry = get_tracepoint(iter->name);
if (mark_entry) {
set_tracepoint(&mark_entry, iter,
//ust// module_imv_update();
}
//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;
{
struct tracepoint_entry *entry;
entry = get_tracepoint(name);
if (!entry) {
entry = add_tracepoint(name);
if (IS_ERR(entry))
entry = get_tracepoint(name);
if (!entry) {
entry = add_tracepoint(name);
if (IS_ERR(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;
if (IS_ERR(old) && !entry->refcount)
remove_tracepoint(entry);
return old;
* Returns 0 if ok, error value on error.
* The probe address must at least be aligned on the architecture pointer size.
*/
* 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);
{
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);
pthread_mutex_unlock(&tracepoints_mutex);
if (IS_ERR(old))
return PTR_ERR(old);
}
//ust// EXPORT_SYMBOL_GPL(tracepoint_probe_register);
}
//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;
{
struct tracepoint_entry *entry;
void *old;
entry = get_tracepoint(name);
if (!entry)
return ERR_PTR(-ENOENT);
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)
if (IS_ERR(old))
return old;
if (!entry->refcount)
* tracepoint_probe_unregister - Disconnect a probe from a tracepoint
* @name: tracepoint name
* @probe: probe function pointer
* 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.
*/
*
* 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);
{
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);
pthread_mutex_unlock(&tracepoints_mutex);
if (IS_ERR(old))
return PTR_ERR(old);
*
* caller must call tracepoint_probe_update_all()
*/
*
* 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);
{
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);
if (IS_ERR(old)) {
pthread_mutex_unlock(&tracepoints_mutex);
return PTR_ERR(old);
*
* caller must call tracepoint_probe_update_all()
*/
*
* 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);
{
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);
if (IS_ERR(old)) {
pthread_mutex_unlock(&tracepoints_mutex);
return PTR_ERR(old);
lib_update_tracepoints();
DBG("just registered a tracepoints section from %p and having %d tracepoints", tracepoints_start, tracepoints_count);
lib_update_tracepoints();
DBG("just registered a tracepoints section from %p and having %d tracepoints", tracepoints_start, tracepoints_count);