aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2008-05-02 19:00:27 -0400
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2008-05-02 19:00:27 -0400
commit2f030cd48bbdfc6f4155c38684d0e8b98195f4f5 (patch)
tree2d67fe40b43f2a05940b8c37375e83bfd42ef602
parentc55e411400c13bcfc774d541fc1c9f0f62b644c4 (diff)
LITMUS: rework job migration code
The old version had a significant window for races with interrupt handlers executing on other CPUs.
-rw-r--r--kernel/sched.c3
-rw-r--r--litmus/sched_litmus.c77
2 files changed, 55 insertions, 25 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index 00097dea89..170237e3a4 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3649,9 +3649,10 @@ need_resched_nonpreemptible:
3649 /* do litmus scheduling outside of rq lock, so that we 3649 /* do litmus scheduling outside of rq lock, so that we
3650 * can do proper migrations for global schedulers 3650 * can do proper migrations for global schedulers
3651 */ 3651 */
3652 litmus_schedule(rq, prev); 3652
3653 spin_lock(&rq->lock); 3653 spin_lock(&rq->lock);
3654 clear_tsk_need_resched(prev); 3654 clear_tsk_need_resched(prev);
3655 litmus_schedule(rq, prev);
3655 3656
3656 if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { 3657 if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
3657 if (unlikely((prev->state & TASK_INTERRUPTIBLE) && 3658 if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
diff --git a/litmus/sched_litmus.c b/litmus/sched_litmus.c
index 16cdf2db59..feb0159033 100644
--- a/litmus/sched_litmus.c
+++ b/litmus/sched_litmus.c
@@ -24,46 +24,75 @@ static void litmus_tick(struct rq *rq, struct task_struct *p)
24static void litmus_schedule(struct rq *rq, struct task_struct *prev) 24static void litmus_schedule(struct rq *rq, struct task_struct *prev)
25{ 25{
26 struct rq* other_rq; 26 struct rq* other_rq;
27 int success = 0; 27 long prev_state;
28 /* WARNING: rq is _not_ locked! */ 28 /* WARNING: rq is _not_ locked! */
29 if (is_realtime(prev)) 29 if (is_realtime(prev))
30 update_time_litmus(rq, prev); 30 update_time_litmus(rq, prev);
31 31
32 while (!success) { 32 /* let the plugin schedule */
33 /* let the plugin schedule */ 33 rq->litmus_next = litmus->schedule(prev);
34 rq->litmus_next = litmus->schedule(prev); 34
35 35 /* check if a global plugin pulled a task from a different RQ */
36 /* check if a global plugin pulled a task from a different RQ */ 36 if (rq->litmus_next && task_rq(rq->litmus_next) != rq) {
37 if (rq->litmus_next && task_rq(rq->litmus_next) != rq) { 37 /* we need to migrate the task */
38 /* we need to migrate the task */ 38 other_rq = task_rq(rq->litmus_next);
39 other_rq = task_rq(rq->litmus_next); 39 TRACE_TASK(rq->litmus_next, "migrate from %d\n", other_rq->cpu);
40 double_rq_lock(rq, other_rq); 40
41 /* now that we have the lock we need to make sure a 41 /* while we drop the lock, the prev task could change its
42 * couple of things still hold: 42 * state
43 * - it is still a real-time task 43 */
44 * - it is still runnable (could have been stopped) 44 prev_state = prev->state;
45 */ 45 spin_unlock(&rq->lock);
46 if (is_realtime(rq->litmus_next) && 46 double_rq_lock(rq, other_rq);
47 is_running(rq->litmus_next)) { 47 if (prev->state != prev_state) {
48 set_task_cpu(rq->litmus_next, smp_processor_id()); 48 TRACE_TASK(prev,
49 success = 1; 49 "state changed while we dropped"
50 } /* else something raced, retry */ 50 " the lock: now=%d, old=%d",
51 double_rq_unlock(rq, other_rq); 51 prev->state, prev_state);
52 } else 52 if (prev_state && !prev->state) {
53 success = 1; 53 /* prev task became unblocked
54 } 54 * we need to simulate normal sequence of events
55 * to scheduler plugins.
56 */
57 litmus->task_block(prev);
58 litmus->task_wake_up(prev);
59 }
60 }
61
62 set_task_cpu(rq->litmus_next, smp_processor_id());
63
64 /* now that we have the lock we need to make sure a
65 * couple of things still hold:
66 * - it is still a real-time task
67 * - it is still runnable (could have been stopped)
68 */
69 if (!is_realtime(rq->litmus_next) ||
70 !is_running(rq->litmus_next)) {
71 /* BAD BAD BAD */
72 TRACE_TASK(rq->litmus_next,
73 "migration invariant FAILED: rt=%d running=%d\n",
74 is_realtime(rq->litmus_next),
75 is_running(rq->litmus_next));
76 }
77 /* release the other CPU's runqueue, but keep ours */
78 spin_unlock(&other_rq->lock);
79 }
55} 80}
56 81
57static void enqueue_task_litmus(struct rq *rq, struct task_struct *p, int wakeup) 82static void enqueue_task_litmus(struct rq *rq, struct task_struct *p, int wakeup)
58{ 83{
59 if (wakeup) 84 if (wakeup)
60 litmus->task_wake_up(p); 85 litmus->task_wake_up(p);
86 else
87 TRACE_TASK(p, "ignoring an enqueue, not a wake up.\n");
61} 88}
62 89
63static void dequeue_task_litmus(struct rq *rq, struct task_struct *p, int sleep) 90static void dequeue_task_litmus(struct rq *rq, struct task_struct *p, int sleep)
64{ 91{
65 if (sleep) 92 if (sleep)
66 litmus->task_block(p); 93 litmus->task_block(p);
94 else
95 TRACE_TASK(p, "ignoring a dequeue, not going to sleep.\n");
67} 96}
68 97
69static void yield_task_litmus(struct rq *rq) 98static void yield_task_litmus(struct rq *rq)