oprofile: oprofile_set_timeout(), return with error for invalid args
[linux-2.6.git] / drivers / oprofile / oprof.c
blob42c9c765f9f16bfe49b7d34905f95b933dda47ef
1 /**
2 * @file oprof.c
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
7 * @author John Levon <levon@movementarian.org>
8 */
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/oprofile.h>
14 #include <linux/moduleparam.h>
15 #include <linux/workqueue.h>
16 #include <linux/time.h>
17 #include <asm/mutex.h>
19 #include "oprof.h"
20 #include "event_buffer.h"
21 #include "cpu_buffer.h"
22 #include "buffer_sync.h"
23 #include "oprofile_stats.h"
25 struct oprofile_operations oprofile_ops;
27 unsigned long oprofile_started;
28 unsigned long oprofile_backtrace_depth;
29 static unsigned long is_setup;
30 static DEFINE_MUTEX(start_mutex);
32 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
34 static void switch_worker(struct work_struct *work);
35 static DECLARE_DELAYED_WORK(switch_work, switch_worker);
36 unsigned long timeout_jiffies;
37 #define MULTIPLEXING_TIMER_DEFAULT 1
39 #endif
41 /* timer
42 0 - use performance monitoring hardware if available
43 1 - use the timer int mechanism regardless
45 static int timer = 0;
47 int oprofile_setup(void)
49 int err;
51 mutex_lock(&start_mutex);
53 if ((err = alloc_cpu_buffers()))
54 goto out;
56 if ((err = alloc_event_buffer()))
57 goto out1;
59 if (oprofile_ops.setup && (err = oprofile_ops.setup()))
60 goto out2;
62 /* Note even though this starts part of the
63 * profiling overhead, it's necessary to prevent
64 * us missing task deaths and eventually oopsing
65 * when trying to process the event buffer.
67 if (oprofile_ops.sync_start) {
68 int sync_ret = oprofile_ops.sync_start();
69 switch (sync_ret) {
70 case 0:
71 goto post_sync;
72 case 1:
73 goto do_generic;
74 case -1:
75 goto out3;
76 default:
77 goto out3;
80 do_generic:
81 if ((err = sync_start()))
82 goto out3;
84 post_sync:
85 is_setup = 1;
86 mutex_unlock(&start_mutex);
87 return 0;
89 out3:
90 if (oprofile_ops.shutdown)
91 oprofile_ops.shutdown();
92 out2:
93 free_event_buffer();
94 out1:
95 free_cpu_buffers();
96 out:
97 mutex_unlock(&start_mutex);
98 return err;
101 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
103 static void start_switch_worker(void)
105 schedule_delayed_work(&switch_work, timeout_jiffies);
108 static void switch_worker(struct work_struct *work)
110 if (!oprofile_ops.switch_events())
111 start_switch_worker();
114 #endif
116 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
117 int oprofile_start(void)
119 int err = -EINVAL;
121 mutex_lock(&start_mutex);
123 if (!is_setup)
124 goto out;
126 err = 0;
128 if (oprofile_started)
129 goto out;
131 oprofile_reset_stats();
133 if ((err = oprofile_ops.start()))
134 goto out;
136 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
137 if (oprofile_ops.switch_events)
138 start_switch_worker();
139 #endif
141 oprofile_started = 1;
142 out:
143 mutex_unlock(&start_mutex);
144 return err;
148 /* echo 0>/dev/oprofile/enable */
149 void oprofile_stop(void)
151 mutex_lock(&start_mutex);
152 if (!oprofile_started)
153 goto out;
154 oprofile_ops.stop();
155 oprofile_started = 0;
157 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
158 cancel_delayed_work_sync(&switch_work);
159 #endif
161 /* wake up the daemon to read what remains */
162 wake_up_buffer_waiter();
163 out:
164 mutex_unlock(&start_mutex);
168 void oprofile_shutdown(void)
170 mutex_lock(&start_mutex);
171 if (oprofile_ops.sync_stop) {
172 int sync_ret = oprofile_ops.sync_stop();
173 switch (sync_ret) {
174 case 0:
175 goto post_sync;
176 case 1:
177 goto do_generic;
178 default:
179 goto post_sync;
182 do_generic:
183 sync_stop();
184 post_sync:
185 if (oprofile_ops.shutdown)
186 oprofile_ops.shutdown();
187 is_setup = 0;
188 free_event_buffer();
189 free_cpu_buffers();
190 mutex_unlock(&start_mutex);
193 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
195 /* User inputs in ms, converts to jiffies */
196 int oprofile_set_timeout(unsigned long val_msec)
198 int err = 0;
199 unsigned long time_slice;
201 mutex_lock(&start_mutex);
203 if (oprofile_started) {
204 err = -EBUSY;
205 goto out;
208 if (!oprofile_ops.switch_events) {
209 err = -EINVAL;
210 goto out;
213 time_slice = msecs_to_jiffies(val_msec);
214 if (time_slice == MAX_JIFFY_OFFSET) {
215 err = -EINVAL;
216 goto out;
219 timeout_jiffies = time_slice;
221 out:
222 mutex_unlock(&start_mutex);
223 return err;
227 #endif
229 int oprofile_set_backtrace(unsigned long val)
231 int err = 0;
233 mutex_lock(&start_mutex);
235 if (oprofile_started) {
236 err = -EBUSY;
237 goto out;
240 if (!oprofile_ops.backtrace) {
241 err = -EINVAL;
242 goto out;
245 oprofile_backtrace_depth = val;
247 out:
248 mutex_unlock(&start_mutex);
249 return err;
252 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
254 static void __init oprofile_multiplexing_init(void)
256 timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT);
259 #endif
261 static int __init oprofile_init(void)
263 int err;
265 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
266 oprofile_multiplexing_init();
267 #endif
269 err = oprofile_arch_init(&oprofile_ops);
271 if (err < 0 || timer) {
272 printk(KERN_INFO "oprofile: using timer interrupt.\n");
273 oprofile_timer_init(&oprofile_ops);
276 err = oprofilefs_register();
277 if (err)
278 oprofile_arch_exit();
280 return err;
284 static void __exit oprofile_exit(void)
286 oprofilefs_unregister();
287 oprofile_arch_exit();
291 module_init(oprofile_init);
292 module_exit(oprofile_exit);
294 module_param_named(timer, timer, int, 0644);
295 MODULE_PARM_DESC(timer, "force use of timer interrupt");
297 MODULE_LICENSE("GPL");
298 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
299 MODULE_DESCRIPTION("OProfile system profiler");