aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/litmus.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/litmus.c')
-rw-r--r--litmus/litmus.c576
1 files changed, 576 insertions, 0 deletions
diff --git a/litmus/litmus.c b/litmus/litmus.c
new file mode 100644
index 000000000000..7417a8fbda74
--- /dev/null
+++ b/litmus/litmus.c
@@ -0,0 +1,576 @@
1/*
2 * litmus.c -- Implementation of the LITMUS syscalls,
3 * the LITMUS intialization code,
4 * and the procfs interface..
5 */
6#include <asm/uaccess.h>
7#include <linux/uaccess.h>
8#include <linux/sysrq.h>
9#include <linux/sched.h>
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/reboot.h>
13#include <linux/stop_machine.h>
14
15#include <litmus/litmus.h>
16#include <litmus/bheap.h>
17#include <litmus/trace.h>
18#include <litmus/rt_domain.h>
19#include <litmus/litmus_proc.h>
20#include <litmus/sched_trace.h>
21
22#ifdef CONFIG_SCHED_CPU_AFFINITY
23#include <litmus/affinity.h>
24#endif
25
26/* Number of RT tasks that exist in the system */
27atomic_t rt_task_count = ATOMIC_INIT(0);
28
29#ifdef CONFIG_RELEASE_MASTER
30/* current master CPU for handling timer IRQs */
31atomic_t release_master_cpu = ATOMIC_INIT(NO_CPU);
32#endif
33
34static struct kmem_cache * bheap_node_cache;
35extern struct kmem_cache * release_heap_cache;
36
37struct bheap_node* bheap_node_alloc(int gfp_flags)
38{
39 return kmem_cache_alloc(bheap_node_cache, gfp_flags);
40}
41
42void bheap_node_free(struct bheap_node* hn)
43{
44 kmem_cache_free(bheap_node_cache, hn);
45}
46
47struct release_heap* release_heap_alloc(int gfp_flags);
48void release_heap_free(struct release_heap* rh);
49
50/*
51 * sys_set_task_rt_param
52 * @pid: Pid of the task which scheduling parameters must be changed
53 * @param: New real-time extension parameters such as the execution cost and
54 * period
55 * Syscall for manipulating with task rt extension params
56 * Returns EFAULT if param is NULL.
57 * ESRCH if pid is not corrsponding
58 * to a valid task.
59 * EINVAL if either period or execution cost is <=0
60 * EPERM if pid is a real-time task
61 * 0 if success
62 *
63 * Only non-real-time tasks may be configured with this system call
64 * to avoid races with the scheduler. In practice, this means that a
65 * task's parameters must be set _before_ calling sys_prepare_rt_task()
66 *
67 * find_task_by_vpid() assumes that we are in the same namespace of the
68 * target.
69 */
70asmlinkage long sys_set_rt_task_param(pid_t pid, struct rt_task __user * param)
71{
72 struct rt_task tp;
73 struct task_struct *target;
74 int retval = -EINVAL;
75
76 printk("Setting up rt task parameters for process %d.\n", pid);
77
78 if (pid < 0 || param == 0) {
79 goto out;
80 }
81 if (copy_from_user(&tp, param, sizeof(tp))) {
82 retval = -EFAULT;
83 goto out;
84 }
85
86 /* Task search and manipulation must be protected */
87 read_lock_irq(&tasklist_lock);
88 if (!(target = find_task_by_vpid(pid))) {
89 retval = -ESRCH;
90 goto out_unlock;
91 }
92
93 if (is_realtime(target)) {
94 /* The task is already a real-time task.
95 * We cannot not allow parameter changes at this point.
96 */
97 retval = -EBUSY;
98 goto out_unlock;
99 }
100
101 /* set relative deadline to be implicit if left unspecified */
102 if (tp.relative_deadline == 0)
103 tp.relative_deadline = tp.period;
104
105 if (tp.exec_cost <= 0)
106 goto out_unlock;
107 if (tp.period <= 0)
108 goto out_unlock;
109 if (!cpu_online(tp.cpu))
110 goto out_unlock;
111 if (min(tp.relative_deadline, tp.period) < tp.exec_cost) /*density check*/
112 {
113 printk(KERN_INFO "litmus: real-time task %d rejected "
114 "because task density > 1.0\n", pid);
115 goto out_unlock;
116 }
117 if (tp.cls != RT_CLASS_HARD &&
118 tp.cls != RT_CLASS_SOFT &&
119 tp.cls != RT_CLASS_BEST_EFFORT)
120 {
121 printk(KERN_INFO "litmus: real-time task %d rejected "
122 "because its class is invalid\n", pid);
123 goto out_unlock;
124 }
125 if (tp.budget_policy != NO_ENFORCEMENT &&
126 tp.budget_policy != QUANTUM_ENFORCEMENT &&
127 tp.budget_policy != PRECISE_ENFORCEMENT)
128 {
129 printk(KERN_INFO "litmus: real-time task %d rejected "
130 "because unsupported budget enforcement policy "
131 "specified (%d)\n",
132 pid, tp.budget_policy);
133 goto out_unlock;
134 }
135
136 target->rt_param.task_params = tp;
137
138 retval = 0;
139 out_unlock:
140 read_unlock_irq(&tasklist_lock);
141 out:
142 return retval;
143}
144
145/*
146 * Getter of task's RT params
147 * returns EINVAL if param or pid is NULL
148 * returns ESRCH if pid does not correspond to a valid task
149 * returns EFAULT if copying of parameters has failed.
150 *
151 * find_task_by_vpid() assumes that we are in the same namespace of the
152 * target.
153 */
154asmlinkage long sys_get_rt_task_param(pid_t pid, struct rt_task __user * param)
155{
156 int retval = -EINVAL;
157 struct task_struct *source;
158 struct rt_task lp;
159 if (param == 0 || pid < 0)
160 goto out;
161 read_lock(&tasklist_lock);
162 if (!(source = find_task_by_vpid(pid))) {
163 retval = -ESRCH;
164 goto out_unlock;
165 }
166 lp = source->rt_param.task_params;
167 read_unlock(&tasklist_lock);
168 /* Do copying outside the lock */
169 retval =
170 copy_to_user(param, &lp, sizeof(lp)) ? -EFAULT : 0;
171 return retval;
172 out_unlock:
173 read_unlock(&tasklist_lock);
174 out:
175 return retval;
176
177}
178
179/*
180 * This is the crucial function for periodic task implementation,
181 * It checks if a task is periodic, checks if such kind of sleep
182 * is permitted and calls plugin-specific sleep, which puts the
183 * task into a wait array.
184 * returns 0 on successful wakeup
185 * returns EPERM if current conditions do not permit such sleep
186 * returns EINVAL if current task is not able to go to sleep
187 */
188asmlinkage long sys_complete_job(void)
189{
190 int retval = -EPERM;
191 if (!is_realtime(current)) {
192 retval = -EINVAL;
193 goto out;
194 }
195 /* Task with negative or zero period cannot sleep */
196 if (get_rt_period(current) <= 0) {
197 retval = -EINVAL;
198 goto out;
199 }
200 /* The plugin has to put the task into an
201 * appropriate queue and call schedule
202 */
203 retval = litmus->complete_job();
204 out:
205 return retval;
206}
207
208/* This is an "improved" version of sys_complete_job that
209 * addresses the problem of unintentionally missing a job after
210 * an overrun.
211 *
212 * returns 0 on successful wakeup
213 * returns EPERM if current conditions do not permit such sleep
214 * returns EINVAL if current task is not able to go to sleep
215 */
216asmlinkage long sys_wait_for_job_release(unsigned int job)
217{
218 int retval = -EPERM;
219 if (!is_realtime(current)) {
220 retval = -EINVAL;
221 goto out;
222 }
223
224 /* Task with negative or zero period cannot sleep */
225 if (get_rt_period(current) <= 0) {
226 retval = -EINVAL;
227 goto out;
228 }
229
230 retval = 0;
231
232 /* first wait until we have "reached" the desired job
233 *
234 * This implementation has at least two problems:
235 *
236 * 1) It doesn't gracefully handle the wrap around of
237 * job_no. Since LITMUS is a prototype, this is not much
238 * of a problem right now.
239 *
240 * 2) It is theoretically racy if a job release occurs
241 * between checking job_no and calling sleep_next_period().
242 * A proper solution would requiring adding another callback
243 * in the plugin structure and testing the condition with
244 * interrupts disabled.
245 *
246 * FIXME: At least problem 2 should be taken care of eventually.
247 */
248 while (!retval && job > current->rt_param.job_params.job_no)
249 /* If the last job overran then job <= job_no and we
250 * don't send the task to sleep.
251 */
252 retval = litmus->complete_job();
253 out:
254 return retval;
255}
256
257/* This is a helper syscall to query the current job sequence number.
258 *
259 * returns 0 on successful query
260 * returns EPERM if task is not a real-time task.
261 * returns EFAULT if &job is not a valid pointer.
262 */
263asmlinkage long sys_query_job_no(unsigned int __user *job)
264{
265 int retval = -EPERM;
266 if (is_realtime(current))
267 retval = put_user(current->rt_param.job_params.job_no, job);
268
269 return retval;
270}
271
272/* sys_null_call() is only used for determining raw system call
273 * overheads (kernel entry, kernel exit). It has no useful side effects.
274 * If ts is non-NULL, then the current Feather-Trace time is recorded.
275 */
276asmlinkage long sys_null_call(cycles_t __user *ts)
277{
278 long ret = 0;
279 cycles_t now;
280
281 if (ts) {
282 now = get_cycles();
283 ret = put_user(now, ts);
284 }
285
286 return ret;
287}
288
289/* p is a real-time task. Re-init its state as a best-effort task. */
290static void reinit_litmus_state(struct task_struct* p, int restore)
291{
292 struct rt_task user_config = {};
293 void* ctrl_page = NULL;
294
295 if (restore) {
296 /* Safe user-space provided configuration data.
297 * and allocated page. */
298 user_config = p->rt_param.task_params;
299 ctrl_page = p->rt_param.ctrl_page;
300 }
301
302 /* We probably should not be inheriting any task's priority
303 * at this point in time.
304 */
305 WARN_ON(p->rt_param.inh_task);
306
307 /* Cleanup everything else. */
308 memset(&p->rt_param, 0, sizeof(p->rt_param));
309
310 /* Restore preserved fields. */
311 if (restore) {
312 p->rt_param.task_params = user_config;
313 p->rt_param.ctrl_page = ctrl_page;
314 }
315}
316
317long litmus_admit_task(struct task_struct* tsk)
318{
319 long retval = 0;
320
321 BUG_ON(is_realtime(tsk));
322
323 tsk_rt(tsk)->heap_node = NULL;
324 tsk_rt(tsk)->rel_heap = NULL;
325
326 if (get_rt_relative_deadline(tsk) == 0 ||
327 get_exec_cost(tsk) >
328 min(get_rt_relative_deadline(tsk), get_rt_period(tsk)) ) {
329 TRACE_TASK(tsk,
330 "litmus admit: invalid task parameters "
331 "(e = %lu, p = %lu, d = %lu)\n",
332 get_exec_cost(tsk), get_rt_period(tsk),
333 get_rt_relative_deadline(tsk));
334 retval = -EINVAL;
335 goto out;
336 }
337
338 if (!cpu_online(get_partition(tsk))) {
339 TRACE_TASK(tsk, "litmus admit: cpu %d is not online\n",
340 get_partition(tsk));
341 retval = -EINVAL;
342 goto out;
343 }
344
345 INIT_LIST_HEAD(&tsk_rt(tsk)->list);
346
347 /* allocate heap node for this task */
348 tsk_rt(tsk)->heap_node = bheap_node_alloc(GFP_ATOMIC);
349 tsk_rt(tsk)->rel_heap = release_heap_alloc(GFP_ATOMIC);
350
351 if (!tsk_rt(tsk)->heap_node || !tsk_rt(tsk)->rel_heap) {
352 printk(KERN_WARNING "litmus: no more heap node memory!?\n");
353
354 retval = -ENOMEM;
355 goto out;
356 } else {
357 bheap_node_init(&tsk_rt(tsk)->heap_node, tsk);
358 }
359
360 preempt_disable();
361
362 retval = litmus->admit_task(tsk);
363
364 if (!retval) {
365 sched_trace_task_name(tsk);
366 sched_trace_task_param(tsk);
367 atomic_inc(&rt_task_count);
368 }
369
370 preempt_enable();
371
372out:
373 if (retval) {
374 bheap_node_free(tsk_rt(tsk)->heap_node);
375 release_heap_free(tsk_rt(tsk)->rel_heap);
376 }
377 return retval;
378}
379
380void litmus_exit_task(struct task_struct* tsk)
381{
382 if (is_realtime(tsk)) {
383 sched_trace_task_completion(tsk, 1);
384
385 litmus->task_exit(tsk);
386
387 BUG_ON(bheap_node_in_heap(tsk_rt(tsk)->heap_node));
388 bheap_node_free(tsk_rt(tsk)->heap_node);
389 release_heap_free(tsk_rt(tsk)->rel_heap);
390
391 atomic_dec(&rt_task_count);
392 reinit_litmus_state(tsk, 1);
393 }
394}
395
396static int do_plugin_switch(void *_plugin)
397{
398 int ret;
399 struct sched_plugin* plugin = _plugin;
400
401 /* don't switch if there are active real-time tasks */
402 if (atomic_read(&rt_task_count) == 0) {
403 ret = litmus->deactivate_plugin();
404 if (0 != ret)
405 goto out;
406 ret = plugin->activate_plugin();
407 if (0 != ret) {
408 printk(KERN_INFO "Can't activate %s (%d).\n",
409 plugin->plugin_name, ret);
410 plugin = &linux_sched_plugin;
411 }
412 printk(KERN_INFO "Switching to LITMUS^RT plugin %s.\n", plugin->plugin_name);
413 litmus = plugin;
414 } else
415 ret = -EBUSY;
416out:
417 return ret;
418}
419
420/* Switching a plugin in use is tricky.
421 * We must watch out that no real-time tasks exists
422 * (and that none is created in parallel) and that the plugin is not
423 * currently in use on any processor (in theory).
424 */
425int switch_sched_plugin(struct sched_plugin* plugin)
426{
427 BUG_ON(!plugin);
428
429 if (atomic_read(&rt_task_count) == 0)
430 return stop_machine(do_plugin_switch, plugin, NULL);
431 else
432 return -EBUSY;
433}
434
435/* Called upon fork.
436 * p is the newly forked task.
437 */
438void litmus_fork(struct task_struct* p)
439{
440 if (is_realtime(p)) {
441 /* clean out any litmus related state, don't preserve anything */
442 reinit_litmus_state(p, 0);
443 /* Don't let the child be a real-time task. */
444 p->sched_reset_on_fork = 1;
445 } else
446 /* non-rt tasks might have ctrl_page set */
447 tsk_rt(p)->ctrl_page = NULL;
448
449 /* od tables are never inherited across a fork */
450 p->od_table = NULL;
451}
452
453/* Called upon execve().
454 * current is doing the exec.
455 * Don't let address space specific stuff leak.
456 */
457void litmus_exec(void)
458{
459 struct task_struct* p = current;
460
461 if (is_realtime(p)) {
462 WARN_ON(p->rt_param.inh_task);
463 if (tsk_rt(p)->ctrl_page) {
464 free_page((unsigned long) tsk_rt(p)->ctrl_page);
465 tsk_rt(p)->ctrl_page = NULL;
466 }
467 }
468}
469
470void exit_litmus(struct task_struct *dead_tsk)
471{
472 /* We also allow non-RT tasks to
473 * allocate control pages to allow
474 * measurements with non-RT tasks.
475 * So check if we need to free the page
476 * in any case.
477 */
478 if (tsk_rt(dead_tsk)->ctrl_page) {
479 TRACE_TASK(dead_tsk,
480 "freeing ctrl_page %p\n",
481 tsk_rt(dead_tsk)->ctrl_page);
482 free_page((unsigned long) tsk_rt(dead_tsk)->ctrl_page);
483 }
484
485 /* main cleanup only for RT tasks */
486 if (is_realtime(dead_tsk))
487 litmus_exit_task(dead_tsk);
488}
489
490
491#ifdef CONFIG_MAGIC_SYSRQ
492int sys_kill(int pid, int sig);
493
494static void sysrq_handle_kill_rt_tasks(int key)
495{
496 struct task_struct *t;
497 read_lock(&tasklist_lock);
498 for_each_process(t) {
499 if (is_realtime(t)) {
500 sys_kill(t->pid, SIGKILL);
501 }
502 }
503 read_unlock(&tasklist_lock);
504}
505
506static struct sysrq_key_op sysrq_kill_rt_tasks_op = {
507 .handler = sysrq_handle_kill_rt_tasks,
508 .help_msg = "quit-rt-tasks(X)",
509 .action_msg = "sent SIGKILL to all LITMUS^RT real-time tasks",
510};
511#endif
512
513extern struct sched_plugin linux_sched_plugin;
514
515static int litmus_shutdown_nb(struct notifier_block *unused1,
516 unsigned long unused2, void *unused3)
517{
518 /* Attempt to switch back to regular Linux scheduling.
519 * Forces the active plugin to clean up.
520 */
521 if (litmus != &linux_sched_plugin) {
522 int ret = switch_sched_plugin(&linux_sched_plugin);
523 if (ret) {
524 printk("Auto-shutdown of active Litmus plugin failed.\n");
525 }
526 }
527 return NOTIFY_DONE;
528}
529
530static struct notifier_block shutdown_notifier = {
531 .notifier_call = litmus_shutdown_nb,
532};
533
534static int __init _init_litmus(void)
535{
536 /* Common initializers,
537 * mode change lock is used to enforce single mode change
538 * operation.
539 */
540 printk("Starting LITMUS^RT kernel\n");
541
542 register_sched_plugin(&linux_sched_plugin);
543
544 bheap_node_cache = KMEM_CACHE(bheap_node, SLAB_PANIC);
545 release_heap_cache = KMEM_CACHE(release_heap, SLAB_PANIC);
546
547#ifdef CONFIG_MAGIC_SYSRQ
548 /* offer some debugging help */
549 if (!register_sysrq_key('x', &sysrq_kill_rt_tasks_op))
550 printk("Registered kill rt tasks magic sysrq.\n");
551 else
552 printk("Could not register kill rt tasks magic sysrq.\n");
553#endif
554
555 init_litmus_proc();
556
557#ifdef CONFIG_SCHED_CPU_AFFINITY
558 init_topology();
559#endif
560
561 register_reboot_notifier(&shutdown_notifier);
562
563 return 0;
564}
565
566static void _exit_litmus(void)
567{
568 unregister_reboot_notifier(&shutdown_notifier);
569
570 exit_litmus_proc();
571 kmem_cache_destroy(bheap_node_cache);
572 kmem_cache_destroy(release_heap_cache);
573}
574
575module_init(_init_litmus);
576module_exit(_exit_litmus);