aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/budget.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/budget.c')
-rw-r--r--litmus/budget.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/litmus/budget.c b/litmus/budget.c
new file mode 100644
index 000000000000..310e9a3d4172
--- /dev/null
+++ b/litmus/budget.c
@@ -0,0 +1,111 @@
1#include <linux/sched.h>
2#include <linux/percpu.h>
3#include <linux/hrtimer.h>
4
5#include <litmus/litmus.h>
6#include <litmus/preempt.h>
7
8struct enforcement_timer {
9 /* The enforcement timer is used to accurately police
10 * slice budgets. */
11 struct hrtimer timer;
12 int armed;
13};
14
15DEFINE_PER_CPU(struct enforcement_timer, budget_timer);
16
17static enum hrtimer_restart on_enforcement_timeout(struct hrtimer *timer)
18{
19 struct enforcement_timer* et = container_of(timer,
20 struct enforcement_timer,
21 timer);
22 unsigned long flags;
23
24 local_irq_save(flags);
25 TRACE("enforcement timer fired.\n");
26 et->armed = 0;
27 /* activate scheduler */
28 litmus_reschedule_local();
29 local_irq_restore(flags);
30
31 return HRTIMER_NORESTART;
32}
33
34/* assumes called with IRQs off */
35static void cancel_enforcement_timer(struct enforcement_timer* et)
36{
37 int ret;
38
39 TRACE("cancelling enforcement timer.\n");
40
41 /* Since interrupts are disabled and et->armed is only
42 * modified locally, we do not need any locks.
43 */
44
45 if (et->armed) {
46 ret = hrtimer_try_to_cancel(&et->timer);
47 /* Should never be inactive. */
48 BUG_ON(ret == 0);
49 /* Should never be running concurrently. */
50 BUG_ON(ret == -1);
51
52 et->armed = 0;
53 }
54}
55
56/* assumes called with IRQs off */
57static void arm_enforcement_timer(struct enforcement_timer* et,
58 struct task_struct* t)
59{
60 lt_t when_to_fire;
61 TRACE_TASK(t, "arming enforcement timer.\n");
62
63 /* Calling this when there is no budget left for the task
64 * makes no sense, unless the task is non-preemptive. */
65 BUG_ON(budget_exhausted(t) && (!is_np(t)));
66
67 /* __hrtimer_start_range_ns() cancels the timer
68 * anyway, so we don't have to check whether it is still armed */
69
70 if (likely(!is_np(t))) {
71 when_to_fire = litmus_clock() + budget_remaining(t);
72 __hrtimer_start_range_ns(&et->timer,
73 ns_to_ktime(when_to_fire),
74 0 /* delta */,
75 HRTIMER_MODE_ABS_PINNED,
76 0 /* no wakeup */);
77 et->armed = 1;
78 }
79}
80
81
82/* expects to be called with IRQs off */
83void update_enforcement_timer(struct task_struct* t)
84{
85 struct enforcement_timer* et = &__get_cpu_var(budget_timer);
86
87 if (t && budget_precisely_enforced(t)) {
88 /* Make sure we call into the scheduler when this budget
89 * expires. */
90 arm_enforcement_timer(et, t);
91 } else if (et->armed) {
92 /* Make sure we don't cause unnecessary interrupts. */
93 cancel_enforcement_timer(et);
94 }
95}
96
97
98static int __init init_budget_enforcement(void)
99{
100 int cpu;
101 struct enforcement_timer* et;
102
103 for (cpu = 0; cpu < NR_CPUS; cpu++) {
104 et = &per_cpu(budget_timer, cpu);
105 hrtimer_init(&et->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
106 et->timer.function = on_enforcement_timeout;
107 }
108 return 0;
109}
110
111module_init(init_budget_enforcement);