--- linux-2.6.16/kernel/sched.c-7.interactive_starvation 2006-03-27 06:11:01.000000000 +0200 +++ linux-2.6.16/kernel/sched.c 2006-03-30 10:50:46.000000000 +0200 @@ -371,7 +371,7 @@ */ unsigned long nr_uninterruptible; - unsigned long expired_timestamp; + unsigned long long expired_timestamp; unsigned long long timestamp_last_tick; task_t *curr, *idle; struct mm_struct *prev_mm; @@ -839,7 +839,7 @@ /* * It's time to switch arrays. */ - if (jiffies - rq->expired_timestamp >= limit) + if (jiffies - NS64_TO_JIFFIES(rq->expired_timestamp) >= limit) return 1; /* @@ -860,8 +860,12 @@ static inline void __activate_task(task_t *p, runqueue_t *rq) { prio_array_t *array = rq->active; - if (unlikely(expired_starving(rq))) + if (unlikely(expired_starving(rq) && !rt_task(p) && + p->last_ran > rq->expired_timestamp)) { array = rq->expired; + if (p->prio < rq->best_expired_prio) + rq->best_expired_prio = p->prio; + } enqueue_task(p, array); rq->nr_running++; } @@ -2880,12 +2884,12 @@ return; } + spin_lock(&rq->lock); /* Task might have expired already, but not scheduled off yet */ if (p->array != rq->active) { set_tsk_need_resched(p); - goto out; + goto out_unlock; } - spin_lock(&rq->lock); /* * The task was running during this tick - update the * time slice counter. Note: we do not update a thread's @@ -2921,15 +2925,38 @@ p->prio = effective_prio(p); if (!rq->expired_timestamp) - rq->expired_timestamp = jiffies; + rq->expired_timestamp = now; if (!TASK_INTERACTIVE(p) || expired_starving(rq)) { enqueue_task(p, rq->expired); - if (p->static_prio < rq->best_expired_prio) - rq->best_expired_prio = p->static_prio; + if (p->prio < rq->best_expired_prio) + rq->best_expired_prio = p->prio; } else enqueue_task(p, rq->active); } else { /* + * If tasks in the expired array are starving, increase the + * speed of the array switch. If we do not, tasks which are + * awakened on the expired array may suffer severe latency + * due to cpu hogs using their full slice. We don't want to + * switch too fast however, because it may well be these very + * tasks which were causing starvation to begin with. + */ + if (expired_starving(rq)) { + int limit = MIN_TIMESLICE + CURRENT_BONUS(p); + int runtime = now - p->timestamp; + + runtime = NS_TO_JIFFIES(runtime); + if (runtime >= limit && p->time_slice >= limit) { + + dequeue_task(p, rq->active); + enqueue_task(p, rq->expired); + set_tsk_need_resched(p); + if (p->prio < rq->best_expired_prio) + rq->best_expired_prio = p->prio; + } + } + + /* * Prevent a too long timeslice allowing a task to monopolize * the CPU. We do this by splitting up the timeslice into * smaller pieces. @@ -2945,10 +2972,9 @@ * This only applies to tasks in the interactive * delta range with at least TIMESLICE_GRANULARITY to requeue. */ - if (TASK_INTERACTIVE(p) && !((task_timeslice(p) - + else if (TASK_INTERACTIVE(p) && !((task_timeslice(p) - p->time_slice) % TIMESLICE_GRANULARITY(p)) && - (p->time_slice >= TIMESLICE_GRANULARITY(p)) && - (p->array == rq->active)) { + (p->time_slice >= TIMESLICE_GRANULARITY(p))) { requeue_task(p, rq->active); set_tsk_need_resched(p);