Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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.