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.

_______________________________________________
Kernelnewbies mailing list
[email protected]
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

Reply via email to