Commit 23850f8d authored by Ingo Molnar's avatar Ingo Molnar

[PATCH] "interactivity changes", sched-2.5.64-B2

This fixes the SMP runqueue locking bug when updating the wakers
priority.  It also includes:

 - only update the priority and do a requeueing if the sleep average has
   changed. (this does not happen for pure CPU hogs or pure interactive
   tasks, so no need to requeue/recalc-prio in that case.) [All the
   necessary values are available at that point already, so gcc should
   have an easy job making this branch really cheap.]

 - do not do a full task activation in the migration-thread path - that is
   supposed to be near-atomic anyway.

 - fix up comments

I solved the SMP locking bug by moving the requeueing outside of
try_to_wake_up().  It does not matter that the priority update is not
atomically done now, since the current process wont do anything
inbetween.  (well, it could get preempted in a preemptible kernel, but
even that wont do any harm.)
parent 3ec83948
...@@ -321,10 +321,7 @@ static int effective_prio(task_t *p) ...@@ -321,10 +321,7 @@ static int effective_prio(task_t *p)
} }
/* /*
* activate_task - move a task to the runqueue. * __activate_task - move a task to the runqueue.
* Also update all the scheduling statistics stuff. (sleep average
* calculation, priority modifiers, etc.)
*/ */
static inline void __activate_task(task_t *p, runqueue_t *rq) static inline void __activate_task(task_t *p, runqueue_t *rq)
{ {
...@@ -332,9 +329,16 @@ static inline void __activate_task(task_t *p, runqueue_t *rq) ...@@ -332,9 +329,16 @@ static inline void __activate_task(task_t *p, runqueue_t *rq)
nr_running_inc(rq); nr_running_inc(rq);
} }
static inline void activate_task(task_t *p, runqueue_t *rq) /*
* activate_task - move a task to the runqueue and do priority recalculation
*
* Update all the scheduling statistics stuff. (sleep average
* calculation, priority modifiers, etc.)
*/
static inline int activate_task(task_t *p, runqueue_t *rq)
{ {
unsigned long sleep_time = jiffies - p->last_run; unsigned long sleep_time = jiffies - p->last_run;
int requeue_waker = 0;
if (sleep_time) { if (sleep_time) {
int sleep_avg; int sleep_avg;
...@@ -357,23 +361,25 @@ static inline void activate_task(task_t *p, runqueue_t *rq) ...@@ -357,23 +361,25 @@ static inline void activate_task(task_t *p, runqueue_t *rq)
*/ */
if (sleep_avg > MAX_SLEEP_AVG) { if (sleep_avg > MAX_SLEEP_AVG) {
if (!in_interrupt()) { if (!in_interrupt()) {
prio_array_t *array = current->array;
BUG_ON(!array);
sleep_avg += current->sleep_avg - MAX_SLEEP_AVG; sleep_avg += current->sleep_avg - MAX_SLEEP_AVG;
if (sleep_avg > MAX_SLEEP_AVG) if (sleep_avg > MAX_SLEEP_AVG)
sleep_avg = MAX_SLEEP_AVG; sleep_avg = MAX_SLEEP_AVG;
current->sleep_avg = sleep_avg; if (current->sleep_avg != sleep_avg) {
dequeue_task(current, array); current->sleep_avg = sleep_avg;
current->prio = effective_prio(current); requeue_waker = 1;
enqueue_task(current, array); }
} }
sleep_avg = MAX_SLEEP_AVG; sleep_avg = MAX_SLEEP_AVG;
} }
p->sleep_avg = sleep_avg; if (p->sleep_avg != sleep_avg) {
p->prio = effective_prio(p); p->sleep_avg = sleep_avg;
p->prio = effective_prio(p);
}
} }
__activate_task(p, rq); __activate_task(p, rq);
return requeue_waker;
} }
/* /*
...@@ -486,8 +492,8 @@ void kick_if_running(task_t * p) ...@@ -486,8 +492,8 @@ void kick_if_running(task_t * p)
*/ */
static int try_to_wake_up(task_t * p, unsigned int state, int sync) static int try_to_wake_up(task_t * p, unsigned int state, int sync)
{ {
int success = 0, requeue_waker = 0;
unsigned long flags; unsigned long flags;
int success = 0;
long old_state; long old_state;
runqueue_t *rq; runqueue_t *rq;
...@@ -513,7 +519,7 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync) ...@@ -513,7 +519,7 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
if (sync) if (sync)
__activate_task(p, rq); __activate_task(p, rq);
else { else {
activate_task(p, rq); requeue_waker = activate_task(p, rq);
if (p->prio < rq->curr->prio) if (p->prio < rq->curr->prio)
resched_task(rq->curr); resched_task(rq->curr);
} }
...@@ -523,6 +529,21 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync) ...@@ -523,6 +529,21 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
} }
task_rq_unlock(rq, &flags); task_rq_unlock(rq, &flags);
/*
* We have to do this outside the other spinlock, the two
* runqueues might be different:
*/
if (requeue_waker) {
prio_array_t *array;
rq = task_rq_lock(current, &flags);
array = current->array;
dequeue_task(current, array);
current->prio = effective_prio(current);
enqueue_task(current, array);
task_rq_unlock(rq, &flags);
}
return success; return success;
} }
...@@ -2360,7 +2381,7 @@ static int migration_thread(void * data) ...@@ -2360,7 +2381,7 @@ static int migration_thread(void * data)
set_task_cpu(p, cpu_dest); set_task_cpu(p, cpu_dest);
if (p->array) { if (p->array) {
deactivate_task(p, rq_src); deactivate_task(p, rq_src);
activate_task(p, rq_dest); __activate_task(p, rq_dest);
if (p->prio < rq_dest->curr->prio) if (p->prio < rq_dest->curr->prio)
resched_task(rq_dest->curr); resched_task(rq_dest->curr);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment