forked from rotateright/rrnotify
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrrnotify_init.c
158 lines (124 loc) · 2.55 KB
/
rrnotify_init.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/**
* @file rrnotify_init.c
*
* @remark Copyright (C) 2006-2015 RotateRight, LLC
* @remark Copyright 2002 OProfile authors
* @remark Based on Oprofile's implementation.
* @remark Read the file COPYING
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include "rrnotify.h"
#include "rrnotify_stats.h"
#include "event_buffer.h"
#include "buffer_sync.h"
unsigned long rrnotify_started;
static unsigned long is_setup;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
static DEFINE_SEMAPHORE(start_sem);
#else
static DECLARE_MUTEX(start_sem);
#endif
/* Debug
0 - don't print debug statements.
1 - print debug statements.
*/
int rrnotify_debug = 0;
int rrnotify_set_ulong(unsigned long *addr, unsigned long val)
{
int err = -EBUSY;
down(&start_sem);
if (!rrnotify_started) {
*addr = val;
err = 0;
}
up(&start_sem);
return err;
}
int rrnotify_setup(void)
{
int err;
down(&start_sem);
if ((err = alloc_event_buffer())) {
goto out1;
}
/* Note even though this starts part of the
* profiling overhead, it's necessary to prevent
* us missing task deaths and eventually oopsing
* when trying to process the event buffer.
*/
if ((err = sync_start())) {
goto out2;
}
is_setup = 1;
atomic_set(&buffer_dump, 0);
up(&start_sem);
return 0;
out2:
free_event_buffer();
out1:
up(&start_sem);
return err;
}
/* Actually start profiling (echo 1>/dev/rrnotify/enable) */
int rrnotify_start(void)
{
int err = -EINVAL;
down(&start_sem);
if (!is_setup) {
goto out;
}
err = 0;
if (rrnotify_started) {
goto out;
}
rrnotify_reset_stats();
rrnotify_started = 1;
atomic_set(&buffer_dump, 0);
out:
up(&start_sem);
return err;
}
/* echo 0>/dev/rrnotify/enable */
void rrnotify_stop(void)
{
down(&start_sem);
if (!rrnotify_started) {
goto out;
}
rrnotify_started = 0;
/* wake up the daemon to read what remains */
wake_up_buffer_waiter();
out:
up(&start_sem);
}
void rrnotify_shutdown(void)
{
down(&start_sem);
sync_stop();
is_setup = 0;
free_event_buffer();
up(&start_sem);
}
static int __init rrnotify_init(void)
{
int err;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
sema_init(&start_sem, 1);
#endif
init_event_buffer();
printk(KERN_INFO "rrnotify: init\n");
err = rrnotifyfs_register();
return err;
}
static void __exit rrnotify_exit(void)
{
rrnotifyfs_unregister();
printk(KERN_INFO "rrnotify: exit\n");
}
module_init(rrnotify_init);
module_exit(rrnotify_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("RotateRight, LLC");
MODULE_DESCRIPTION("rotateright task exit notifier");