diff options
-rw-r--r-- | litmus/sched_pdumb.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/litmus/sched_pdumb.c b/litmus/sched_pdumb.c index c4a123475160..af1076dc9be0 100644 --- a/litmus/sched_pdumb.c +++ b/litmus/sched_pdumb.c | |||
@@ -19,8 +19,11 @@ struct dumb_cpu { | |||
19 | int blocked; | 19 | int blocked; |
20 | raw_spinlock_t lock; | 20 | raw_spinlock_t lock; |
21 | }; | 21 | }; |
22 | |||
22 | /* Define AND initialize one dumb_cpu per CPU. | 23 | /* Define AND initialize one dumb_cpu per CPU. |
23 | * Use of this macro is good for safety and performance reasons. | 24 | * Use of this macro is good for safety and performance reasons. |
25 | * Beware: this macro creates global variables. If two plugins pick | ||
26 | * the same name here, this will not compile. | ||
24 | */ | 27 | */ |
25 | DEFINE_PER_CPU(struct dumb_cpu, pdumb_cpus); | 28 | DEFINE_PER_CPU(struct dumb_cpu, pdumb_cpus); |
26 | 29 | ||
@@ -40,7 +43,7 @@ static long pdumb_activate_plugin(void) | |||
40 | cpu = &per_cpu(pdumb_cpus, i); | 43 | cpu = &per_cpu(pdumb_cpus, i); |
41 | cpu->dumb_task = NULL; | 44 | cpu->dumb_task = NULL; |
42 | cpu->scheduled = 0; | 45 | cpu->scheduled = 0; |
43 | cpu->blocked = 0; | 46 | cpu->blocked = 0; |
44 | } | 47 | } |
45 | 48 | ||
46 | printk(KERN_ERR "Activated a dumb plugin!\n"); | 49 | printk(KERN_ERR "Activated a dumb plugin!\n"); |
@@ -55,6 +58,7 @@ static long pdumb_activate_plugin(void) | |||
55 | static long pdumb_admit_task(struct task_struct *t) | 58 | static long pdumb_admit_task(struct task_struct *t) |
56 | { | 59 | { |
57 | long ret; | 60 | long ret; |
61 | unsigned long flags; | ||
58 | int cpu_num = get_partition(t); | 62 | int cpu_num = get_partition(t); |
59 | 63 | ||
60 | /* Per CPU variables have to be accessed wierd. | 64 | /* Per CPU variables have to be accessed wierd. |
@@ -62,22 +66,23 @@ static long pdumb_admit_task(struct task_struct *t) | |||
62 | */ | 66 | */ |
63 | struct dumb_cpu *cpu = &per_cpu(pdumb_cpus, cpu_num); | 67 | struct dumb_cpu *cpu = &per_cpu(pdumb_cpus, cpu_num); |
64 | 68 | ||
65 | raw_spin_lock(&cpu->lock); | 69 | /* We are accessing state atomically, we need a lock and to |
70 | * disable irqs. | ||
71 | */ | ||
72 | raw_spin_lock_irqsave(&cpu->lock, flags); | ||
66 | 73 | ||
67 | if (cpu->dumb_task) { | 74 | if (cpu->dumb_task) { |
68 | printk(KERN_ERR "Already have a dumb task on %d!\n", | 75 | /* Reject the task, causing a failure in userspace */ |
69 | cpu_num); | 76 | printk(KERN_ERR "Already have a dumb task on %d!\n", cpu_num); |
70 | ret = -EINVAL; | 77 | ret = -EINVAL; |
71 | } else { | 78 | } else { |
72 | printk(KERN_ERR "Taking your dumb task on %d!\n", | 79 | /* Assign our dumb task */ |
73 | cpu_num); | 80 | printk(KERN_ERR "Taking your dumb task on %d!\n", cpu_num); |
74 | |||
75 | /* Assign our dumb task! */ | ||
76 | cpu->dumb_task = t; | 81 | cpu->dumb_task = t; |
77 | ret = 0; | 82 | ret = 0; |
78 | } | 83 | } |
79 | 84 | ||
80 | raw_spin_unlock(&cpu->lock); | 85 | raw_spin_unlock_irqrestore(&cpu->lock, flags); |
81 | return ret; | 86 | return ret; |
82 | } | 87 | } |
83 | 88 | ||
@@ -89,15 +94,16 @@ static void pdumb_task_new(struct task_struct *t, int on_rq, int running) | |||
89 | { | 94 | { |
90 | /* Needed to disable interrupts */ | 95 | /* Needed to disable interrupts */ |
91 | unsigned long flags; | 96 | unsigned long flags; |
92 | /* The macro __get_cpu_var() returns the local cpu variable */ | ||
93 | struct dumb_cpu *cpu = &per_cpu(pdumb_cpus, get_partition(t)); | 97 | struct dumb_cpu *cpu = &per_cpu(pdumb_cpus, get_partition(t)); |
94 | 98 | ||
95 | /* We are accessing state atomically, we need a lock and to | ||
96 | * disable irqs. | ||
97 | */ | ||
98 | raw_spin_lock_irqsave(&cpu->lock, flags); | 99 | raw_spin_lock_irqsave(&cpu->lock, flags); |
99 | 100 | ||
100 | /* The task could already be running in Linux. | 101 | /* We only admit one task per cpu, this better be it */ |
102 | BUG_ON(cpu->dumb_task != t); | ||
103 | |||
104 | /* The task could already be running in Linux. For example, it | ||
105 | * could have been running, then switched into real-time | ||
106 | * mode. This is how all real-time tasks begin execution. | ||
101 | * Lets just say its running here too. | 107 | * Lets just say its running here too. |
102 | */ | 108 | */ |
103 | if (running) { | 109 | if (running) { |
@@ -120,6 +126,7 @@ static void pdumb_task_exit(struct task_struct *t) | |||
120 | raw_spin_lock_irqsave(&cpu->lock, flags); | 126 | raw_spin_lock_irqsave(&cpu->lock, flags); |
121 | cpu->dumb_task = NULL; | 127 | cpu->dumb_task = NULL; |
122 | cpu->scheduled = 0; | 128 | cpu->scheduled = 0; |
129 | cpu->blocked = 0; | ||
123 | raw_spin_unlock_irqrestore(&cpu->lock, flags); | 130 | raw_spin_unlock_irqrestore(&cpu->lock, flags); |
124 | } | 131 | } |
125 | 132 | ||
@@ -131,6 +138,7 @@ static void pdumb_task_exit(struct task_struct *t) | |||
131 | */ | 138 | */ |
132 | static struct task_struct* pdumb_schedule(struct task_struct *prev) | 139 | static struct task_struct* pdumb_schedule(struct task_struct *prev) |
133 | { | 140 | { |
141 | /* The macro __get_cpu_var() returns the local cpu variable */ | ||
134 | struct dumb_cpu *cpu = &__get_cpu_var(pdumb_cpus); | 142 | struct dumb_cpu *cpu = &__get_cpu_var(pdumb_cpus); |
135 | struct task_struct *sched; | 143 | struct task_struct *sched; |
136 | 144 | ||
@@ -140,6 +148,7 @@ static struct task_struct* pdumb_schedule(struct task_struct *prev) | |||
140 | */ | 148 | */ |
141 | raw_spin_lock(&cpu->lock); | 149 | raw_spin_lock(&cpu->lock); |
142 | 150 | ||
151 | /* Switch between dumb_task and nothing arbitrarily */ | ||
143 | if (cpu->scheduled || cpu->blocked || !cpu->dumb_task) { | 152 | if (cpu->scheduled || cpu->blocked || !cpu->dumb_task) { |
144 | cpu->scheduled = 0; | 153 | cpu->scheduled = 0; |
145 | sched = NULL; | 154 | sched = NULL; |
@@ -150,9 +159,15 @@ static struct task_struct* pdumb_schedule(struct task_struct *prev) | |||
150 | TRACE_TASK(cpu->dumb_task, "Scheduled!\n"); | 159 | TRACE_TASK(cpu->dumb_task, "Scheduled!\n"); |
151 | } | 160 | } |
152 | 161 | ||
162 | /* This must be done when the cpu state has been atomically | ||
163 | * chosen. This allows litmus to manage some race conditions | ||
164 | * with tasks blocking / preempting / releasing without any | ||
165 | * work on the plugin's part. | ||
166 | */ | ||
153 | sched_state_task_picked(); | 167 | sched_state_task_picked(); |
154 | 168 | ||
155 | raw_spin_unlock(&cpu->lock); | 169 | raw_spin_unlock(&cpu->lock); |
170 | |||
156 | return sched; | 171 | return sched; |
157 | } | 172 | } |
158 | 173 | ||
@@ -171,7 +186,7 @@ static void pdumb_task_block(struct task_struct *t) | |||
171 | TRACE_TASK(t, "Blocked!\n"); | 186 | TRACE_TASK(t, "Blocked!\n"); |
172 | 187 | ||
173 | raw_spin_lock_irqsave(&cpu->lock, flags); | 188 | raw_spin_lock_irqsave(&cpu->lock, flags); |
174 | cpu->blocked = 1; | 189 | cpu->blocked = 1; |
175 | cpu->scheduled = 0; | 190 | cpu->scheduled = 0; |
176 | raw_spin_unlock_irqrestore(&cpu->lock, flags); | 191 | raw_spin_unlock_irqrestore(&cpu->lock, flags); |
177 | } | 192 | } |
@@ -188,7 +203,7 @@ static void pdumb_task_wake_up(struct task_struct *t) | |||
188 | TRACE_TASK(t, "Awoken!\n"); | 203 | TRACE_TASK(t, "Awoken!\n"); |
189 | 204 | ||
190 | raw_spin_lock_irqsave(&cpu->lock, flags); | 205 | raw_spin_lock_irqsave(&cpu->lock, flags); |
191 | cpu->blocked = 0; | 206 | cpu->blocked = 0; |
192 | cpu->scheduled = 0; | 207 | cpu->scheduled = 0; |
193 | raw_spin_unlock_irqrestore(&cpu->lock, flags); | 208 | raw_spin_unlock_irqrestore(&cpu->lock, flags); |
194 | } | 209 | } |
@@ -212,6 +227,7 @@ static struct sched_plugin pdumb_plugin __cacheline_aligned_in_smp = { | |||
212 | .task_exit = pdumb_task_exit, | 227 | .task_exit = pdumb_task_exit, |
213 | }; | 228 | }; |
214 | 229 | ||
230 | |||
215 | /** | 231 | /** |
216 | * Called when the system boots up. | 232 | * Called when the system boots up. |
217 | */ | 233 | */ |