aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/sched_mc.c
diff options
context:
space:
mode:
authorJeremy Erickson <jerickso@cs.unc.edu>2011-01-22 11:14:07 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2011-08-25 14:41:21 -0400
commitd7f8fc563ffd17b5584acc5afedd16b385ad517b (patch)
tree5236d65f51dd53536ce5cd32dc8291ee5cf5aa4d /litmus/sched_mc.c
parent77282ed493834665c45c8ff86c9980e90840b01e (diff)
Use watchdog timers (compiles, but not tested yet.)
Diffstat (limited to 'litmus/sched_mc.c')
-rw-r--r--litmus/sched_mc.c97
1 files changed, 91 insertions, 6 deletions
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c
index 0f5da078c597..63dd157925ab 100644
--- a/litmus/sched_mc.c
+++ b/litmus/sched_mc.c
@@ -13,6 +13,7 @@
13#include <linux/spinlock.h> 13#include <linux/spinlock.h>
14#include <linux/percpu.h> 14#include <linux/percpu.h>
15#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/hrtimer.h>
16 17
17#include <litmus/litmus.h> 18#include <litmus/litmus.h>
18#include <litmus/jobs.h> 19#include <litmus/jobs.h>
@@ -99,6 +100,16 @@ typedef struct {
99 struct task_struct* ghost_tasks[CRIT_LEVEL_D+1]; 100 struct task_struct* ghost_tasks[CRIT_LEVEL_D+1];
100} cpu_entry_t; 101} cpu_entry_t;
101 102
103/*This code is heavily based on Bjoern's budget enforcement code. */
104struct watchdog_timer {
105 /* The watchdog timers determine when ghost jobs finish. */
106 struct hrtimer timer;
107 struct task_struct* task;
108};
109
110DEFINE_PER_CPU(struct watchdog_timer[CRIT_LEVEL_D+1], ghost_timers);
111#define ghost_timer(cpu, crit) (&(per_cpu(ghost_timers, cpu)[crit]))
112
102DEFINE_PER_CPU(cpu_entry_t, mc_cpu_entries); 113DEFINE_PER_CPU(cpu_entry_t, mc_cpu_entries);
103 114
104cpu_entry_t* mc_cpus[NR_CPUS]; 115cpu_entry_t* mc_cpus[NR_CPUS];
@@ -328,7 +339,7 @@ static void update_ghost_time(struct task_struct *p)
328 u64 clock; 339 u64 clock;
329 340
330 BUG_ON(!is_ghost(p)); 341 BUG_ON(!is_ghost(p));
331 clock = cpu_clock(p->rt_param.linked_on); 342 clock = litmus_clock();
332 delta = clock - p->se.exec_start; 343 delta = clock - p->se.exec_start;
333 if (unlikely ((s64)delta < 0)) { 344 if (unlikely ((s64)delta < 0)) {
334 delta = 0; 345 delta = 0;
@@ -344,6 +355,25 @@ static void update_ghost_time(struct task_struct *p)
344} 355}
345 356
346 357
358/*
359 *
360 */
361static void cancel_watchdog_timer(struct watchdog_timer* wt)
362{
363 int ret;
364
365 if (wt->task) {
366 TRACE_TASK(wt->task, "Cancelling watchdog timer.\n");
367 ret = hrtimer_try_to_cancel(&wt->timer);
368 /*Should never be inactive.*/
369 BUG_ON(ret == 0);
370 /*Should never be running concurrently. */
371 BUG_ON(ret == -1);
372
373 wt->task = NULL;
374 }
375}
376
347/* link_task_to_cpu - Update the link of a CPU. 377/* link_task_to_cpu - Update the link of a CPU.
348 * Handles the case where the to-be-linked task is already 378 * Handles the case where the to-be-linked task is already
349 * scheduled on a different CPU. 379 * scheduled on a different CPU.
@@ -358,6 +388,8 @@ static noinline void link_task_to_cpu(struct task_struct* linked,
358 struct task_struct* tmp; 388 struct task_struct* tmp;
359 int on_cpu; 389 int on_cpu;
360 int i; 390 int i;
391 struct watchdog_timer* timer;
392 lt_t when_to_fire;
361 393
362 BUG_ON(linked && !is_realtime(linked)); 394 BUG_ON(linked && !is_realtime(linked));
363 BUG_ON(linked && is_realtime(linked) && 395 BUG_ON(linked && is_realtime(linked) &&
@@ -378,8 +410,22 @@ static noinline void link_task_to_cpu(struct task_struct* linked,
378 */ 410 */
379 BUG_ON(linked->rt_param.linked_on != NO_CPU); 411 BUG_ON(linked->rt_param.linked_on != NO_CPU);
380 linked->rt_param.linked_on = entry->cpu; 412 linked->rt_param.linked_on = entry->cpu;
381 linked->se.exec_start = cpu_clock(entry->cpu); 413 linked->se.exec_start = litmus_clock();
382 entry->ghost_tasks[linked->rt_param.task_params.crit] = linked; 414 entry->ghost_tasks[linked->rt_param.task_params.crit] = linked;
415 /* Set up the watchdog timer. */
416 timer = ghost_timer(entry->cpu,
417 linked->rt_param.task_params.crit);
418 if (timer->task){
419 cancel_watchdog_timer(timer);
420 }
421 when_to_fire = litmus_clock() +
422 linked->rt_param.job_params.ghost_budget;
423 timer->task = linked;
424 __hrtimer_start_range_ns(&timer->timer,
425 ns_to_ktime(when_to_fire),
426 0 /* delta */,
427 HRTIMER_MODE_ABS_PINNED,
428 0 /* no wakeup */);
383 } 429 }
384 else{ 430 else{
385 /* Currently linked task is set to be unlinked. */ 431 /* Currently linked task is set to be unlinked. */
@@ -465,6 +511,7 @@ static noinline void unlink(struct task_struct* t)
465{ 511{
466 int cpu; 512 int cpu;
467 cpu_entry_t *entry; 513 cpu_entry_t *entry;
514 struct watchdog_timer *timer;
468 515
469 if (unlikely(!t)) { 516 if (unlikely(!t)) {
470 TRACE_BUG_ON(!t); 517 TRACE_BUG_ON(!t);
@@ -477,6 +524,12 @@ static noinline void unlink(struct task_struct* t)
477 entry = remote_cpu_entry(cpu); 524 entry = remote_cpu_entry(cpu);
478 t->rt_param.linked_on = NO_CPU; 525 t->rt_param.linked_on = NO_CPU;
479 if (is_ghost(t)) { 526 if (is_ghost(t)) {
527 /* Clear the timer.*/
528 timer = ghost_timer(cpu,
529 t->rt_param.task_params.crit);
530 /* Should already be watching task.*/
531 BUG_ON(timer->task != t);
532 cancel_watchdog_timer(timer);
480 if (t->rt_param.job_params.ghost_budget > 0){ 533 if (t->rt_param.job_params.ghost_budget > 0){
481 /* Job isn't finished, so do accounting. */ 534 /* Job isn't finished, so do accounting. */
482 update_ghost_time(t); 535 update_ghost_time(t);
@@ -686,7 +739,9 @@ static noinline void job_completion(struct task_struct *t, int forced)
686 739
687 /* set flags */ 740 /* set flags */
688 set_rt_flags(t, RT_F_SLEEP); 741 set_rt_flags(t, RT_F_SLEEP);
689 /*If it's not a ghost job, do ghost job conversion and return.*/ 742 /* If it's not a ghost job, do ghost job conversion and return if
743 * needed.
744 */
690 if (!is_ghost(t)) { 745 if (!is_ghost(t)) {
691 cpu = remote_cpu_entry(t->rt_param.scheduled_on); 746 cpu = remote_cpu_entry(t->rt_param.scheduled_on);
692 /*Unlink first while it's not a ghost job.*/ 747 /*Unlink first while it's not a ghost job.*/
@@ -697,6 +752,12 @@ static noinline void job_completion(struct task_struct *t, int forced)
697 /* If we did just convert the job to ghost, we can safely 752 /* If we did just convert the job to ghost, we can safely
698 * reschedule it and then let schedule() determine a new 753 * reschedule it and then let schedule() determine a new
699 * job to run in the slack. 754 * job to run in the slack.
755 *
756 * If it actually needs to run as a ghost job, we'll do so
757 * here.
758 *
759 * If it doesn't need to, it will fall through and be handled
760 * properly as well.
700 */ 761 */
701 if (t->rt_param.job_params.ghost_budget > 0){ 762 if (t->rt_param.job_params.ghost_budget > 0){
702 link_task_to_cpu(t, cpu); 763 link_task_to_cpu(t, cpu);
@@ -705,9 +766,6 @@ static noinline void job_completion(struct task_struct *t, int forced)
705 } 766 }
706 } 767 }
707 /* prepare for next period */ 768 /* prepare for next period */
708 /* TODO: check what happens if we actually finish with exactly our
709 * budget and never convert to ghost
710 */
711 if (is_ghost(t)) { 769 if (is_ghost(t)) {
712 t->rt_param.job_params.ghost_budget = 0; 770 t->rt_param.job_params.ghost_budget = 0;
713 prepare_for_next_period(t); 771 prepare_for_next_period(t);
@@ -726,6 +784,26 @@ static noinline void job_completion(struct task_struct *t, int forced)
726 mc_job_arrival(t); 784 mc_job_arrival(t);
727} 785}
728 786
787/* watchdog_timeout - this function is called when a watchdog timer expires.
788 *
789 * Acquires global lock
790 */
791
792static enum hrtimer_restart watchdog_timeout(struct hrtimer *timer)
793{
794 struct watchdog_timer* wt = container_of(timer,
795 struct watchdog_timer,
796 timer);
797 unsigned long flags;
798 raw_spin_lock_irqsave(&global_lock, flags);
799 /*If we have triggered, we know the budget must have expired.*/
800 wt->task->rt_param.job_params.ghost_budget = 0;
801 job_completion(wt->task, 0);
802 raw_spin_unlock_irqrestore(&global_lock, flags);
803 return HRTIMER_NORESTART;
804}
805
806
729/* mc_tick - this function is called for every local timer 807/* mc_tick - this function is called for every local timer
730 * interrupt. 808 * interrupt.
731 * 809 *
@@ -1144,6 +1222,7 @@ static int __init init_mc(void)
1144 int cpu; 1222 int cpu;
1145 int i; 1223 int i;
1146 cpu_entry_t *entry; 1224 cpu_entry_t *entry;
1225 struct watchdog_timer *timer;
1147 1226
1148 bheap_init(&mc_cpu_heap_c); 1227 bheap_init(&mc_cpu_heap_c);
1149 bheap_init(&mc_cpu_heap_d); 1228 bheap_init(&mc_cpu_heap_d);
@@ -1157,6 +1236,12 @@ static int __init init_mc(void)
1157 entry->hn_d = &mc_heap_node_d[cpu]; 1236 entry->hn_d = &mc_heap_node_d[cpu];
1158 bheap_node_init(&entry->hn_c, entry); 1237 bheap_node_init(&entry->hn_c, entry);
1159 bheap_node_init(&entry->hn_d, entry); 1238 bheap_node_init(&entry->hn_d, entry);
1239 for (i = CRIT_LEVEL_A; i <= CRIT_LEVEL_D; i++){
1240 timer = ghost_timer(cpu, i);
1241 hrtimer_init(&timer->timer, CLOCK_MONOTONIC,
1242 HRTIMER_MODE_ABS);
1243 timer->timer.function = watchdog_timeout;
1244 }
1160 } 1245 }
1161 mc_edf_domain_init(&crit_c, NULL, mc_release_jobs); 1246 mc_edf_domain_init(&crit_c, NULL, mc_release_jobs);
1162 mc_edf_domain_init(&crit_d, NULL, mc_release_jobs); 1247 mc_edf_domain_init(&crit_d, NULL, mc_release_jobs);