--- linux-2.6.0-test1.G8/kernel/sched.c.org Wed Aug 13 09:19:13 2003 +++ linux-2.6.0-test1.G8/kernel/sched.c Wed Aug 13 14:41:42 2003 @@ -358,6 +358,8 @@ if (sleep_time > 0) { unsigned long long sleep_avg; + unsigned long run_time = now - current->timestamp; + unsigned int slice = 1000000 * current->time_slice; /* * This code gives a bonus to interactive tasks. @@ -381,6 +383,22 @@ p->sleep_avg = sleep_avg; p->prio = effective_prio(p); } + /* + * If the awakened task has been asleep for longer than the + * waker has had the CPU plus round-robin time, and it is + * going to preempt, there is a good chance that the waker + * is not getting enough CPU to service the awakened task in + * a timely manner, and that this is the cause of the preempt. + * Take some of the resulting sleep_time from the awakened + * task, and give it to the waker. + */ + if (!in_interrupt() && p->mm && current->mm && sleep_avg > + current->sleep_avg + slice && sleep_time > run_time + + (1000000 * this_rq()->nr_running * TIMESLICE_GRANULARITY) && + TASK_PREEMPTS_CURR(p, task_rq(current))) { + current->sleep_avg += slice; + sleep_avg -= slice; + } } } @@ -1414,6 +1432,7 @@ next->timestamp = now; rq->nr_switches++; rq->curr = next; + next->timestamp = now; prepare_arch_switch(rq, next); prev = context_switch(rq, prev, next);