diff options
Diffstat (limited to 'include/linux/tracepoint.h')
-rw-r--r-- | include/linux/tracepoint.h | 95 |
1 files changed, 72 insertions, 23 deletions
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 8d5e4f6d96d0..9a59d1f98cd4 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -20,12 +20,17 @@ | |||
20 | struct module; | 20 | struct module; |
21 | struct tracepoint; | 21 | struct tracepoint; |
22 | 22 | ||
23 | struct tracepoint_func { | ||
24 | void *func; | ||
25 | void *data; | ||
26 | }; | ||
27 | |||
23 | struct tracepoint { | 28 | struct tracepoint { |
24 | const char *name; /* Tracepoint name */ | 29 | const char *name; /* Tracepoint name */ |
25 | int state; /* State. */ | 30 | int state; /* State. */ |
26 | void (*regfunc)(void); | 31 | void (*regfunc)(void); |
27 | void (*unregfunc)(void); | 32 | void (*unregfunc)(void); |
28 | void **funcs; | 33 | struct tracepoint_func *funcs; |
29 | } __attribute__((aligned(32))); /* | 34 | } __attribute__((aligned(32))); /* |
30 | * Aligned on 32 bytes because it is | 35 | * Aligned on 32 bytes because it is |
31 | * globally visible and gcc happily | 36 | * globally visible and gcc happily |
@@ -37,16 +42,19 @@ struct tracepoint { | |||
37 | * Connect a probe to a tracepoint. | 42 | * Connect a probe to a tracepoint. |
38 | * Internal API, should not be used directly. | 43 | * Internal API, should not be used directly. |
39 | */ | 44 | */ |
40 | extern int tracepoint_probe_register(const char *name, void *probe); | 45 | extern int tracepoint_probe_register(const char *name, void *probe, void *data); |
41 | 46 | ||
42 | /* | 47 | /* |
43 | * Disconnect a probe from a tracepoint. | 48 | * Disconnect a probe from a tracepoint. |
44 | * Internal API, should not be used directly. | 49 | * Internal API, should not be used directly. |
45 | */ | 50 | */ |
46 | extern int tracepoint_probe_unregister(const char *name, void *probe); | 51 | extern int |
52 | tracepoint_probe_unregister(const char *name, void *probe, void *data); | ||
47 | 53 | ||
48 | extern int tracepoint_probe_register_noupdate(const char *name, void *probe); | 54 | extern int tracepoint_probe_register_noupdate(const char *name, void *probe, |
49 | extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe); | 55 | void *data); |
56 | extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe, | ||
57 | void *data); | ||
50 | extern void tracepoint_probe_update_all(void); | 58 | extern void tracepoint_probe_update_all(void); |
51 | 59 | ||
52 | struct tracepoint_iter { | 60 | struct tracepoint_iter { |
@@ -102,17 +110,27 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
102 | /* | 110 | /* |
103 | * it_func[0] is never NULL because there is at least one element in the array | 111 | * it_func[0] is never NULL because there is at least one element in the array |
104 | * when the array itself is non NULL. | 112 | * when the array itself is non NULL. |
113 | * | ||
114 | * Note, the proto and args passed in includes "__data" as the first parameter. | ||
115 | * The reason for this is to handle the "void" prototype. If a tracepoint | ||
116 | * has a "void" prototype, then it is invalid to declare a function | ||
117 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just | ||
118 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". | ||
105 | */ | 119 | */ |
106 | #define __DO_TRACE(tp, proto, args) \ | 120 | #define __DO_TRACE(tp, proto, args) \ |
107 | do { \ | 121 | do { \ |
108 | void **it_func; \ | 122 | struct tracepoint_func *it_func_ptr; \ |
123 | void *it_func; \ | ||
124 | void *__data; \ | ||
109 | \ | 125 | \ |
110 | rcu_read_lock_sched_notrace(); \ | 126 | rcu_read_lock_sched_notrace(); \ |
111 | it_func = rcu_dereference_sched((tp)->funcs); \ | 127 | it_func_ptr = rcu_dereference_sched((tp)->funcs); \ |
112 | if (it_func) { \ | 128 | if (it_func_ptr) { \ |
113 | do { \ | 129 | do { \ |
114 | ((void(*)(proto))(*it_func))(args); \ | 130 | it_func = (it_func_ptr)->func; \ |
115 | } while (*(++it_func)); \ | 131 | __data = (it_func_ptr)->data; \ |
132 | ((void(*)(proto))(it_func))(args); \ | ||
133 | } while ((++it_func_ptr)->func); \ | ||
116 | } \ | 134 | } \ |
117 | rcu_read_unlock_sched_notrace(); \ | 135 | rcu_read_unlock_sched_notrace(); \ |
118 | } while (0) | 136 | } while (0) |
@@ -122,23 +140,29 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
122 | * not add unwanted padding between the beginning of the section and the | 140 | * not add unwanted padding between the beginning of the section and the |
123 | * structure. Force alignment to the same alignment as the section start. | 141 | * structure. Force alignment to the same alignment as the section start. |
124 | */ | 142 | */ |
125 | #define DECLARE_TRACE(name, proto, args) \ | 143 | #define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ |
126 | extern struct tracepoint __tracepoint_##name; \ | 144 | extern struct tracepoint __tracepoint_##name; \ |
127 | static inline void trace_##name(proto) \ | 145 | static inline void trace_##name(proto) \ |
128 | { \ | 146 | { \ |
129 | if (unlikely(__tracepoint_##name.state)) \ | 147 | if (unlikely(__tracepoint_##name.state)) \ |
130 | __DO_TRACE(&__tracepoint_##name, \ | 148 | __DO_TRACE(&__tracepoint_##name, \ |
131 | TP_PROTO(proto), TP_ARGS(args)); \ | 149 | TP_PROTO(data_proto), \ |
150 | TP_ARGS(data_args)); \ | ||
132 | } \ | 151 | } \ |
133 | static inline int register_trace_##name(void (*probe)(proto)) \ | 152 | static inline int \ |
153 | register_trace_##name(void (*probe)(data_proto), void *data) \ | ||
134 | { \ | 154 | { \ |
135 | return tracepoint_probe_register(#name, (void *)probe); \ | 155 | return tracepoint_probe_register(#name, (void *)probe, \ |
156 | data); \ | ||
136 | } \ | 157 | } \ |
137 | static inline int unregister_trace_##name(void (*probe)(proto)) \ | 158 | static inline int \ |
159 | unregister_trace_##name(void (*probe)(data_proto), void *data) \ | ||
138 | { \ | 160 | { \ |
139 | return tracepoint_probe_unregister(#name, (void *)probe);\ | 161 | return tracepoint_probe_unregister(#name, (void *)probe, \ |
162 | data); \ | ||
140 | } \ | 163 | } \ |
141 | static inline void check_trace_callback_type_##name(void (*cb)(proto)) \ | 164 | static inline void \ |
165 | check_trace_callback_type_##name(void (*cb)(data_proto)) \ | ||
142 | { \ | 166 | { \ |
143 | } | 167 | } |
144 | 168 | ||
@@ -158,20 +182,22 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
158 | EXPORT_SYMBOL(__tracepoint_##name) | 182 | EXPORT_SYMBOL(__tracepoint_##name) |
159 | 183 | ||
160 | #else /* !CONFIG_TRACEPOINTS */ | 184 | #else /* !CONFIG_TRACEPOINTS */ |
161 | #define DECLARE_TRACE(name, proto, args) \ | 185 | #define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ |
162 | static inline void _do_trace_##name(struct tracepoint *tp, proto) \ | ||
163 | { } \ | ||
164 | static inline void trace_##name(proto) \ | 186 | static inline void trace_##name(proto) \ |
165 | { } \ | 187 | { } \ |
166 | static inline int register_trace_##name(void (*probe)(proto)) \ | 188 | static inline int \ |
189 | register_trace_##name(void (*probe)(data_proto), \ | ||
190 | void *data) \ | ||
167 | { \ | 191 | { \ |
168 | return -ENOSYS; \ | 192 | return -ENOSYS; \ |
169 | } \ | 193 | } \ |
170 | static inline int unregister_trace_##name(void (*probe)(proto)) \ | 194 | static inline int \ |
195 | unregister_trace_##name(void (*probe)(data_proto), \ | ||
196 | void *data) \ | ||
171 | { \ | 197 | { \ |
172 | return -ENOSYS; \ | 198 | return -ENOSYS; \ |
173 | } \ | 199 | } \ |
174 | static inline void check_trace_callback_type_##name(void (*cb)(proto)) \ | 200 | static inline void check_trace_callback_type_##name(void (*cb)(data_proto)) \ |
175 | { \ | 201 | { \ |
176 | } | 202 | } |
177 | 203 | ||
@@ -181,6 +207,29 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
181 | #define EXPORT_TRACEPOINT_SYMBOL(name) | 207 | #define EXPORT_TRACEPOINT_SYMBOL(name) |
182 | 208 | ||
183 | #endif /* CONFIG_TRACEPOINTS */ | 209 | #endif /* CONFIG_TRACEPOINTS */ |
210 | |||
211 | /* | ||
212 | * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype | ||
213 | * (void). "void" is a special value in a function prototype and can | ||
214 | * not be combined with other arguments. Since the DECLARE_TRACE() | ||
215 | * macro adds a data element at the beginning of the prototype, | ||
216 | * we need a way to differentiate "(void *data, proto)" from | ||
217 | * "(void *data, void)". The second prototype is invalid. | ||
218 | * | ||
219 | * DECLARE_TRACE_NOARGS() passes "void" as the tracepoint prototype | ||
220 | * and "void *__data" as the callback prototype. | ||
221 | * | ||
222 | * DECLARE_TRACE() passes "proto" as the tracepoint protoype and | ||
223 | * "void *__data, proto" as the callback prototype. | ||
224 | */ | ||
225 | #define DECLARE_TRACE_NOARGS(name) \ | ||
226 | __DECLARE_TRACE(name, void, , void *__data, __data) | ||
227 | |||
228 | #define DECLARE_TRACE(name, proto, args) \ | ||
229 | __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ | ||
230 | PARAMS(void *__data, proto), \ | ||
231 | PARAMS(__data, args)) | ||
232 | |||
184 | #endif /* DECLARE_TRACE */ | 233 | #endif /* DECLARE_TRACE */ |
185 | 234 | ||
186 | #ifndef TRACE_EVENT | 235 | #ifndef TRACE_EVENT |