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.
|