diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2010-10-18 16:01:10 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2010-10-19 09:40:41 -0400 |
commit | 576b1ad144f81d3fd3bd37d18dab86cd1e8660b0 (patch) | |
tree | 07cb473c807f4a4297d117883c9a6c3fa14110ba | |
parent | 9b718afbc5db5a808804a336c17ba896a9f048a1 (diff) |
Litmus core: add plugin-independent precise budget enforcement infrastructure
Simple logic: if a task requires precise enforcement, then program a
hr-timer to fire when the task must be descheduled. When the timer
fires, simply activate the scheduler. When we switch to a different
task, either reprogram the timer or cancel it.
-rw-r--r-- | include/litmus/budget.h | 8 | ||||
-rw-r--r-- | litmus/Makefile | 1 | ||||
-rw-r--r-- | litmus/budget.c | 109 |
3 files changed, 118 insertions, 0 deletions
diff --git a/include/litmus/budget.h b/include/litmus/budget.h new file mode 100644 index 000000000000..732530e63491 --- /dev/null +++ b/include/litmus/budget.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _LITMUS_BUDGET_H_ | ||
2 | #define _LITMUS_BUDGET_H_ | ||
3 | |||
4 | /* Update the per-processor enforcement timer (arm/reproram/cancel) for | ||
5 | * the next task. */ | ||
6 | void update_enforcement_timer(struct task_struct* t); | ||
7 | |||
8 | #endif | ||
diff --git a/litmus/Makefile b/litmus/Makefile index 30369787ece2..f301d2842e43 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y = sched_plugin.o litmus.o \ | 5 | obj-y = sched_plugin.o litmus.o \ |
6 | budget.o \ | ||
6 | jobs.o \ | 7 | jobs.o \ |
7 | sync.o \ | 8 | sync.o \ |
8 | rt_domain.o \ | 9 | rt_domain.o \ |
diff --git a/litmus/budget.c b/litmus/budget.c new file mode 100644 index 000000000000..b99177a26313 --- /dev/null +++ b/litmus/budget.c | |||
@@ -0,0 +1,109 @@ | |||
1 | #include <linux/percpu.h> | ||
2 | #include <linux/hrtimer.h> | ||
3 | |||
4 | #include <litmus/litmus.h> | ||
5 | |||
6 | struct enforcement_timer { | ||
7 | /* The enforcement timer is used to accurately police | ||
8 | * slice budgets. */ | ||
9 | struct hrtimer timer; | ||
10 | int armed; | ||
11 | }; | ||
12 | |||
13 | DEFINE_PER_CPU(struct enforcement_timer, budget_timer); | ||
14 | |||
15 | static enum hrtimer_restart on_enforcement_timeout(struct hrtimer *timer) | ||
16 | { | ||
17 | struct enforcement_timer* et = container_of(timer, | ||
18 | struct enforcement_timer, | ||
19 | timer); | ||
20 | unsigned long flags; | ||
21 | |||
22 | local_irq_save(flags); | ||
23 | TRACE("enforcement timer fired.\n"); | ||
24 | et->armed = 0; | ||
25 | /* activate scheduler */ | ||
26 | set_tsk_need_resched(current); | ||
27 | local_irq_restore(flags); | ||
28 | |||
29 | return HRTIMER_NORESTART; | ||
30 | } | ||
31 | |||
32 | /* assumes called with IRQs off */ | ||
33 | static void cancel_enforcement_timer(struct enforcement_timer* et) | ||
34 | { | ||
35 | int ret; | ||
36 | |||
37 | TRACE("cancelling enforcement timer.\n"); | ||
38 | |||
39 | /* Since interrupts are disabled and et->armed is only | ||
40 | * modified locally, we do not need any locks. | ||
41 | */ | ||
42 | |||
43 | if (et->armed) { | ||
44 | ret = hrtimer_try_to_cancel(&et->timer); | ||
45 | /* Should never be inactive. */ | ||
46 | BUG_ON(ret == 0); | ||
47 | /* Should never be running concurrently. */ | ||
48 | BUG_ON(ret == -1); | ||
49 | |||
50 | et->armed = 0; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | /* assumes called with IRQs off */ | ||
55 | static void arm_enforcement_timer(struct enforcement_timer* et, | ||
56 | struct task_struct* t) | ||
57 | { | ||
58 | lt_t when_to_fire; | ||
59 | TRACE_TASK(t, "arming enforcement timer.\n"); | ||
60 | |||
61 | /* Calling this when there is no budget left for the task | ||
62 | * makes no sense, unless the task is non-preemptive. */ | ||
63 | BUG_ON(budget_exhausted(t) && (!is_np(t))); | ||
64 | |||
65 | /* __hrtimer_start_range_ns() cancels the timer | ||
66 | * anyway, so we don't have to check whether it is still armed */ | ||
67 | |||
68 | if (likely(!is_np(t))) { | ||
69 | when_to_fire = litmus_clock() + budget_remaining(t); | ||
70 | __hrtimer_start_range_ns(&et->timer, | ||
71 | ns_to_ktime(when_to_fire), | ||
72 | 0 /* delta */, | ||
73 | HRTIMER_MODE_ABS_PINNED, | ||
74 | 0 /* no wakeup */); | ||
75 | et->armed = 1; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | |||
80 | /* expects to be called with IRQs off */ | ||
81 | void update_enforcement_timer(struct task_struct* t) | ||
82 | { | ||
83 | struct enforcement_timer* et = &__get_cpu_var(budget_timer); | ||
84 | |||
85 | if (t && budget_precisely_enforced(t)) { | ||
86 | /* Make sure we call into the scheduler when this budget | ||
87 | * expires. */ | ||
88 | arm_enforcement_timer(et, t); | ||
89 | } else if (et->armed) { | ||
90 | /* Make sure we don't cause unnecessary interrupts. */ | ||
91 | cancel_enforcement_timer(et); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | |||
96 | static int __init init_budget_enforcement(void) | ||
97 | { | ||
98 | int cpu; | ||
99 | struct enforcement_timer* et; | ||
100 | |||
101 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
102 | et = &per_cpu(budget_timer, cpu); | ||
103 | hrtimer_init(&et->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
104 | et->timer.function = on_enforcement_timeout; | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | module_init(init_budget_enforcement); | ||