diff options
| -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 | } |
