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  * jiq.c -- the just-in-queue module
  3  *
  4  * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
  5  * Copyright (C) 2001 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: jiq.c,v 1.7 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/sched.h>
 23 #include <linux/kernel.h>
 24 #include <linux/fs.h>     /* everything... */
 25 #include <linux/proc_fs.h>
 26 #include <linux/errno.h>  /* error codes */
 27 #include <linux/workqueue.h>
 28 #include <linux/preempt.h>
 29 #include <linux/interrupt.h> /* tasklets */
 30 
 31 MODULE_LICENSE("Dual BSD/GPL");
 32 
 33 /*
 34  * The delay for the delayed workqueue timer file.
 35  */
 36 static long delay = 1;
 37 module_param(delay, long, 0);
 38 
 39 /*
 40  * This module is a silly one: it only embeds short code fragments
 41  * that show how enqueued tasks `feel' the environment
 42  */
 43 
 44 #define LIMIT   (PAGE_SIZE-128) /* don't print any more after this size */
 45 
 46 /*
 47  * Print information about the current environment. This is called from
 48  * within the task queues. If the limit is reched, awake the reading
 49  * process.
 50  */
 51 static DECLARE_WAIT_QUEUE_HEAD (jiq_wait);
 52 
 53 /*
 54  * Keep track of info we need between task queue runs.
 55  */
 56 static struct clientdata {
 57         int len;
 58         char *buf;
 59         unsigned long jiffies;
 60         long delay;
 61         struct delayed_work work;
 62 } jiq_data;
 63 
 64 #define SCHEDULER_QUEUE ((task_queue *) 1)
 65 
 66 static void jiq_print_tasklet(unsigned long);
 67 static DECLARE_TASKLET(jiq_tasklet, jiq_print_tasklet, (unsigned long)&jiq_data);
 68 
 69 
 70 /*
 71  * Do the printing; return non-zero if the task should be rescheduled.
 72  */
 73 static int jiq_print(void *ptr)
 74 {
 75         struct clientdata *data = ptr;
 76         int len = data->len;
 77         char *buf = data->buf;
 78         unsigned long j = jiffies;
 79 
 80         if (len > LIMIT) { 
 81                 wake_up_interruptible(&jiq_wait);
 82                 return 0;
 83         }
 84 
 85         if (len == 0)
 86                 len = sprintf(buf,"    time  delta preempt   pid cpu command\n");
 87         else
 88                 len =0;
 89 
 90         /* intr_count is only exported since 1.3.5, but 1.99.4 is needed anyways */
 91         len += sprintf(buf+len, "%9li  %4li     %3i %5i %3i %s\n",
 92                         j, j - data->jiffies,
 93                         preempt_count(), current->pid, smp_processor_id(),
 94                         current->comm);
 95 
 96         data->len += len;
 97         data->buf += len;
 98         data->jiffies = j;
 99         return 1;
100 }
101 
102 
103 /*
104  * Call jiq_print from a work queue
105  */
106 static void jiq_print_wq(struct work_struct *ptr)
107 {
108         struct clientdata *data = (struct clientdata *) ptr;
109     
110         if (! jiq_print (ptr))
111                 return;
112     
113         if (data->delay)
114                 schedule_delayed_work(&jiq_data.work, data->delay);
115         else
116                 schedule_work(&jiq_data.work.work);
117 }
118 
119 static int jiq_read_wq(char *buf, char **start, off_t offset,
120                    int len, int *eof, void *data)
121 {
122         DEFINE_WAIT(wait);
123         
124         jiq_data.len = 0;                /* nothing printed, yet */
125         jiq_data.buf = buf;              /* print in this place */
126         jiq_data.jiffies = jiffies;      /* initial time */
127         jiq_data.delay = 0;
128     
129         prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
130         schedule_work(&jiq_data.work.work);
131         schedule();
132         finish_wait(&jiq_wait, &wait);
133 
134         *eof = 1;
135         return jiq_data.len;
136 }
137 
138 
139 static int jiq_read_wq_delayed(char *buf, char **start, off_t offset,
140                    int len, int *eof, void *data)
141 {
142         DEFINE_WAIT(wait);
143         
144         jiq_data.len = 0;                /* nothing printed, yet */
145         jiq_data.buf = buf;              /* print in this place */
146         jiq_data.jiffies = jiffies;      /* initial time */
147         jiq_data.delay = delay;
148     
149         prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE);
150         schedule_delayed_work(&jiq_data.work, delay);
151         schedule();
152         finish_wait(&jiq_wait, &wait);
153 
154         *eof = 1;
155         return jiq_data.len;
156 }
157 
158 
159 
160 
161 /*
162  * Call jiq_print from a tasklet
163  */
164 static void jiq_print_tasklet(unsigned long ptr)
165 {
166         if (jiq_print ((void *) ptr))
167                 tasklet_schedule (&jiq_tasklet);
168 }
169 
170 
171 
172 static int jiq_read_tasklet(char *buf, char **start, off_t offset, int len,
173                 int *eof, void *data)
174 {
175         jiq_data.len = 0;                /* nothing printed, yet */
176         jiq_data.buf = buf;              /* print in this place */
177         jiq_data.jiffies = jiffies;      /* initial time */
178 
179         tasklet_schedule(&jiq_tasklet);
180         interruptible_sleep_on(&jiq_wait);    /* sleep till completion */
181 
182         *eof = 1;
183         return jiq_data.len;
184 }
185 
186 
187 
188 
189 /*
190  * This one, instead, tests out the timers.
191  */
192 
193 static struct timer_list jiq_timer;
194 
195 static void jiq_timedout(unsigned long ptr)
196 {
197         jiq_print((void *)ptr);            /* print a line */
198         wake_up_interruptible(&jiq_wait);  /* awake the process */
199 }
200 
201 
202 static int jiq_read_run_timer(char *buf, char **start, off_t offset,
203                    int len, int *eof, void *data)
204 {
205 
206         jiq_data.len = 0;           /* prepare the argument for jiq_print() */
207         jiq_data.buf = buf;
208         jiq_data.jiffies = jiffies;
209 
210         init_timer(&jiq_timer);              /* init the timer structure */
211         jiq_timer.function = jiq_timedout;
212         jiq_timer.data = (unsigned long)&jiq_data;
213         jiq_timer.expires = jiffies + HZ; /* one second */
214 
215         jiq_print(&jiq_data);   /* print and go to sleep */
216         add_timer(&jiq_timer);
217         interruptible_sleep_on(&jiq_wait);  /* RACE */
218         del_timer_sync(&jiq_timer);  /* in case a signal woke us up */
219     
220         *eof = 1;
221         return jiq_data.len;
222 }
223 
224 
225 
226 /*
227  * the init/clean material
228  */
229 
230 static int jiq_init(void)
231 {
232 
233         /* this line is in jiq_init() */
234         INIT_DELAYED_WORK(&jiq_data.work, jiq_print_wq);
235 
236         create_proc_read_entry("jiqwq", 0, NULL, jiq_read_wq, NULL);
237         create_proc_read_entry("jiqwqdelay", 0, NULL, jiq_read_wq_delayed, NULL);
238         create_proc_read_entry("jitimer", 0, NULL, jiq_read_run_timer, NULL);
239         create_proc_read_entry("jiqtasklet", 0, NULL, jiq_read_tasklet, NULL);
240 
241         return 0; /* succeed */
242 }
243 
244 static void jiq_cleanup(void)
245 {
246         remove_proc_entry("jiqwq", NULL);
247         remove_proc_entry("jiqwqdelay", NULL);
248         remove_proc_entry("jitimer", NULL);
249         remove_proc_entry("jiqtasklet", NULL);
250 }
251 
252 
253 module_init(jiq_init);
254 module_exit(jiq_cleanup);
255 
  This page was automatically generated by the LXR engine.