aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/budget.c
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2010-10-18 16:01:10 -0400
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2010-10-19 09:40:41 -0400
commit576b1ad144f81d3fd3bd37d18dab86cd1e8660b0 (patch)
tree07cb473c807f4a4297d117883c9a6c3fa14110ba /litmus/budget.c
parent9b718afbc5db5a808804a336c17ba896a9f048a1 (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.
Diffstat (limited to 'litmus/budget.c')
-rw-r--r--litmus/budget.c109
1 files changed, 109 insertions, 0 deletions
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
6struct enforcement_timer {
7 /* The enforcement timer is used to accurately police
8 * slice budgets. */
9 struct hrtimer timer;
10 int armed;
11};
12
13DEFINE_PER_CPU(struct enforcement_timer, budget_timer);
14
15static 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 */
33static 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 */
55static 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 */
81void 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
96static 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
109module_init(init_budget_enforcement);