blob: d55092964da2f3fec32b61f6ef7906093d0945fe [file] [log] [blame]
Wang Nana0748652016-11-26 07:03:28 +00001/*
2 * perf_hooks.c
3 *
4 * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com>
5 * Copyright (C) 2016 Huawei Inc.
6 */
7
8#include <errno.h>
9#include <stdlib.h>
10#include <setjmp.h>
11#include <linux/err.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030012#include <linux/kernel.h>
Wang Nana0748652016-11-26 07:03:28 +000013#include "util/util.h"
14#include "util/debug.h"
15#include "util/perf-hooks.h"
16
17static sigjmp_buf jmpbuf;
18static const struct perf_hook_desc *current_perf_hook;
19
20void perf_hooks__invoke(const struct perf_hook_desc *desc)
21{
22 if (!(desc && desc->p_hook_func && *desc->p_hook_func))
23 return;
24
25 if (sigsetjmp(jmpbuf, 1)) {
26 pr_warning("Fatal error (SEGFAULT) in perf hook '%s'\n",
27 desc->hook_name);
28 *(current_perf_hook->p_hook_func) = NULL;
29 } else {
30 current_perf_hook = desc;
Wang Nan8ad85e92016-11-26 07:03:29 +000031 (**desc->p_hook_func)(desc->hook_ctx);
Wang Nana0748652016-11-26 07:03:28 +000032 }
33 current_perf_hook = NULL;
34}
35
36void perf_hooks__recover(void)
37{
38 if (current_perf_hook)
39 siglongjmp(jmpbuf, 1);
40}
41
42#define PERF_HOOK(name) \
43perf_hook_func_t __perf_hook_func_##name = NULL; \
44struct perf_hook_desc __perf_hook_desc_##name = \
Wang Nan8ad85e92016-11-26 07:03:29 +000045 {.hook_name = #name, \
46 .p_hook_func = &__perf_hook_func_##name, \
47 .hook_ctx = NULL};
Wang Nana0748652016-11-26 07:03:28 +000048#include "perf-hooks-list.h"
49#undef PERF_HOOK
50
51#define PERF_HOOK(name) \
52 &__perf_hook_desc_##name,
53
54static struct perf_hook_desc *perf_hooks[] = {
55#include "perf-hooks-list.h"
56};
57#undef PERF_HOOK
58
59int perf_hooks__set_hook(const char *hook_name,
Wang Nan8ad85e92016-11-26 07:03:29 +000060 perf_hook_func_t hook_func,
61 void *hook_ctx)
Wang Nana0748652016-11-26 07:03:28 +000062{
63 unsigned int i;
64
65 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) {
66 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0)
67 continue;
68
69 if (*(perf_hooks[i]->p_hook_func))
70 pr_warning("Overwrite existing hook: %s\n", hook_name);
71 *(perf_hooks[i]->p_hook_func) = hook_func;
Wang Nan8ad85e92016-11-26 07:03:29 +000072 perf_hooks[i]->hook_ctx = hook_ctx;
Wang Nana0748652016-11-26 07:03:28 +000073 return 0;
74 }
75 return -ENOENT;
76}
77
78perf_hook_func_t perf_hooks__get_hook(const char *hook_name)
79{
80 unsigned int i;
81
82 for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) {
83 if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0)
84 continue;
85
86 return *(perf_hooks[i]->p_hook_func);
87 }
88 return ERR_PTR(-ENOENT);
89}