Contents of /trunk/kernel26-alx/patches-2.6.21-r14/0006-2.6.21-sched-idleprio-2.3.patch
Parent Directory | Revision Log
Revision 447 -
(show annotations)
(download)
Tue Jan 22 17:55:52 2008 UTC (16 years, 8 months ago) by niro
File size: 11511 byte(s)
Tue Jan 22 17:55:52 2008 UTC (16 years, 8 months ago) by niro
File size: 11511 byte(s)
-2.6.21-alx-r14 - fixed some natsemi errors on wys terminals
1 | 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 */ |