question about macro __DO_TRACE

Frederic Weisbecker fweisbec at gmail.com
Fri Feb 25 23:37:59 EST 2011


On Sat, Feb 26, 2011 at 10:40:32AM +0800, zhao bao wrote:
>  Hello,everybody. When I read tracepoint code, I find variable __data
> never used. Am I missing something?
> 
> #define __DO_TRACE(tp, proto, args, cond)                               \
>         do {                                                            \
>                 struct tracepoint_func *it_func_ptr;                    \
>                 void *it_func;                                          \
>                 void *__data;                                           \
>                                                                         \
>                 if (!(cond))                                            \
>                         return;                                         \
>                 rcu_read_lock_sched_notrace();                          \
>                 it_func_ptr = rcu_dereference_sched((tp)->funcs);       \
>                 if (it_func_ptr) {                                      \
>                         do {                                            \
>                                 it_func = (it_func_ptr)->func;          \
>                                 __data = (it_func_ptr)->data;           \
>                                 ((void(*)(proto))(it_func))(args);      \
>                         } while ((++it_func_ptr)->func);                \
>                 }                                                       \
>                 rcu_read_unlock_sched_notrace();                        \
>         } while (0)


Yeah that's a quite tricky part.

So what we want with tracepoints is to have them passing something
specific as a first parameter. Always the same thing for a given func.

So you register a probe with tracepoint_probe_register() and the third
argument of this func, data, is the first parameter that will always been
passed to your probe function.

This is that "__data".

We declare a tracepoint with DECLARE_TRACE():

DECLARE_TRACE(my_trace, int myarg, myarg).

The CPP engine will translate that too:

__DECLARE_TRACE(mytrace, (int myarg), (myarg), 1
			(void *__data, int myarg),
			(__data, myarg))

			^^
Look, that where is the trick. DECLARE_TRACE is cheating by
adding this __data argument.

Further, __DO_TRACE will be called with these arguments:

__DO_TRACE(&__tracepoint_mytrace, (void *__data, int myarg),
	(__data, myarg), (cond))

And then it makes the trick inside __DO_TRACE(), we end up having:

				void *__data;

				__data = (it_func_ptr)->data;
				((void(*)(proto))(it_func))(__data, myarg);

See? That's a kind of ghost argument we inject in our CPP macros
and in the end we cheat in order to pass that constant tracepoint data
as a first argument of the probe.

In practice we use that to pass the ftrace event (struct ftrace_event_call *)
structure as a first argument of the probe.

It's a shame we needed to get something so unreadable and quick to generate
headaches but IIRC we didn't have the choice in order to pass that specific data
argument.



More information about the Kernelnewbies mailing list