aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched/litmus.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched/litmus.c')
-rw-r--r--kernel/sched/litmus.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/kernel/sched/litmus.c b/kernel/sched/litmus.c
new file mode 100644
index 000000000000..924358babde2
--- /dev/null
+++ b/kernel/sched/litmus.c
@@ -0,0 +1,350 @@
1/* This file is included from kernel/sched.c */
2
3#include "sched.h"
4
5#include <litmus/trace.h>
6#include <litmus/sched_trace.h>
7
8#include <litmus/litmus.h>
9#include <litmus/budget.h>
10#include <litmus/sched_plugin.h>
11#include <litmus/preempt.h>
12
13static void update_time_litmus(struct rq *rq, struct task_struct *p)
14{
15 u64 delta = rq->clock - p->se.exec_start;
16 if (unlikely((s64)delta < 0))
17 delta = 0;
18 /* per job counter */
19 p->rt_param.job_params.exec_time += delta;
20 /* task counter */
21 p->se.sum_exec_runtime += delta;
22 if (delta) {
23 TRACE_TASK(p, "charged %llu exec time (total:%llu, rem:%llu)\n",
24 delta, p->rt_param.job_params.exec_time, budget_remaining(p));
25 }
26 /* sched_clock() */
27 p->se.exec_start = rq->clock;
28 cpuacct_charge(p, delta);
29}
30
31static void double_rq_lock(struct rq *rq1, struct rq *rq2);
32static void double_rq_unlock(struct rq *rq1, struct rq *rq2);
33
34static struct task_struct *
35litmus_schedule(struct rq *rq, struct task_struct *prev)
36{
37 struct task_struct *next;
38
39#ifdef CONFIG_SMP
40 struct rq* other_rq;
41 long was_running;
42 lt_t _maybe_deadlock = 0;
43#endif
44
45 /* let the plugin schedule */
46 next = litmus->schedule(prev);
47
48 sched_state_plugin_check();
49
50#ifdef CONFIG_SMP
51 /* check if a global plugin pulled a task from a different RQ */
52 if (next && task_rq(next) != rq) {
53 /* we need to migrate the task */
54 other_rq = task_rq(next);
55 TRACE_TASK(next, "migrate from %d\n", other_rq->cpu);
56
57 /* while we drop the lock, the prev task could change its
58 * state
59 */
60 BUG_ON(prev != current);
61 was_running = is_current_running();
62 mb();
63 raw_spin_unlock(&rq->lock);
64
65 /* Don't race with a concurrent switch. This could deadlock in
66 * the case of cross or circular migrations. It's the job of
67 * the plugin to make sure that doesn't happen.
68 */
69 TRACE_TASK(next, "stack_in_use=%d\n",
70 next->rt_param.stack_in_use);
71 if (next->rt_param.stack_in_use != NO_CPU) {
72 TRACE_TASK(next, "waiting to deschedule\n");
73 _maybe_deadlock = litmus_clock();
74 }
75 while (next->rt_param.stack_in_use != NO_CPU) {
76 cpu_relax();
77 mb();
78 if (next->rt_param.stack_in_use == NO_CPU)
79 TRACE_TASK(next,"descheduled. Proceeding.\n");
80
81 if (lt_before(_maybe_deadlock + 1000000000L,
82 litmus_clock())) {
83 /* We've been spinning for 1s.
84 * Something can't be right!
85 * Let's abandon the task and bail out; at least
86 * we will have debug info instead of a hard
87 * deadlock.
88 */
89#ifdef CONFIG_BUG_ON_MIGRATION_DEADLOCK
90 BUG();
91#else
92 TRACE_TASK(next,"stack too long in use. "
93 "Deadlock?\n");
94 next = NULL;
95
96 /* bail out */
97 raw_spin_lock(&rq->lock);
98 return next;
99#endif
100 }
101 }
102#ifdef __ARCH_WANT_UNLOCKED_CTXSW
103 if (next->on_cpu)
104 TRACE_TASK(next, "waiting for !oncpu");
105 while (next->on_cpu) {
106 cpu_relax();
107 mb();
108 }
109#endif
110 double_rq_lock(rq, other_rq);
111 mb();
112 if (is_realtime(current) && is_current_running() != was_running) {
113 TRACE_TASK(prev,
114 "state changed while we dropped"
115 " the lock: is_running=%d, was_running=%d\n",
116 is_current_running(), was_running);
117 if (is_current_running() && !was_running) {
118 /* prev task became unblocked
119 * we need to simulate normal sequence of events
120 * to scheduler plugins.
121 */
122 litmus->task_block(prev);
123 litmus->task_wake_up(prev);
124 }
125 }
126
127 set_task_cpu(next, smp_processor_id());
128
129 /* DEBUG: now that we have the lock we need to make sure a
130 * couple of things still hold:
131 * - it is still a real-time task
132 * - it is still runnable (could have been stopped)
133 * If either is violated, then the active plugin is
134 * doing something wrong.
135 */
136 if (!is_realtime(next) || !tsk_rt(next)->present) {
137 /* BAD BAD BAD */
138 TRACE_TASK(next,"BAD: migration invariant FAILED: "
139 "rt=%d present=%d\n",
140 is_realtime(next),
141 tsk_rt(next)->present);
142 /* drop the task */
143 next = NULL;
144 }
145 /* release the other CPU's runqueue, but keep ours */
146 raw_spin_unlock(&other_rq->lock);
147 }
148#endif
149
150 if (next) {
151#ifdef CONFIG_SMP
152 next->rt_param.stack_in_use = rq->cpu;
153#else
154 next->rt_param.stack_in_use = 0;
155#endif
156 update_rq_clock(rq);
157 next->se.exec_start = rq->clock;
158 }
159
160 update_enforcement_timer(next);
161 return next;
162}
163
164static void enqueue_task_litmus(struct rq *rq, struct task_struct *p,
165 int flags)
166{
167 if (flags & ENQUEUE_WAKEUP) {
168 sched_trace_task_resume(p);
169 tsk_rt(p)->present = 1;
170 /* LITMUS^RT plugins need to update the state
171 * _before_ making it available in global structures.
172 * Linux gets away with being lazy about the task state
173 * update. We can't do that, hence we update the task
174 * state already here.
175 *
176 * WARNING: this needs to be re-evaluated when porting
177 * to newer kernel versions.
178 */
179 p->state = TASK_RUNNING;
180 litmus->task_wake_up(p);
181
182 rq->litmus.nr_running++;
183 } else {
184 TRACE_TASK(p, "ignoring an enqueue, not a wake up.\n");
185 p->se.exec_start = rq->clock;
186 }
187}
188
189static void dequeue_task_litmus(struct rq *rq, struct task_struct *p,
190 int flags)
191{
192 if (flags & DEQUEUE_SLEEP) {
193 litmus->task_block(p);
194 tsk_rt(p)->present = 0;
195 sched_trace_task_block(p);
196
197 rq->litmus.nr_running--;
198 } else
199 TRACE_TASK(p, "ignoring a dequeue, not going to sleep.\n");
200}
201
202static void yield_task_litmus(struct rq *rq)
203{
204 TS_SYSCALL_IN_START;
205 TS_SYSCALL_IN_END;
206
207 BUG_ON(rq->curr != current);
208 /* sched_yield() is called to trigger delayed preemptions.
209 * Thus, mark the current task as needing to be rescheduled.
210 * This will cause the scheduler plugin to be invoked, which can
211 * then determine if a preemption is still required.
212 */
213 clear_exit_np(current);
214 litmus_reschedule_local();
215
216 TS_SYSCALL_OUT_START;
217}
218
219/* Plugins are responsible for this.
220 */
221static void check_preempt_curr_litmus(struct rq *rq, struct task_struct *p, int flags)
222{
223}
224
225static void put_prev_task_litmus(struct rq *rq, struct task_struct *p)
226{
227}
228
229/* pick_next_task_litmus() - litmus_schedule() function
230 *
231 * return the next task to be scheduled
232 */
233static struct task_struct *pick_next_task_litmus(struct rq *rq, struct task_struct *prev)
234{
235 struct task_struct *next;
236
237 if (is_realtime(prev))
238 update_time_litmus(rq, prev);
239
240 TS_PLUGIN_SCHED_START;
241 next = litmus_schedule(rq, prev);
242 TS_PLUGIN_SCHED_END;
243
244 /* This is a bit backwards: the other classes call put_prev_task()
245 * _after_ they've determined that the class has some queued tasks.
246 * We can't determine this easily because each plugin manages its own
247 * ready queues, and because in the case of globally shared queues,
248 * we really don't know whether we'll have something ready even if
249 * we test here. So we do it in reverse: first ask the plugin to
250 * provide a task, and if we find one, call put_prev_task() on the
251 * previously scheduled task.
252 */
253 if (next)
254 put_prev_task(rq, prev);
255
256 return next;
257}
258
259static void task_tick_litmus(struct rq *rq, struct task_struct *p, int queued)
260{
261 if (is_realtime(p) && !queued) {
262 update_time_litmus(rq, p);
263 /* budget check for QUANTUM_ENFORCEMENT tasks */
264 if (budget_enforced(p) && budget_exhausted(p)) {
265 litmus_reschedule_local();
266 }
267 }
268}
269
270static void switched_to_litmus(struct rq *rq, struct task_struct *p)
271{
272}
273
274static void prio_changed_litmus(struct rq *rq, struct task_struct *p,
275 int oldprio)
276{
277}
278
279unsigned int get_rr_interval_litmus(struct rq *rq, struct task_struct *p)
280{
281 /* return infinity */
282 return 0;
283}
284
285/* This is called when a task became a real-time task, either due to a SCHED_*
286 * class transition or due to PI mutex inheritance. We don't handle Linux PI
287 * mutex inheritance yet (and probably never will). Use LITMUS provided
288 * synchronization primitives instead.
289 */
290static void set_curr_task_litmus(struct rq *rq)
291{
292 rq->curr->se.exec_start = rq->clock;
293}
294
295
296#ifdef CONFIG_SMP
297/* execve tries to rebalance task in this scheduling domain.
298 * We don't care about the scheduling domain; can gets called from
299 * exec, fork, wakeup.
300 */
301static int
302select_task_rq_litmus(struct task_struct *p, int cpu, int sd_flag, int flags)
303{
304 /* preemption is already disabled.
305 * We don't want to change cpu here
306 */
307 return task_cpu(p);
308}
309#endif
310
311static void update_curr_litmus(struct rq *rq)
312{
313 struct task_struct *p = rq->curr;
314
315 if (!is_realtime(p))
316 return;
317
318 update_time_litmus(rq, p);
319}
320
321const struct sched_class litmus_sched_class = {
322 /* From 34f971f6 the stop/migrate worker threads have a class on
323 * their own, which is the highest prio class. We don't support
324 * cpu-hotplug or cpu throttling. Allows Litmus to use up to 1.0
325 * CPU capacity.
326 */
327 .next = &dl_sched_class,
328 .enqueue_task = enqueue_task_litmus,
329 .dequeue_task = dequeue_task_litmus,
330 .yield_task = yield_task_litmus,
331
332 .check_preempt_curr = check_preempt_curr_litmus,
333
334 .pick_next_task = pick_next_task_litmus,
335 .put_prev_task = put_prev_task_litmus,
336
337#ifdef CONFIG_SMP
338 .select_task_rq = select_task_rq_litmus,
339#endif
340
341 .set_curr_task = set_curr_task_litmus,
342 .task_tick = task_tick_litmus,
343
344 .get_rr_interval = get_rr_interval_litmus,
345
346 .prio_changed = prio_changed_litmus,
347 .switched_to = switched_to_litmus,
348
349 .update_curr = update_curr_litmus,
350};