1 /*
2 * jit.c -- the just-in-time module
3 *
4 * Copyright (C) 2001,2003 Alessandro Rubini and Jonathan Corbet
5 * Copyright (C) 2001,2003 O'Reilly & Associates
6 *
7 * The source code in this file can be freely used, adapted,
8 * and redistributed in source or binary form, so long as an
9 * acknowledgment appears in derived source files. The citation
10 * should list that the code comes from the book "Linux Device
11 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
12 * by O'Reilly & Associates. No warranty is attached;
13 * we cannot take responsibility for errors or fitness for use.
14 *
15 * $Id: jit.c,v 1.16 2004/09/26 07:02:43 gregkh Exp $
16 */
17
18 #include <linux/module.h>
19 #include <linux/moduleparam.h>
20 #include <linux/init.h>
21
22 #include <linux/time.h>
23 #include <linux/timer.h>
24 #include <linux/kernel.h>
25 #include <linux/proc_fs.h>
26 #include <linux/types.h>
27 #include <linux/spinlock.h>
28 #include <linux/interrupt.h>
29
30 #include <asm/hardirq.h>
31 /*
32 * This module is a silly one: it only embeds short code fragments
33 * that show how time delays can be handled in the kernel.
34 */
35
36 int delay = HZ; /* the default delay, expressed in jiffies */
37
38 module_param(delay, int, 0);
39
40 MODULE_AUTHOR("Alessandro Rubini");
41 MODULE_LICENSE("Dual BSD/GPL");
42
43 /* use these as data pointers, to implement four files in one function */
44 enum jit_files {
45 JIT_BUSY,
46 JIT_SCHED,
47 JIT_QUEUE,
48 JIT_SCHEDTO
49 };
50
51 /*
52 * This function prints one line of data, after sleeping one second.
53 * It can sleep in different ways, according to the data pointer
54 */
55 int jit_fn(char *buf, char **start, off_t offset,
56 int len, int *eof, void *data)
57 {
58 unsigned long j0, j1; /* jiffies */
59 wait_queue_head_t wait;
60
61 init_waitqueue_head (&wait);
62 j0 = jiffies;
63 j1 = j0 + delay;
64
65 switch((long)data) {
66 case JIT_BUSY:
67 while (time_before(jiffies, j1))
68 cpu_relax();
69 break;
70 case JIT_SCHED:
71 while (time_before(jiffies, j1)) {
72 schedule();
73 }
74 break;
75 case JIT_QUEUE:
76 wait_event_interruptible_timeout(wait, 0, delay);
77 break;
78 case JIT_SCHEDTO:
79 set_current_state(TASK_INTERRUPTIBLE);
80 schedule_timeout (delay);
81 break;
82 }
83 j1 = jiffies; /* actual value after we delayed */
84
85 len = sprintf(buf, "%9li %9li\n", j0, j1);
86 *start = buf;
87 return len;
88 }
89
90 /*
91 * This file, on the other hand, returns the current time forever
92 */
93 int jit_currentime(char *buf, char **start, off_t offset,
94 int len, int *eof, void *data)
95 {
96 struct timeval tv1;
97 struct timespec tv2;
98 unsigned long j1;
99 u64 j2;
100
101 /* get them four */
102 j1 = jiffies;
103 j2 = get_jiffies_64();
104 do_gettimeofday(&tv1);
105 tv2 = current_kernel_time();
106
107 /* print */
108 len=0;
109 len += sprintf(buf,"0x%08lx 0x%016Lx %10i.%06i\n"
110 "%40i.%09i\n",
111 j1, j2,
112 (int) tv1.tv_sec, (int) tv1.tv_usec,
113 (int) tv2.tv_sec, (int) tv2.tv_nsec);
114 *start = buf;
115 return len;
116 }
117
118 /*
119 * The timer example follows
120 */
121
122 int tdelay = 10;
123 module_param(tdelay, int, 0);
124
125 /* This data structure used as "data" for the timer and tasklet functions */
126 struct jit_data {
127 struct timer_list timer;
128 struct tasklet_struct tlet;
129 int hi; /* tasklet or tasklet_hi */
130 wait_queue_head_t wait;
131 unsigned long prevjiffies;
132 unsigned char *buf;
133 int loops;
134 };
135 #define JIT_ASYNC_LOOPS 5
136
137 void jit_timer_fn(unsigned long arg)
138 {
139 struct jit_data *data = (struct jit_data *)arg;
140 unsigned long j = jiffies;
141 data->buf += sprintf(data->buf, "%9li %3li %i %6i %i %s\n",
142 j, j - data->prevjiffies, in_interrupt() ? 1 : 0,
143 current->pid, smp_processor_id(), current->comm);
144
145 if (--data->loops) {
146 data->timer.expires += tdelay;
147 data->prevjiffies = j;
148 add_timer(&data->timer);
149 } else {
150 wake_up_interruptible(&data->wait);
151 }
152 }
153
154 /* the /proc function: allocate everything to allow concurrency */
155 int jit_timer(char *buf, char **start, off_t offset,
156 int len, int *eof, void *unused_data)
157 {
158 struct jit_data *data;
159 char *buf2 = buf;
160 unsigned long j = jiffies;
161
162 data = kmalloc(sizeof(*data), GFP_KERNEL);
163 if (!data)
164 return -ENOMEM;
165
166 init_timer(&data->timer);
167 init_waitqueue_head (&data->wait);
168
169 /* write the first lines in the buffer */
170 buf2 += sprintf(buf2, " time delta inirq pid cpu command\n");
171 buf2 += sprintf(buf2, "%9li %3li %i %6i %i %s\n",
172 j, 0L, in_interrupt() ? 1 : 0,
173 current->pid, smp_processor_id(), current->comm);
174
175 /* fill the data for our timer function */
176 data->prevjiffies = j;
177 data->buf = buf2;
178 data->loops = JIT_ASYNC_LOOPS;
179
180 /* register the timer */
181 data->timer.data = (unsigned long)data;
182 data->timer.function = jit_timer_fn;
183 data->timer.expires = j + tdelay; /* parameter */
184 add_timer(&data->timer);
185
186 /* wait for the buffer to fill */
187 wait_event_interruptible(data->wait, !data->loops);
188 if (signal_pending(current))
189 return -ERESTARTSYS;
190 buf2 = data->buf;
191 kfree(data);
192 *eof = 1;
193 return buf2 - buf;
194 }
195
196 void jit_tasklet_fn(unsigned long arg)
197 {
198 struct jit_data *data = (struct jit_data *)arg;
199 unsigned long j = jiffies;
200 data->buf += sprintf(data->buf, "%9li %3li %i %6i %i %s\n",
201 j, j - data->prevjiffies, in_interrupt() ? 1 : 0,
202 current->pid, smp_processor_id(), current->comm);
203
204 if (--data->loops) {
205 data->prevjiffies = j;
206 if (data->hi)
207 tasklet_hi_schedule(&data->tlet);
208 else
209 tasklet_schedule(&data->tlet);
210 } else {
211 wake_up_interruptible(&data->wait);
212 }
213 }
214
215 /* the /proc function: allocate everything to allow concurrency */
216 int jit_tasklet(char *buf, char **start, off_t offset,
217 int len, int *eof, void *arg)
218 {
219 struct jit_data *data;
220 char *buf2 = buf;
221 unsigned long j = jiffies;
222 long hi = (long)arg;
223
224 data = kmalloc(sizeof(*data), GFP_KERNEL);
225 if (!data)
226 return -ENOMEM;
227
228 init_waitqueue_head (&data->wait);
229
230 /* write the first lines in the buffer */
231 buf2 += sprintf(buf2, " time delta inirq pid cpu command\n");
232 buf2 += sprintf(buf2, "%9li %3li %i %6i %i %s\n",
233 j, 0L, in_interrupt() ? 1 : 0,
234 current->pid, smp_processor_id(), current->comm);
235
236 /* fill the data for our tasklet function */
237 data->prevjiffies = j;
238 data->buf = buf2;
239 data->loops = JIT_ASYNC_LOOPS;
240
241 /* register the tasklet */
242 tasklet_init(&data->tlet, jit_tasklet_fn, (unsigned long)data);
243 data->hi = hi;
244 if (hi)
245 tasklet_hi_schedule(&data->tlet);
246 else
247 tasklet_schedule(&data->tlet);
248
249 /* wait for the buffer to fill */
250 wait_event_interruptible(data->wait, !data->loops);
251
252 if (signal_pending(current))
253 return -ERESTARTSYS;
254 buf2 = data->buf;
255 kfree(data);
256 *eof = 1;
257 return buf2 - buf;
258 }
259
260
261
262 int __init jit_init(void)
263 {
264 create_proc_read_entry("currentime", 0, NULL, jit_currentime, NULL);
265 create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY);
266 create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED);
267 create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE);
268 create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO);
269
270 create_proc_read_entry("jitimer", 0, NULL, jit_timer, NULL);
271 create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, NULL);
272 create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1);
273
274 return 0; /* success */
275 }
276
277 void __exit jit_cleanup(void)
278 {
279 remove_proc_entry("currentime", NULL);
280 remove_proc_entry("jitbusy", NULL);
281 remove_proc_entry("jitsched", NULL);
282 remove_proc_entry("jitqueue", NULL);
283 remove_proc_entry("jitschedto", NULL);
284
285 remove_proc_entry("jitimer", NULL);
286 remove_proc_entry("jitasklet", NULL);
287 remove_proc_entry("jitasklethi", NULL);
288 }
289
290 module_init(jit_init);
291 module_exit(jit_cleanup);
292
|
This page was automatically generated by the
LXR engine.
|