diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-06-14 02:37:32 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-06-14 02:37:32 -0400 |
commit | 836633b4ee918091913d701379f814394c939de7 (patch) | |
tree | 57f1d564954e7b2454481d4914446ee1dfb57eb8 | |
parent | 63360ea7ec23f403462e5335d4a3aed9d756a24e (diff) |
Scheduling of PGM jobs.wip-rtas12-pgm
-rw-r--r-- | include/litmus/rt_param.h | 7 | ||||
-rw-r--r-- | litmus/pgm.c | 93 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 6 |
3 files changed, 78 insertions, 28 deletions
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index a767e52882f4..5411f1251e57 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -129,8 +129,11 @@ struct pgm_consume | |||
129 | struct rt_pgm { | 129 | struct rt_pgm { |
130 | struct pgm_produce *produce; /* output and current state */ | 130 | struct pgm_produce *produce; /* output and current state */ |
131 | struct pgm_consume *consume; /* input constraints and current state */ | 131 | struct pgm_consume *consume; /* input constraints and current state */ |
132 | struct task_struct *root; /* root node of the PGM */ | 132 | struct task_struct *src; /* root node of the PGM */ |
133 | // struct task_struct *src; /* only not NULL if task is sink */ | 133 | |
134 | /* only valid for source nodes */ | ||
135 | struct completion children_ready; | ||
136 | atomic_t nr_children_pending; | ||
134 | }; | 137 | }; |
135 | 138 | ||
136 | #endif /* end PGM */ | 139 | #endif /* end PGM */ |
diff --git a/litmus/pgm.c b/litmus/pgm.c index 661fb2065dea..fe67d8f95d17 100644 --- a/litmus/pgm.c +++ b/litmus/pgm.c | |||
@@ -1,6 +1,8 @@ | |||
1 | 1 | ||
2 | #include <linux/slab.h> | 2 | #include <linux/slab.h> |
3 | #include <linux/spinlock.h> | 3 | #include <linux/spinlock.h> |
4 | #include <linux/completion.h> | ||
5 | #include <linux/atomic.h> | ||
4 | 6 | ||
5 | #include <litmus/pgm.h> | 7 | #include <litmus/pgm.h> |
6 | #include <litmus/sched_plugin.h> | 8 | #include <litmus/sched_plugin.h> |
@@ -11,7 +13,7 @@ | |||
11 | 13 | ||
12 | static void pgm_consume(struct task_struct *t); | 14 | static void pgm_consume(struct task_struct *t); |
13 | static void pgm_produce_intermediate(struct task_struct *t); | 15 | static void pgm_produce_intermediate(struct task_struct *t); |
14 | static void pgm_produce_root(struct task_struct *t); | 16 | static void pgm_produce_src(struct task_struct *t); |
15 | 17 | ||
16 | 18 | ||
17 | static inline int __is_pgm_satisfied(struct task_struct *t) | 19 | static inline int __is_pgm_satisfied(struct task_struct *t) |
@@ -41,10 +43,18 @@ static void pgm_produce(struct task_struct *t) | |||
41 | pgm_produce_intermediate(t); | 43 | pgm_produce_intermediate(t); |
42 | } | 44 | } |
43 | else { | 45 | else { |
44 | pgm_produce_root(t); | 46 | pgm_produce_src(t); |
45 | } | 47 | } |
46 | } | 48 | } |
47 | 49 | ||
50 | static void pgm_prepare_to_wake(struct task_struct *t) | ||
51 | { | ||
52 | // 't' is not a source node. | ||
53 | |||
54 | set_task_state(t, TASK_RUNNING); | ||
55 | |||
56 | /* TODO: Set our deadline! */ | ||
57 | } | ||
48 | 58 | ||
49 | static void pgm_produce_intermediate(struct task_struct *t) | 59 | static void pgm_produce_intermediate(struct task_struct *t) |
50 | { | 60 | { |
@@ -111,6 +121,7 @@ static void pgm_produce_intermediate(struct task_struct *t) | |||
111 | if(release_child) | 121 | if(release_child) |
112 | { | 122 | { |
113 | pgm_consume(child); | 123 | pgm_consume(child); |
124 | pgm_prepare_to_wake(child); | ||
114 | 125 | ||
115 | TRACE_TASK(t, "waking up %s/%d\n", child->comm, child->pid); | 126 | TRACE_TASK(t, "waking up %s/%d\n", child->comm, child->pid); |
116 | litmus->task_wake_up(child); | 127 | litmus->task_wake_up(child); |
@@ -119,18 +130,18 @@ static void pgm_produce_intermediate(struct task_struct *t) | |||
119 | } | 130 | } |
120 | 131 | ||
121 | 132 | ||
122 | static void pgm_produce_root(struct task_struct *t) | 133 | static void pgm_produce_src(struct task_struct *t) |
123 | { | 134 | { |
124 | struct task_struct *root; | 135 | struct task_struct *src; |
125 | BUG_ON(!is_pgm_sink(t)); | 136 | BUG_ON(!is_pgm_sink(t)); |
126 | 137 | ||
127 | root = tsk_rt(t)->pgm_params.root; | 138 | src = tsk_rt(t)->pgm_params.src; |
128 | 139 | ||
129 | TRACE_TASK(t, "waking up PGM root %s/%d\n", | 140 | TRACE_TASK(t, "waking up PGM src %s/%d\n", |
130 | root->comm, root->pid); | 141 | src->comm, src->pid); |
131 | 142 | ||
132 | /* wake up the new task, the task will sleep if it is too soon. */ | 143 | /* wake up the new task, the task will sleep if it is too soon. */ |
133 | litmus->task_wake_up(root); | 144 | litmus->task_wake_up(src); |
134 | } | 145 | } |
135 | 146 | ||
136 | 147 | ||
@@ -183,9 +194,27 @@ int is_pgm_satisfied(struct task_struct *t) | |||
183 | 194 | ||
184 | void pgm_prepare_for_next_period(struct task_struct *t) | 195 | void pgm_prepare_for_next_period(struct task_struct *t) |
185 | { | 196 | { |
197 | BUG_ON(!t); | ||
198 | |||
186 | TRACE_TASK(t, "pgm_prepage_for_next_period().\n"); | 199 | TRACE_TASK(t, "pgm_prepage_for_next_period().\n"); |
187 | 200 | ||
188 | prepare_for_next_period(t); | 201 | if(is_pgm_src(t)) { |
202 | prepare_for_next_period(t); | ||
203 | } | ||
204 | else { | ||
205 | // We defer setting up release and deadline times | ||
206 | // up to wake-time. This makes handling the deadline | ||
207 | // of the first job properly. | ||
208 | |||
209 | tsk_rt(t)->job_params.exec_time = 0; | ||
210 | ++(tsk_rt(t)->job_params.job_no); | ||
211 | t->rt.time_slice = 1; // don't confuse Linux (??) | ||
212 | } | ||
213 | |||
214 | // DANGER! We're setting an UNINTERRUPTIBLE state | ||
215 | // without going on a wait queue! Better hope the | ||
216 | // PGM sources do their work... | ||
217 | set_task_state(t, TASK_UNINTERRUPTIBLE); | ||
189 | } | 218 | } |
190 | 219 | ||
191 | 220 | ||
@@ -230,7 +259,7 @@ int pgm_complete_job(struct task_struct *t) | |||
230 | } | 259 | } |
231 | 260 | ||
232 | /* produce new tokens, possibly waking up children, | 261 | /* produce new tokens, possibly waking up children, |
233 | * or setup for the next PGM root. | 262 | * or setup for the next PGM src. |
234 | */ | 263 | */ |
235 | pgm_produce(t); | 264 | pgm_produce(t); |
236 | 265 | ||
@@ -245,13 +274,6 @@ int do_pgm_add_edge(struct task_struct *a, int nr_gen, | |||
245 | struct pgm_produce *prod; | 274 | struct pgm_produce *prod; |
246 | struct pgm_consume *cons; | 275 | struct pgm_consume *cons; |
247 | 276 | ||
248 | // validation of parameters takes place upstream. | ||
249 | |||
250 | if(!is_pgm(a)) { | ||
251 | // 'a' is the root. set itself as such. | ||
252 | tsk_rt(a)->pgm_params.root = a; | ||
253 | } | ||
254 | |||
255 | if(tsk_rt(a)->pgm_params.produce == NULL) { | 277 | if(tsk_rt(a)->pgm_params.produce == NULL) { |
256 | tsk_rt(a)->pgm_params.produce = | 278 | tsk_rt(a)->pgm_params.produce = |
257 | kmalloc(sizeof(pgm_produce), GFP_KERNEL); | 279 | kmalloc(sizeof(pgm_produce), GFP_KERNEL); |
@@ -288,9 +310,6 @@ int do_pgm_add_edge(struct task_struct *a, int nr_gen, | |||
288 | __set_bit(cons->nr_consumptions, cons->unsatisfied); | 310 | __set_bit(cons->nr_consumptions, cons->unsatisfied); |
289 | ++(cons->nr_consumptions); | 311 | ++(cons->nr_consumptions); |
290 | 312 | ||
291 | // copy over root node from a to b | ||
292 | tsk_rt(b)->pgm_params.root = tsk_rt(a)->pgm_params.root; | ||
293 | |||
294 | // mark as pgm nodes | 313 | // mark as pgm nodes |
295 | tsk_rt(a)->is_pgm_node = 1; | 314 | tsk_rt(a)->is_pgm_node = 1; |
296 | tsk_rt(b)->is_pgm_node = 1; | 315 | tsk_rt(b)->is_pgm_node = 1; |
@@ -299,13 +318,25 @@ out: | |||
299 | return retval; | 318 | return retval; |
300 | } | 319 | } |
301 | 320 | ||
302 | int do_pgm_signal_ready(struct task_struct *root) | 321 | int do_pgm_signal_ready(struct task_struct *src) |
303 | { | 322 | { |
304 | int retval = -EINVAL; | 323 | int retval = -EINVAL; |
324 | int num_remaining; | ||
325 | struct task_struct *t = current; | ||
305 | 326 | ||
306 | tsk_rt(current)->pgm_params.root = root; | 327 | tsk_rt(t)->pgm_params.src = src; |
328 | |||
329 | num_remaining = | ||
330 | atomic_dec_return(&tsk_rt(src)->pgm_params.nr_children_pending); | ||
331 | |||
332 | if(num_remaining == 0) { | ||
333 | complete(&tsk_rt(src)->pgm_params.children_ready); | ||
334 | } | ||
307 | 335 | ||
308 | /* decrement the parent's semaphore and then suspend */ | 336 | // pray that our parent wakes us up. |
337 | set_task_state(t, TASK_UNINTERRUPTIBLE); | ||
338 | schedule(); | ||
339 | retval = 0; | ||
309 | 340 | ||
310 | return retval; | 341 | return retval; |
311 | } | 342 | } |
@@ -313,19 +344,29 @@ int do_pgm_signal_ready(struct task_struct *root) | |||
313 | int do_pgm_set_nr_children(int nr_children) | 344 | int do_pgm_set_nr_children(int nr_children) |
314 | { | 345 | { |
315 | int retval = -EINVAL; | 346 | int retval = -EINVAL; |
347 | struct task_struct *src = current; | ||
316 | 348 | ||
317 | /* TODO: set up a counting semaphore */ | 349 | if(!is_pgm_src(src)) |
350 | goto out; | ||
351 | |||
352 | init_completion(&tsk_rt(src)->pgm_params.children_ready); | ||
353 | atomic_set(&tsk_rt(src)->pgm_params.nr_children_pending, nr_children); | ||
318 | 354 | ||
355 | out: | ||
319 | return retval; | 356 | return retval; |
320 | } | 357 | } |
321 | 358 | ||
322 | int do_pgm_wait_for_children(void) | 359 | int do_pgm_wait_for_children(void) |
323 | { | 360 | { |
324 | int retval = -EINVAL; | 361 | int retval = -EINVAL; |
325 | struct task_struct *root = current; | 362 | struct task_struct *src = current; |
326 | 363 | ||
327 | /* TODO: sleep on a counting semaphore */ | 364 | if(!is_pgm_src(src)) |
365 | goto out; | ||
366 | |||
367 | wait_for_completion(&tsk_rt(src)->pgm_params.children_ready); | ||
328 | 368 | ||
369 | out: | ||
329 | return retval; | 370 | return retval; |
330 | } | 371 | } |
331 | 372 | ||
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index c1145fc1dc8c..ca877938f729 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -640,6 +640,8 @@ static void gsnedf_task_wake_up(struct task_struct *task) | |||
640 | TRACE_TASK(task, "wake_up at %llu\n", litmus_clock()); | 640 | TRACE_TASK(task, "wake_up at %llu\n", litmus_clock()); |
641 | 641 | ||
642 | raw_spin_lock_irqsave(&gsnedf_lock, flags); | 642 | raw_spin_lock_irqsave(&gsnedf_lock, flags); |
643 | |||
644 | #if 0 | ||
643 | /* We need to take suspensions because of semaphores into | 645 | /* We need to take suspensions because of semaphores into |
644 | * account! If a job resumes after being suspended due to acquiring | 646 | * account! If a job resumes after being suspended due to acquiring |
645 | * a semaphore, it should never be treated as a new job release. | 647 | * a semaphore, it should never be treated as a new job release. |
@@ -661,6 +663,10 @@ static void gsnedf_task_wake_up(struct task_struct *task) | |||
661 | } | 663 | } |
662 | } | 664 | } |
663 | } | 665 | } |
666 | #else // periodic task model | ||
667 | set_rt_flags(task, RT_F_RUNNING); | ||
668 | #endif | ||
669 | |||
664 | gsnedf_job_arrival(task); | 670 | gsnedf_job_arrival(task); |
665 | raw_spin_unlock_irqrestore(&gsnedf_lock, flags); | 671 | raw_spin_unlock_irqrestore(&gsnedf_lock, flags); |
666 | } | 672 | } |