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 8d5e4f6d96d..9a59d1f98cd 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -20,12 +20,17 @@  struct module;  struct tracepoint; +struct tracepoint_func { +	void *func; +	void *data; +}; +  struct tracepoint {  	const char *name;		/* Tracepoint name */  	int state;			/* State. */  	void (*regfunc)(void);  	void (*unregfunc)(void); -	void **funcs; +	struct tracepoint_func *funcs;  } __attribute__((aligned(32)));		/*  					 * Aligned on 32 bytes because it is  					 * globally visible and gcc happily @@ -37,16 +42,19 @@ struct tracepoint {   * 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 { @@ -102,17 +110,27 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,  /*   * it_func[0] is never NULL because there is at least one element in the array   * when the array itself is non NULL. + * + * Note, the proto and args passed in includes "__data" as the first parameter. + * The reason for this is to handle the "void" prototype. If a tracepoint + * has a "void" prototype, then it is invalid to declare a function + * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just + * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".   */  #define __DO_TRACE(tp, proto, args)					\  	do {								\ -		void **it_func;						\ +		struct tracepoint_func *it_func_ptr;			\ +		void *it_func;						\ +		void *__data;						\  									\  		rcu_read_lock_sched_notrace();				\ -		it_func = rcu_dereference_sched((tp)->funcs);		\ -		if (it_func) {						\ +		it_func_ptr = rcu_dereference_sched((tp)->funcs);	\ +		if (it_func_ptr) {					\  			do {						\ -				((void(*)(proto))(*it_func))(args);	\ -			} while (*(++it_func));				\ +				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) @@ -122,23 +140,29 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,   * not add unwanted padding between the beginning of the section and the   * structure. Force alignment to the same alignment as the section start.   */ -#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)				\  	{								\  		if (unlikely(__tracepoint_##name.state))		\  			__DO_TRACE(&__tracepoint_##name,		\ -				TP_PROTO(proto), TP_ARGS(args));	\ +				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);		\  	}								\ -	static inline void check_trace_callback_type_##name(void (*cb)(proto)) \ +	static inline void						\ +	check_trace_callback_type_##name(void (*cb)(data_proto))	\  	{								\  	} @@ -158,20 +182,22 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,  	EXPORT_SYMBOL(__tracepoint_##name)  #else /* !CONFIG_TRACEPOINTS */ -#define DECLARE_TRACE(name, proto, args)				\ -	static inline void _do_trace_##name(struct tracepoint *tp, proto) \ -	{ }								\ +#define __DECLARE_TRACE(name, proto, args, data_proto, data_args)	\  	static inline void trace_##name(proto)				\  	{ }								\ -	static inline int register_trace_##name(void (*probe)(proto))	\ +	static inline int						\ +	register_trace_##name(void (*probe)(data_proto),		\ +			      void *data)				\  	{								\  		return -ENOSYS;						\  	}								\ -	static inline int unregister_trace_##name(void (*probe)(proto))	\ +	static inline int						\ +	unregister_trace_##name(void (*probe)(data_proto),		\ +				void *data)				\  	{								\  		return -ENOSYS;						\  	}								\ -	static inline void check_trace_callback_type_##name(void (*cb)(proto)) \ +	static inline void check_trace_callback_type_##name(void (*cb)(data_proto)) \  	{								\  	} @@ -181,6 +207,29 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,  #define EXPORT_TRACEPOINT_SYMBOL(name)  #endif /* CONFIG_TRACEPOINTS */ + +/* + * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype + * (void). "void" is a special value in a function prototype and can + * not be combined with other arguments. Since the DECLARE_TRACE() + * macro adds a data element at the beginning of the prototype, + * we need a way to differentiate "(void *data, proto)" from + * "(void *data, void)". The second prototype is invalid. + * + * DECLARE_TRACE_NOARGS() passes "void" as the tracepoint prototype + * and "void *__data" as the callback prototype. + * + * DECLARE_TRACE() passes "proto" as the tracepoint protoype and + * "void *__data, proto" as the callback prototype. + */ +#define DECLARE_TRACE_NOARGS(name)					\ +		__DECLARE_TRACE(name, void, , void *__data, __data) + +#define DECLARE_TRACE(name, proto, args)				\ +		__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args),	\ +				PARAMS(void *__data, proto),		\ +				PARAMS(__data, args)) +  #endif /* DECLARE_TRACE */  #ifndef TRACE_EVENT  |