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