Annotation of /trunk/kernel26-tinyalx/patches-2.6.21-r14/0006-2.6.21-sched-idleprio-2.3.patch
Parent Directory | Revision Log
Revision 453 -
(hide annotations)
(download)
Fri Jan 25 23:34:48 2008 UTC (16 years, 8 months ago) by niro
File size: 11511 byte(s)
Fri Jan 25 23:34:48 2008 UTC (16 years, 8 months ago) by niro
File size: 11511 byte(s)
-tiny-alx 2.6.21-tinyalx-r14
1 | niro | 453 | Add the SCHED_IDLEPRIO scheduling policy. Tasks set to this policy are only |
2 | given cpu time if no other tasks at all wish to have cpu time thus running | ||
3 | effectively at idle priority. If semaphores or mutexes are held, or the | ||
4 | system is going into suspend, schedule them as SCHED_NORMAL nice 19. | ||
5 | |||
6 | Signed-off-by: Con Kolivas <kernel@kolivas.org> | ||
7 | --- | ||
8 | include/linux/sched.h | 5 + | ||
9 | kernel/sched.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++---- | ||
10 | 2 files changed, 138 insertions(+), 12 deletions(-) | ||
11 | |||
12 | Index: linux-2.6.21-ck2/include/linux/sched.h | ||
13 | =================================================================== | ||
14 | --- linux-2.6.21-ck2.orig/include/linux/sched.h 2007-05-14 19:30:31.000000000 +1000 | ||
15 | +++ linux-2.6.21-ck2/include/linux/sched.h 2007-05-14 19:30:31.000000000 +1000 | ||
16 | @@ -35,10 +35,11 @@ | ||
17 | #define SCHED_RR 2 | ||
18 | #define SCHED_BATCH 3 | ||
19 | #define SCHED_ISO 4 | ||
20 | +#define SCHED_IDLEPRIO 5 | ||
21 | |||
22 | #ifdef __KERNEL__ | ||
23 | |||
24 | -#define SCHED_MAX SCHED_ISO | ||
25 | +#define SCHED_MAX SCHED_IDLEPRIO | ||
26 | #define SCHED_RANGE(policy) ((policy) <= SCHED_MAX) | ||
27 | |||
28 | struct sched_param { | ||
29 | @@ -537,6 +538,7 @@ struct signal_struct { | ||
30 | (policy) == SCHED_RR) | ||
31 | #define has_rt_policy(p) unlikely(is_rt_policy((p)->policy)) | ||
32 | #define iso_task(p) unlikely((p)->policy == SCHED_ISO) | ||
33 | +#define idleprio_task(p) unlikely((p)->policy == SCHED_IDLEPRIO) | ||
34 | |||
35 | /* | ||
36 | * Some day this will be a full-fledged user tracking system.. | ||
37 | @@ -1173,6 +1175,7 @@ static inline void put_task_struct(struc | ||
38 | #define PF_ISOREF 0x04000000 /* SCHED_ISO task has used up quota */ | ||
39 | #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ | ||
40 | #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ | ||
41 | +#define PF_NONSLEEP 0x40000000 /* Waiting on in-kernel activity */ | ||
42 | |||
43 | /* | ||
44 | * Only the _current_ task can read/write to tsk->flags, but other | ||
45 | Index: linux-2.6.21-ck2/kernel/sched.c | ||
46 | =================================================================== | ||
47 | --- linux-2.6.21-ck2.orig/kernel/sched.c 2007-05-14 19:30:31.000000000 +1000 | ||
48 | +++ linux-2.6.21-ck2/kernel/sched.c 2007-05-14 19:30:31.000000000 +1000 | ||
49 | @@ -144,7 +144,7 @@ struct rq; | ||
50 | */ | ||
51 | struct prio_array { | ||
52 | /* Tasks queued at each priority */ | ||
53 | - struct list_head queue[MAX_PRIO]; | ||
54 | + struct list_head queue[MAX_PRIO + 1]; | ||
55 | |||
56 | /* | ||
57 | * The bitmap of priorities queued for this array. While the expired | ||
58 | @@ -201,7 +201,7 @@ struct rq { | ||
59 | unsigned long next_balance; | ||
60 | struct mm_struct *prev_mm; | ||
61 | |||
62 | - struct prio_array *active, *expired, arrays[2]; | ||
63 | + struct prio_array *active, *expired, *idleprio, arrays[2]; | ||
64 | unsigned long *dyn_bitmap, *exp_bitmap; | ||
65 | |||
66 | /* | ||
67 | @@ -215,6 +215,8 @@ struct rq { | ||
68 | unsigned long iso_ticks; | ||
69 | unsigned short iso_refractory; | ||
70 | |||
71 | + /* Number of idleprio tasks running */ | ||
72 | + unsigned long nr_idleprio; | ||
73 | atomic_t nr_iowait; | ||
74 | |||
75 | #ifdef CONFIG_SMP | ||
76 | @@ -652,6 +654,17 @@ sched_info_switch(struct task_struct *pr | ||
77 | #define sched_info_switch(t, next) do { } while (0) | ||
78 | #endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */ | ||
79 | |||
80 | +static int idleprio_suitable(struct task_struct *p) | ||
81 | +{ | ||
82 | + return (!p->mutexes_held && !freezing(p) && !signal_pending(p) && | ||
83 | + !(p->flags & (PF_NONSLEEP | PF_EXITING))); | ||
84 | +} | ||
85 | + | ||
86 | +static int idleprio(const struct task_struct *p) | ||
87 | +{ | ||
88 | + return (p->prio == MAX_PRIO); | ||
89 | +} | ||
90 | + | ||
91 | static inline int task_queued(struct task_struct *task) | ||
92 | { | ||
93 | return !list_empty(&task->run_list); | ||
94 | @@ -668,7 +681,9 @@ static inline void set_dynamic_bit(struc | ||
95 | static void dequeue_task(struct task_struct *p, struct rq *rq) | ||
96 | { | ||
97 | list_del_init(&p->run_list); | ||
98 | - if (list_empty(p->array->queue + p->prio)) | ||
99 | + if (idleprio_task(p) && idleprio(p)) | ||
100 | + rq->nr_idleprio--; | ||
101 | + else if (list_empty(p->array->queue + p->prio)) | ||
102 | __clear_bit(p->prio, p->array->prio_bitmap); | ||
103 | } | ||
104 | |||
105 | @@ -809,6 +824,8 @@ static inline int isoprio_suitable(struc | ||
106 | return !(p->flags & PF_ISOREF); | ||
107 | } | ||
108 | |||
109 | +static int task_timeslice(struct task_struct *p); | ||
110 | + | ||
111 | /* | ||
112 | * recalc_task_prio determines what priority a non rt_task will be | ||
113 | * queued at. If the task has already been running during this runqueue's | ||
114 | @@ -842,6 +859,30 @@ static void recalc_task_prio(struct task | ||
115 | /* Just about to be demoted to SCHED_NORMAL */ | ||
116 | p->time_slice = 0; | ||
117 | } | ||
118 | + } else if (idleprio_task(p)) { | ||
119 | + if (idleprio_suitable(p)) { | ||
120 | + /* | ||
121 | + * If suitable idleprio_tasks are queued at MAX_PRIO | ||
122 | + * only on the idleprio array. Their time_slice is | ||
123 | + * their full task_timeslice as they cooperatively | ||
124 | + * multitask. | ||
125 | + */ | ||
126 | + p->prio = p->normal_prio = MAX_PRIO; | ||
127 | + p->array = rq->idleprio; | ||
128 | + if (p->time_slice <= 0) | ||
129 | + p->time_slice = task_timeslice(p); | ||
130 | + return; | ||
131 | + } | ||
132 | + /* | ||
133 | + * If unsuitable idleprio_tasks are queued equivalent to | ||
134 | + * nice 19 tasks on the expired array. | ||
135 | + */ | ||
136 | + p->flags &= ~PF_NONSLEEP; | ||
137 | + p->prio = p->normal_prio = MAX_PRIO - 1; | ||
138 | + p->array = rq->expired; | ||
139 | + if (p->time_slice <= 0 || p->time_slice > p->quota) | ||
140 | + p->time_slice = p->quota; | ||
141 | + return; | ||
142 | } | ||
143 | |||
144 | update_if_moved(p, rq); | ||
145 | @@ -878,6 +919,8 @@ static inline void __enqueue_task(struct | ||
146 | else | ||
147 | recalc_task_prio(p, rq); | ||
148 | |||
149 | + if (idleprio_task(p) && idleprio(p)) | ||
150 | + rq->nr_idleprio++; | ||
151 | sched_info_queued(p); | ||
152 | set_dynamic_bit(p, rq); | ||
153 | } | ||
154 | @@ -942,6 +985,8 @@ static int task_timeslice(struct task_st | ||
155 | |||
156 | static void set_load_weight(struct task_struct *p) | ||
157 | { | ||
158 | + int load_weight; | ||
159 | + | ||
160 | if (has_rt_policy(p)) { | ||
161 | #ifdef CONFIG_SMP | ||
162 | if (p == task_rq(p)->migration_thread) | ||
163 | @@ -950,12 +995,19 @@ static void set_load_weight(struct task_ | ||
164 | * Giving its load any weight will skew balancing | ||
165 | * adversely. | ||
166 | */ | ||
167 | - p->load_weight = 0; | ||
168 | + load_weight = 0; | ||
169 | else | ||
170 | #endif | ||
171 | - p->load_weight = RTPRIO_TO_LOAD_WEIGHT(p->rt_priority); | ||
172 | + load_weight = RTPRIO_TO_LOAD_WEIGHT(p->rt_priority); | ||
173 | } else | ||
174 | - p->load_weight = task_timeslice(p); | ||
175 | + load_weight = task_timeslice(p); | ||
176 | + /* | ||
177 | + * idleprio tasks have much lower weight than SCHED_NORMAL tasks but | ||
178 | + * still need to be weighted to allow balancing to occur. | ||
179 | + */ | ||
180 | + if (likely(!idleprio_task(p))) | ||
181 | + load_weight *= PRIO_RANGE; | ||
182 | + p->load_weight = load_weight; | ||
183 | } | ||
184 | |||
185 | static inline void | ||
186 | @@ -1653,6 +1705,14 @@ out_activate: | ||
187 | out_running: | ||
188 | p->state = TASK_RUNNING; | ||
189 | out: | ||
190 | + /* | ||
191 | + * Special case when freezing we need to reschedule idleprio tasks | ||
192 | + * as SCHED_NORMAL or else they'll never freeze | ||
193 | + */ | ||
194 | + if (idleprio_task(p) && freezing(p) && idleprio(p)) { | ||
195 | + dequeue_task(p, rq); | ||
196 | + enqueue_task(p, rq); | ||
197 | + } | ||
198 | task_rq_unlock(rq, &flags); | ||
199 | |||
200 | return success; | ||
201 | @@ -2263,7 +2323,9 @@ skip_bitmap: | ||
202 | idx = sched_find_first_bit(array->prio_bitmap); | ||
203 | else | ||
204 | idx = find_next_bit(array->prio_bitmap, MAX_PRIO, idx); | ||
205 | - if (idx >= MAX_PRIO) { | ||
206 | + if (idx == MAX_PRIO) { | ||
207 | + if (array == busiest->idleprio && busiest->nr_idleprio) | ||
208 | + goto found_idleprio; | ||
209 | if (array == busiest->expired) { | ||
210 | array = busiest->active; | ||
211 | goto new_array; | ||
212 | @@ -2271,6 +2333,7 @@ skip_bitmap: | ||
213 | goto out; | ||
214 | } | ||
215 | |||
216 | +found_idleprio: | ||
217 | head = array->queue + idx; | ||
218 | curr = head->prev; | ||
219 | skip_queue: | ||
220 | @@ -2292,6 +2355,17 @@ skip_queue: | ||
221 | best_prio_seen |= idx == best_prio; | ||
222 | if (curr != head) | ||
223 | goto skip_queue; | ||
224 | + if (idx == MAX_PRIO) { | ||
225 | + /* | ||
226 | + * Occurs either when balancing idleprio tasks or | ||
227 | + * there really are no more tasks to find. | ||
228 | + */ | ||
229 | + if (array == busiest->expired) { | ||
230 | + array = busiest->active; | ||
231 | + goto new_array; | ||
232 | + } | ||
233 | + goto out; | ||
234 | + } | ||
235 | idx++; | ||
236 | goto skip_bitmap; | ||
237 | } | ||
238 | @@ -2309,6 +2383,13 @@ skip_queue: | ||
239 | this_best_prio = idx; | ||
240 | if (curr != head) | ||
241 | goto skip_queue; | ||
242 | + if (idx == MAX_PRIO) { | ||
243 | + if (array == busiest->expired) { | ||
244 | + array = busiest->active; | ||
245 | + goto new_array; | ||
246 | + } | ||
247 | + goto out; | ||
248 | + } | ||
249 | idx++; | ||
250 | goto skip_bitmap; | ||
251 | } | ||
252 | @@ -3136,7 +3217,7 @@ void account_user_time(struct task_struc | ||
253 | |||
254 | /* Add user time to cpustat. */ | ||
255 | tmp = cputime_to_cputime64(cputime); | ||
256 | - if (TASK_NICE(p) > 0) | ||
257 | + if (TASK_NICE(p) > 0 || idleprio_task(p)) | ||
258 | cpustat->nice = cputime64_add(cpustat->nice, tmp); | ||
259 | else | ||
260 | cpustat->user = cputime64_add(cpustat->user, tmp); | ||
261 | @@ -3351,6 +3432,28 @@ static void reset_prio_levels(struct rq | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | + * Only tasks running are SCHED_IDLEPRIO. Set the active array to the | ||
266 | + * idleprio array and if it isn't already active | ||
267 | + */ | ||
268 | +static struct task_struct *next_idleprio_task(struct rq *rq) | ||
269 | +{ | ||
270 | + struct prio_array *array = rq->active; | ||
271 | + struct list_head *queue; | ||
272 | + | ||
273 | + if (array != rq->idleprio) { | ||
274 | + rq->active = rq->idleprio; | ||
275 | + rq->expired = array; | ||
276 | + array = rq->active; | ||
277 | + rq->exp_bitmap = rq->expired->prio_bitmap; | ||
278 | + rq->dyn_bitmap = rq->active->prio_bitmap; | ||
279 | + } | ||
280 | + rq->prio_rotation++; | ||
281 | + reset_prio_levels(rq); | ||
282 | + queue = array->queue + MAX_PRIO; | ||
283 | + return list_entry(queue->next, struct task_struct, run_list); | ||
284 | +} | ||
285 | + | ||
286 | +/* | ||
287 | * next_dynamic_task finds the next suitable dynamic task. | ||
288 | */ | ||
289 | static inline struct task_struct *next_dynamic_task(struct rq *rq, int idx) | ||
290 | @@ -3361,6 +3464,8 @@ static inline struct task_struct *next_d | ||
291 | int nstatic; | ||
292 | |||
293 | retry: | ||
294 | + if (unlikely(rq->nr_running == rq->nr_idleprio)) | ||
295 | + return next_idleprio_task(rq); | ||
296 | if (idx >= MAX_PRIO) { | ||
297 | /* There are no more tasks in the active array. Swap arrays */ | ||
298 | array = rq->expired; | ||
299 | @@ -3451,8 +3556,10 @@ need_resched_nonpreemptible: | ||
300 | unlikely(signal_pending(prev)))) | ||
301 | prev->state = TASK_RUNNING; | ||
302 | else { | ||
303 | - if (prev->state == TASK_UNINTERRUPTIBLE) | ||
304 | + if (prev->state == TASK_UNINTERRUPTIBLE) { | ||
305 | + prev->flags |= PF_NONSLEEP; | ||
306 | rq->nr_uninterruptible++; | ||
307 | + } | ||
308 | deactivate_task(prev, rq); | ||
309 | } | ||
310 | } | ||
311 | @@ -3994,7 +4101,8 @@ void set_user_nice(struct task_struct *p | ||
312 | * If the task increased its priority or is running and | ||
313 | * lowered its priority, then reschedule its CPU: | ||
314 | */ | ||
315 | - if (delta < 0 || (delta > 0 && task_running(rq, p))) | ||
316 | + if (delta < 0 || ((delta > 0 || idleprio_task(p)) && | ||
317 | + task_running(rq, p))) | ||
318 | resched_task(rq->curr); | ||
319 | } | ||
320 | out_unlock: | ||
321 | @@ -4195,6 +4303,11 @@ recheck: | ||
322 | return -EPERM; | ||
323 | } | ||
324 | |||
325 | + if (!(p->mm) && policy == SCHED_IDLEPRIO) { | ||
326 | + /* Don't allow kernel threads to be SCHED_IDLEPRIO. */ | ||
327 | + return -EINVAL; | ||
328 | + } | ||
329 | + | ||
330 | retval = security_task_setscheduler(p, policy, param); | ||
331 | if (retval) | ||
332 | return retval; | ||
333 | @@ -4520,12 +4633,18 @@ asmlinkage long sys_sched_yield(void) | ||
334 | struct prio_array *old_array = p->array; | ||
335 | int old_prio = p->prio; | ||
336 | |||
337 | + if (idleprio_task(p)) { | ||
338 | + dequeue_task(p, rq); | ||
339 | + enqueue_task(p, rq); | ||
340 | + goto out_release; | ||
341 | + } | ||
342 | /* p->prio will be updated in requeue_task via queue_expired */ | ||
343 | if (!rt_task(p)) | ||
344 | p->array = rq->expired; | ||
345 | requeue_task(p, rq, old_array, old_prio); | ||
346 | } | ||
347 | |||
348 | +out_release: | ||
349 | /* | ||
350 | * Since we are going to call schedule() anyway, there's | ||
351 | * no need to preempt or enable interrupts: | ||
352 | @@ -4678,6 +4797,7 @@ asmlinkage long sys_sched_get_priority_m | ||
353 | case SCHED_NORMAL: | ||
354 | case SCHED_BATCH: | ||
355 | case SCHED_ISO: | ||
356 | + case SCHED_IDLEPRIO: | ||
357 | ret = 0; | ||
358 | break; | ||
359 | } | ||
360 | @@ -4703,6 +4823,7 @@ asmlinkage long sys_sched_get_priority_m | ||
361 | case SCHED_NORMAL: | ||
362 | case SCHED_BATCH: | ||
363 | case SCHED_ISO: | ||
364 | + case SCHED_IDLEPRIO: | ||
365 | ret = 0; | ||
366 | } | ||
367 | return ret; | ||
368 | @@ -6812,8 +6933,10 @@ void __init sched_init(void) | ||
369 | lockdep_set_class(&rq->lock, &rq->rq_lock_key); | ||
370 | rq->iso_ticks = 0; | ||
371 | rq->nr_running = 0; | ||
372 | + rq->nr_idleprio = 0; | ||
373 | rq->prio_rotation = 0; | ||
374 | rq->active = rq->arrays; | ||
375 | + rq->idleprio = rq->active; | ||
376 | rq->expired = rq->arrays + 1; | ||
377 | reset_prio_levels(rq); | ||
378 | rq->dyn_bitmap = rq->active->prio_bitmap; | ||
379 | @@ -6836,7 +6959,7 @@ void __init sched_init(void) | ||
380 | for (j = 0; j < 2; j++) { | ||
381 | |||
382 | array = rq->arrays + j; | ||
383 | - for (k = 0; k < MAX_PRIO; k++) | ||
384 | + for (k = 0; k <= MAX_PRIO; k++) | ||
385 | INIT_LIST_HEAD(array->queue + k); | ||
386 | bitmap_zero(array->prio_bitmap, MAX_PRIO); | ||
387 | /* delimiter for bitsearch */ |