diff options
Diffstat (limited to 'tools/perf/util/perf-hooks.c')
| -rw-r--r-- | tools/perf/util/perf-hooks.c | 88 | 
1 files changed, 88 insertions, 0 deletions
diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c new file mode 100644 index 000000000000..cb368306b12b --- /dev/null +++ b/tools/perf/util/perf-hooks.c @@ -0,0 +1,88 @@ +/* + * perf_hooks.c + * + * Copyright (C) 2016 Wang Nan <[email protected]> + * Copyright (C) 2016 Huawei Inc. + */ + +#include <errno.h> +#include <stdlib.h> +#include <setjmp.h> +#include <linux/err.h> +#include "util/util.h" +#include "util/debug.h" +#include "util/perf-hooks.h" + +static sigjmp_buf jmpbuf; +static const struct perf_hook_desc *current_perf_hook; + +void perf_hooks__invoke(const struct perf_hook_desc *desc) +{ +	if (!(desc && desc->p_hook_func && *desc->p_hook_func)) +		return; + +	if (sigsetjmp(jmpbuf, 1)) { +		pr_warning("Fatal error (SEGFAULT) in perf hook '%s'\n", +			   desc->hook_name); +		*(current_perf_hook->p_hook_func) = NULL; +	} else { +		current_perf_hook = desc; +		(**desc->p_hook_func)(desc->hook_ctx); +	} +	current_perf_hook = NULL; +} + +void perf_hooks__recover(void) +{ +	if (current_perf_hook) +		siglongjmp(jmpbuf, 1); +} + +#define PERF_HOOK(name)					\ +perf_hook_func_t __perf_hook_func_##name = NULL;	\ +struct perf_hook_desc __perf_hook_desc_##name =		\ +	{.hook_name = #name,				\ +	 .p_hook_func = &__perf_hook_func_##name,	\ +	 .hook_ctx = NULL}; +#include "perf-hooks-list.h" +#undef PERF_HOOK + +#define PERF_HOOK(name)		\ +	&__perf_hook_desc_##name, + +static struct perf_hook_desc *perf_hooks[] = { +#include "perf-hooks-list.h" +}; +#undef PERF_HOOK + +int perf_hooks__set_hook(const char *hook_name, +			 perf_hook_func_t hook_func, +			 void *hook_ctx) +{ +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) { +		if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0) +			continue; + +		if (*(perf_hooks[i]->p_hook_func)) +			pr_warning("Overwrite existing hook: %s\n", hook_name); +		*(perf_hooks[i]->p_hook_func) = hook_func; +		perf_hooks[i]->hook_ctx = hook_ctx; +		return 0; +	} +	return -ENOENT; +} + +perf_hook_func_t perf_hooks__get_hook(const char *hook_name) +{ +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) { +		if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0) +			continue; + +		return *(perf_hooks[i]->p_hook_func); +	} +	return ERR_PTR(-ENOENT); +}  |