summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2009-09-24 15:14:22 -0400
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2009-09-24 15:14:22 -0400
commit069bf2e2ae96a03d3bdcaa1934b6fcd43d372850 (patch)
treeb4bf38833867a51920d439702a993165a9f33638
parent1f946afc63455f4a11c84cf2c66e1d333e7c0425 (diff)
Release 2008.3.
-rw-r--r--doc/changes.html84
-rw-r--r--doc/changes.txt95
-rw-r--r--download/2008.3/SHA256SUMS3
-rw-r--r--download/2008.3/ft_tools-2008.3.tgzbin0 -> 5560 bytes
-rw-r--r--download/2008.3/liblitmus-2008.3.tgzbin0 -> 12992 bytes
-rw-r--r--download/2008.3/litmus-rt-2008.3.patch10581
-rw-r--r--download/2008.3/qemu-config1420
-rw-r--r--index.html68
8 files changed, 12239 insertions, 12 deletions
diff --git a/doc/changes.html b/doc/changes.html
new file mode 100644
index 0000000..1c2a941
--- /dev/null
+++ b/doc/changes.html
@@ -0,0 +1,84 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
6 <meta name="verify-v1" content="pZNmf5XyUUfAPdlSPbFSavMUsLgVsmBYOXzOhbIy2gw=" />
7 <link rel="stylesheet" type="text/css" href="../inc/format-doc.css"/>
8 <title>changes.txt</title>
9 </head>
10 <body>
11<h1>LITMUS<sup>RT</sup> Change Log</h1>
12
13<div class="preamble">
14This document is part of the documentation of the <a href="../index.html">LITMUS<sup>RT</sup> project</a>.
15</div>
16
17<h2>2008.2 -> 2008.3</h2>
18
19<ul>
20<li><p>New feature: <code>sys_null_call()</code>, a dummy system call that simplifies the process
21of determining system call overheads [<code>litmus/litmus.c</code>].</p></li>
22<li><p>New feature: support for starting timers on remote CPUs via
23<code>hrtimer_start_on()</code> [<code>kernel/hrtimer.c</code>].</p></li>
24<li><p>New feature: support dedicated release handling in GSN-EDF and a
25corresponding <code>/proc</code> interface [<code>litmus/rt_domain.c</code>, <code>litmus/sched_gsn_edf.c</code>,
26<code>litmus/litmus.c</code>].</p></li>
27<li><p>New feature: support IPI latency tracing [<code>litmus/trace.c</code>].</p></li>
28<li><p>Warn if a task's priority is compared against itself [<code>litmus/edf_common.c</code>].</p></li>
29<li><p>Remove duplicated code in heap_node allocation and allocate heap_node structs
30from a dedicated slab [<code>litmus/litmus.c</code>].</p></li>
31<li><p>Avoid memory allocation/de-allocation in the release queue handling hot-path
32[<code>litmus/rt_domain.c</code>]</p></li>
33<li><p>Use per-event hrtimers instead of multiplexing all future releases onto a
34single timer. Linux's hrtimers are cheap enough to do this, and it removes
35complexity.</p></li>
36<li><p>Uninline binomial heap implementation to reduce code size [<code>litmus/heap.c</code>].</p></li>
37<li><p>Assorted minor debugging improvements.</p></li>
38<li><p>Minor code cleanups.</p></li>
39<li><p>Bugfix: use <code>is_running()</code> in <code>litmus_schedule()</code> to test for task state change
40race; otherwise plugins might get confused due to unexpected
41<code>task_block()</code>/<code>wake_up()</code> calls.</p></li>
42<li><p>Bugfix: avoid deadlock in <code>hrtimer_cancel()</code>; use <code>hrtimer_try_to_cancel()</code>
43instead [<code>litmus/rt_domain.c</code>].</p></li>
44<li><p>Bugfix: avoid race that lead to arming the same timer twice
45[<code>litmus/rt_domain.c</code>].</p></li>
46<li><p>Bugfix: avoid use-after-free race in <code>release_heap</code> [<code>litmus/rt_domain.c</code>].</p></li>
47<li><p>Bugfix: avoid rare deadlock between timer base lock and release lock
48[<code>litmus/rt_domain.c</code>].</p></li>
49<li><p>Bugfix: fix compilation with <code>CONFIG_SCHED_TASK_TRACE</code> on <code>sparc64</code>
50[<code>include/litmus/sched_trace.h</code>].</p></li>
51<li><p>Bugfix: fix Linux execution time accounting in Litmus scheduling class so
52that <code>top(1)</code> and <code>ps(1)</code> work again [<code>litmus/sched_litmus.c</code>].</p></li>
53<li><p>Bugfix: make sure magic sysrq hotkeys do not collide [<code>litmus/litmus.c</code>].</p></li>
54<li><p><code>liblitmus</code>: switch to <code>scons</code> build system.</p></li>
55<li><p><code>liblitmus</code>: support <code>x86-64</code>-><code>i386</code> cross compilation.</p></li>
56<li><p><code>liblitmus</code>: add <code>cycles</code> tools to simplify measuring of CPU cycles per
57second.</p></li>
58<li><p><code>liblitmus</code>: support <code>null_call()</code> system call and add <code>null_call</code> tool (for
59system call overhead measurements).</p></li>
60<li><p><code>liblitmus</code>: improved diagnostic output if <code>setsched</code> fails.</p></li>
61<li><p><code>liblitmus</code>: support fractional costs and periods in <code>rtspin</code>.</p></li>
62<li><p><code>liblitmus</code>: improve <code>release_ts</code> with <code>-w</code> (wait for all tasks) and <code>-f</code>
63(wait for specified number of tasks) options.</p></li>
64<li><p><code>liblitmus</code>: remove outdated tests (<code>mode_test</code>, <code>np_test</code>, and <code>wait_test</code>).</p></li>
65<li><p><code>liblitmus</code>: remove <code>sched_trace</code> support. The removed code will be part of a
66future standalone <code>sched_trace</code> library.</p></li>
67<li><p><code>ft_tools</code>: switch to <code>scons</code> build system.</p></li>
68<li><p><code>ft_tools</code>: support <code>x86-64</code>-><code>i386</code> cross compilation.</p></li>
69<li><p><code>ft_tools</code>: support for IPI latency measurements (<code>SEND_RESCHED</code>).</p></li>
70</ul>
71
72<h2>Change History</h2>
73
74<ul>
75<li>Initially created by <a href="http://www.cs.unc.edu/~bbb">Bjoern B. Brandenburg</a> (bbb at cs.unc.edu) on 09/24/2009.</li>
76</ul>
77<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
78</script>
79<script type="text/javascript">
80_uacct = "UA-3184628-1";
81urchinTracker();
82</script>
83</body>
84</html>
diff --git a/doc/changes.txt b/doc/changes.txt
new file mode 100644
index 0000000..2b40e90
--- /dev/null
+++ b/doc/changes.txt
@@ -0,0 +1,95 @@
1LITMUS<sup>RT</sup> Change Log
2==============================
3
4<div class="preamble">
5This document is part of the documentation of the <a href="../index.html">LITMUS<sup>RT</sup> project</a>.
6</div>
7
82008.2 -> 2008.3
9----------------
10
11- New feature: `sys_null_call()`, a dummy system call that simplifies the process
12 of determining system call overheads [`litmus/litmus.c`].
13
14- New feature: support for starting timers on remote CPUs via
15 `hrtimer_start_on()` [`kernel/hrtimer.c`].
16
17- New feature: support dedicated release handling in GSN-EDF and a
18 corresponding `/proc` interface [`litmus/rt_domain.c`, `litmus/sched_gsn_edf.c`,
19 `litmus/litmus.c`].
20
21- New feature: support IPI latency tracing [`litmus/trace.c`].
22
23- Warn if a task's priority is compared against itself [`litmus/edf_common.c`].
24
25- Remove duplicated code in heap_node allocation and allocate heap_node structs
26 from a dedicated slab [`litmus/litmus.c`].
27
28- Avoid memory allocation/de-allocation in the release queue handling hot-path
29 [`litmus/rt_domain.c`]
30
31- Use per-event hrtimers instead of multiplexing all future releases onto a
32 single timer. Linux's hrtimers are cheap enough to do this, and it removes
33 complexity.
34
35- Uninline binomial heap implementation to reduce code size [`litmus/heap.c`].
36
37- Assorted minor debugging improvements.
38
39- Minor code cleanups.
40
41- Bugfix: use `is_running()` in `litmus_schedule()` to test for task state change
42 race; otherwise plugins might get confused due to unexpected
43 `task_block()`/`wake_up()` calls.
44
45- Bugfix: avoid deadlock in `hrtimer_cancel()`; use `hrtimer_try_to_cancel()`
46 instead [`litmus/rt_domain.c`].
47
48- Bugfix: avoid race that lead to arming the same timer twice
49 [`litmus/rt_domain.c`].
50
51- Bugfix: avoid use-after-free race in `release_heap` [`litmus/rt_domain.c`].
52
53- Bugfix: avoid rare deadlock between timer base lock and release lock
54 [`litmus/rt_domain.c`].
55
56- Bugfix: fix compilation with `CONFIG_SCHED_TASK_TRACE` on `sparc64`
57 [`include/litmus/sched_trace.h`].
58
59- Bugfix: fix Linux execution time accounting in Litmus scheduling class so
60 that `top(1)` and `ps(1)` work again [`litmus/sched_litmus.c`].
61
62- Bugfix: make sure magic sysrq hotkeys do not collide [`litmus/litmus.c`].
63
64- `liblitmus`: switch to `scons` build system.
65
66- `liblitmus`: support `x86-64`->`i386` cross compilation.
67
68- `liblitmus`: add `cycles` tools to simplify measuring of CPU cycles per
69 second.
70
71- `liblitmus`: support `null_call()` system call and add `null_call` tool (for
72 system call overhead measurements).
73
74- `liblitmus`: improved diagnostic output if `setsched` fails.
75
76- `liblitmus`: support fractional costs and periods in `rtspin`.
77
78- `liblitmus`: improve `release_ts` with `-w` (wait for all tasks) and `-f`
79 (wait for specified number of tasks) options.
80
81- `liblitmus`: remove outdated tests (`mode_test`, `np_test`, and `wait_test`).
82
83- `liblitmus`: remove `sched_trace` support. The removed code will be part of a
84 future standalone `sched_trace` library.
85
86- `ft_tools`: switch to `scons` build system.
87
88- `ft_tools`: support `x86-64`->`i386` cross compilation.
89
90- `ft_tools`: support for IPI latency measurements (`SEND_RESCHED`).
91
92
93Change History
94--------------
95- Initially created by <a href="http://www.cs.unc.edu/~bbb">Bjoern B. Brandenburg</a> (bbb at cs.unc.edu) on 09/24/2009.
diff --git a/download/2008.3/SHA256SUMS b/download/2008.3/SHA256SUMS
new file mode 100644
index 0000000..3fc8896
--- /dev/null
+++ b/download/2008.3/SHA256SUMS
@@ -0,0 +1,3 @@
1ed5c87d795f68951476f64f57ef042ebc1bb2839911e79c92c1d5e3197c8ae59 ft_tools-2008.3.tgz
2e058368d7690e7009c29c704783c2b46a2cc50175fbe648bb82686c273aa54b7 liblitmus-2008.3.tgz
3d72a277785bfd0780d8a966433bea0e355de21c618e665f9853653dcc379302b litmus-rt-2008.3.patch
diff --git a/download/2008.3/ft_tools-2008.3.tgz b/download/2008.3/ft_tools-2008.3.tgz
new file mode 100644
index 0000000..6842901
--- /dev/null
+++ b/download/2008.3/ft_tools-2008.3.tgz
Binary files differ
diff --git a/download/2008.3/liblitmus-2008.3.tgz b/download/2008.3/liblitmus-2008.3.tgz
new file mode 100644
index 0000000..315cbff
--- /dev/null
+++ b/download/2008.3/liblitmus-2008.3.tgz
Binary files differ
diff --git a/download/2008.3/litmus-rt-2008.3.patch b/download/2008.3/litmus-rt-2008.3.patch
new file mode 100644
index 0000000..cb33348
--- /dev/null
+++ b/download/2008.3/litmus-rt-2008.3.patch
@@ -0,0 +1,10581 @@
1 Makefile | 2 +-
2 arch/sparc64/Kconfig | 2 +
3 arch/sparc64/kernel/smp.c | 25 +
4 arch/sparc64/kernel/systbls.S | 21 +-
5 arch/sparc64/kernel/ttable.S | 5 +
6 arch/sparc64/mm/ultra.S | 5 +
7 arch/x86/Kconfig | 2 +
8 arch/x86/boot/boot.h | 16 +-
9 arch/x86/kernel/Makefile_32 | 3 +
10 arch/x86/kernel/ft_event.c | 104 ++++
11 arch/x86/kernel/smp_32.c | 21 +
12 arch/x86/kernel/smpboot_32.c | 2 +
13 arch/x86/kernel/syscall_table_32.S | 17 +
14 fs/exec.c | 3 +
15 fs/inode.c | 2 +
16 include/asm-sparc64/feather_trace.h | 22 +
17 include/asm-sparc64/pil.h | 1 +
18 include/asm-sparc64/spinlock.h | 113 ++--
19 include/asm-sparc64/spinlock_types.h | 5 +-
20 include/asm-sparc64/unistd.h | 6 +-
21 include/asm-x86/feather_trace.h | 104 ++++
22 include/asm-x86/hw_irq_32.h | 1 +
23 include/asm-x86/mach-default/entry_arch.h | 1 +
24 include/asm-x86/mach-default/irq_vectors.h | 2 +
25 include/asm-x86/unistd_32.h | 6 +-
26 include/linux/completion.h | 2 +-
27 include/linux/fs.h | 5 +
28 include/linux/hrtimer.h | 15 +
29 include/linux/sched.h | 11 +
30 include/linux/smp.h | 6 +
31 include/linux/tick.h | 3 +
32 include/linux/time.h | 4 +
33 include/linux/uaccess.h | 16 +
34 include/litmus/edf_common.h | 26 +
35 include/litmus/fdso.h | 69 +++
36 include/litmus/feather_buffer.h | 94 +++
37 include/litmus/feather_trace.h | 37 ++
38 include/litmus/ftdev.h | 49 ++
39 include/litmus/heap.h | 74 +++
40 include/litmus/jobs.h | 9 +
41 include/litmus/litmus.h | 202 ++++++
42 include/litmus/norqlock.h | 26 +
43 include/litmus/rt_domain.h | 164 +++++
44 include/litmus/rt_param.h | 175 ++++++
45 include/litmus/sched_plugin.h | 159 +++++
46 include/litmus/sched_trace.h | 191 ++++++
47 include/litmus/trace.h | 113 ++++
48 include/litmus/unistd.h | 21 +
49 kernel/exit.c | 4 +
50 kernel/fork.c | 8 +
51 kernel/hrtimer.c | 77 +++-
52 kernel/printk.c | 11 +-
53 kernel/sched.c | 99 +++-
54 kernel/sched_fair.c | 2 +-
55 kernel/sched_rt.c | 2 +-
56 kernel/time/tick-sched.c | 44 ++-
57 litmus/Kconfig | 85 +++
58 litmus/Makefile | 18 +
59 litmus/edf_common.c | 103 ++++
60 litmus/fdso.c | 281 +++++++++
61 litmus/fmlp.c | 262 ++++++++
62 litmus/ft_event.c | 43 ++
63 litmus/ftdev.c | 352 +++++++++++
64 litmus/heap.c | 287 +++++++++
65 litmus/jobs.c | 43 ++
66 litmus/litmus.c | 913 ++++++++++++++++++++++++++++
67 litmus/norqlock.c | 76 +++
68 litmus/rt_domain.c | 302 +++++++++
69 litmus/sched_cedf.c | 703 +++++++++++++++++++++
70 litmus/sched_gsn_edf.c | 760 +++++++++++++++++++++++
71 litmus/sched_litmus.c | 245 ++++++++
72 litmus/sched_pfair.c | 882 +++++++++++++++++++++++++++
73 litmus/sched_plugin.c | 199 ++++++
74 litmus/sched_psn_edf.c | 454 ++++++++++++++
75 litmus/sched_task_trace.c | 200 ++++++
76 litmus/sched_trace.c | 507 +++++++++++++++
77 litmus/srp.c | 318 ++++++++++
78 litmus/sync.c | 104 ++++
79 litmus/trace.c | 98 +++
80 79 files changed, 9349 insertions(+), 95 deletions(-)
81
82diff --git a/Makefile b/Makefile
83index 189d8ef..d9e4495 100644
84--- a/Makefile
85+++ b/Makefile
86@@ -597,7 +597,7 @@ export mod_strip_cmd
87
88
89 ifeq ($(KBUILD_EXTMOD),)
90-core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
91+core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ litmus/
92
93 vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
94 $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
95diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
96index 10b212a..8d90b5a 100644
97--- a/arch/sparc64/Kconfig
98+++ b/arch/sparc64/Kconfig
99@@ -471,3 +471,5 @@ source "security/Kconfig"
100 source "crypto/Kconfig"
101
102 source "lib/Kconfig"
103+
104+source "litmus/Kconfig"
105diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
106index c399449..e0d85ff 100644
107--- a/arch/sparc64/kernel/smp.c
108+++ b/arch/sparc64/kernel/smp.c
109@@ -46,6 +46,9 @@
110 #include <asm/ldc.h>
111 #include <asm/hypervisor.h>
112
113+#include <litmus/litmus.h>
114+#include <litmus/trace.h>
115+
116 extern void calibrate_delay(void);
117
118 int sparc64_multi_core __read_mostly;
119@@ -903,6 +906,7 @@ extern unsigned long xcall_flush_tlb_kernel_range;
120 extern unsigned long xcall_report_regs;
121 extern unsigned long xcall_receive_signal;
122 extern unsigned long xcall_new_mmu_context_version;
123+extern unsigned long xcall_pull_timers;
124
125 #ifdef DCACHE_ALIASING_POSSIBLE
126 extern unsigned long xcall_flush_dcache_page_cheetah;
127@@ -1033,6 +1037,8 @@ void smp_receive_signal(int cpu)
128 void smp_receive_signal_client(int irq, struct pt_regs *regs)
129 {
130 clear_softint(1 << irq);
131+ set_tsk_need_resched(current);
132+ TS_SEND_RESCHED_END;
133 }
134
135 void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
136@@ -1413,9 +1419,28 @@ void __init smp_cpus_done(unsigned int max_cpus)
137
138 void smp_send_reschedule(int cpu)
139 {
140+ TS_SEND_RESCHED_START(cpu);
141 smp_receive_signal(cpu);
142 }
143
144+void smp_send_pull_timers(int cpu)
145+{
146+ cpumask_t mask = cpumask_of_cpu(cpu);
147+
148+ if (cpu_online(cpu))
149+ smp_cross_call_masked(&xcall_pull_timers, 0, 0, 0, mask);
150+}
151+
152+void hrtimer_pull(void);
153+
154+void smp_pull_timers_client(int irq, struct pt_regs *regs)
155+{
156+ clear_softint(1 << irq);
157+ TRACE("pull timers interrupt\n");
158+ hrtimer_pull();
159+}
160+
161+
162 /* This is a nop because we capture all other cpus
163 * anyways when making the PROM active.
164 */
165diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
166index 06d1090..7dcbac7 100644
167--- a/arch/sparc64/kernel/systbls.S
168+++ b/arch/sparc64/kernel/systbls.S
169@@ -82,6 +82,13 @@ sys_call_table32:
170 .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
171 /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
172
173+/*LITMUS, 315*/
174+ .word sys_set_rt_task_param, sys_get_rt_task_param, sys_complete_job, sys_register_np_flag, sys_exit_np
175+/*320*/
176+ .word sys_od_open, sys_od_close, sys_fmlp_down, sys_fmlp_up, sys_srp_down
177+/*325*/ .word sys_srp_up, sys_query_job_no, sys_wait_for_job_release, sys_wait_for_ts_release, sys_release_ts
178+
179+
180 #endif /* CONFIG_COMPAT */
181
182 /* Now the 64-bit native Linux syscall table. */
183@@ -154,6 +161,13 @@ sys_call_table:
184 .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
185 /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
186
187+/*LITMUS, 315*/
188+ .word sys_set_rt_task_param, sys_get_rt_task_param, sys_complete_job, sys_register_np_flag, sys_exit_np
189+/*320*/
190+ .word sys_od_open, sys_od_close, sys_fmlp_down, sys_fmlp_up, sys_srp_down
191+/*325*/ .word sys_srp_up, sys_query_job_no, sys_wait_for_job_release, sys_wait_for_ts_release
192+/*330*/ .word sys_release_ts, sys_null_call
193+
194 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
195 defined(CONFIG_SOLARIS_EMUL_MODULE)
196 /* Now the 32-bit SunOS syscall table. */
197@@ -271,6 +285,11 @@ sunos_sys_table:
198 .word sunos_nosys, sunos_nosys, sunos_nosys
199 .word sunos_nosys
200 /*310*/ .word sunos_nosys, sunos_nosys, sunos_nosys
201- .word sunos_nosys, sunos_nosys
202+ .word sunos_nosys, sunos_nosys, sunos_nosys
203+ .word sunos_nosys, sunos_nosys, sunos_nosys
204+ .word sunos_nosys
205+/*320*/ .word sunos_nosys, sunos_nosys, sunos_nosys
206+ .word sunos_nosys, sunos_nosys, sunos_nosys
207+ .word sunos_nosys, sunos_nosys, sunos_nosys
208
209 #endif
210diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
211index 7575aa3..65a23d3 100644
212--- a/arch/sparc64/kernel/ttable.S
213+++ b/arch/sparc64/kernel/ttable.S
214@@ -58,7 +58,12 @@ tl0_irq3: BTRAP(0x43)
215 tl0_irq4: BTRAP(0x44)
216 #endif
217 tl0_irq5: TRAP_IRQ(handler_irq, 5)
218+#ifdef CONFIG_SMP
219+tl0_irq6: TRAP_IRQ(smp_pull_timers_client, 6)
220+tl0_irq7: BTRAP(0x47) BTRAP(0x48) BTRAP(0x49)
221+#else
222 tl0_irq6: BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49)
223+#endif
224 tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d)
225 tl0_irq14: TRAP_IRQ(timer_interrupt, 14)
226 tl0_irq15: TRAP_IRQ(handler_irq, 15)
227diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
228index 2865c10..3f158cf 100644
229--- a/arch/sparc64/mm/ultra.S
230+++ b/arch/sparc64/mm/ultra.S
231@@ -678,6 +678,11 @@ xcall_new_mmu_context_version:
232 wr %g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint
233 retry
234
235+ .globl xcall_pull_timers
236+xcall_pull_timers:
237+ wr %g0, (1 << PIL_SMP_PULL_TIMERS), %set_softint
238+ retry
239+
240 #endif /* CONFIG_SMP */
241
242
243diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
244index 80b7ba4..f99330f 100644
245--- a/arch/x86/Kconfig
246+++ b/arch/x86/Kconfig
247@@ -1620,3 +1620,5 @@ source "security/Kconfig"
248 source "crypto/Kconfig"
249
250 source "lib/Kconfig"
251+
252+source "litmus/Kconfig"
253diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
254index d2b5adf..8ec5752 100644
255--- a/arch/x86/boot/boot.h
256+++ b/arch/x86/boot/boot.h
257@@ -109,7 +109,7 @@ typedef unsigned int addr_t;
258 static inline u8 rdfs8(addr_t addr)
259 {
260 u8 v;
261- asm volatile("movb %%fs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
262+ asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
263 return v;
264 }
265 static inline u16 rdfs16(addr_t addr)
266@@ -127,21 +127,21 @@ static inline u32 rdfs32(addr_t addr)
267
268 static inline void wrfs8(u8 v, addr_t addr)
269 {
270- asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "r" (v));
271+ asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "qi" (v));
272 }
273 static inline void wrfs16(u16 v, addr_t addr)
274 {
275- asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "r" (v));
276+ asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "ri" (v));
277 }
278 static inline void wrfs32(u32 v, addr_t addr)
279 {
280- asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "r" (v));
281+ asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "ri" (v));
282 }
283
284 static inline u8 rdgs8(addr_t addr)
285 {
286 u8 v;
287- asm volatile("movb %%gs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
288+ asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
289 return v;
290 }
291 static inline u16 rdgs16(addr_t addr)
292@@ -159,15 +159,15 @@ static inline u32 rdgs32(addr_t addr)
293
294 static inline void wrgs8(u8 v, addr_t addr)
295 {
296- asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "r" (v));
297+ asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "qi" (v));
298 }
299 static inline void wrgs16(u16 v, addr_t addr)
300 {
301- asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "r" (v));
302+ asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "ri" (v));
303 }
304 static inline void wrgs32(u32 v, addr_t addr)
305 {
306- asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "r" (v));
307+ asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "ri" (v));
308 }
309
310 /* Note: these only return true/false, not a signed return value! */
311diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
312index a7bc93c..5f87f32 100644
313--- a/arch/x86/kernel/Makefile_32
314+++ b/arch/x86/kernel/Makefile_32
315@@ -49,6 +49,9 @@ obj-y += pcspeaker.o
316
317 obj-$(CONFIG_SCx200) += scx200_32.o
318
319+obj-$(CONFIG_FEATHER_TRACE) += ft_event.o
320+
321+
322 # vsyscall_32.o contains the vsyscall DSO images as __initdata.
323 # We must build both images before we can assemble it.
324 # Note: kbuild does not track this dependency due to usage of .incbin
325diff --git a/arch/x86/kernel/ft_event.c b/arch/x86/kernel/ft_event.c
326new file mode 100644
327index 0000000..b1d80c5
328--- /dev/null
329+++ b/arch/x86/kernel/ft_event.c
330@@ -0,0 +1,104 @@
331+#include <linux/types.h>
332+
333+#include <litmus/feather_trace.h>
334+
335+/* the feather trace management functions assume
336+ * exclusive access to the event table
337+ */
338+
339+
340+#define BYTE_JUMP 0xeb
341+#define BYTE_JUMP_LEN 0x02
342+
343+/* for each event, there is an entry in the event table */
344+struct trace_event {
345+ long id;
346+ long count;
347+ long start_addr;
348+ long end_addr;
349+};
350+
351+extern struct trace_event __start___event_table[];
352+extern struct trace_event __stop___event_table[];
353+
354+int ft_enable_event(unsigned long id)
355+{
356+ struct trace_event* te = __start___event_table;
357+ int count = 0;
358+ char* delta;
359+ unsigned char* instr;
360+
361+ while (te < __stop___event_table) {
362+ if (te->id == id && ++te->count == 1) {
363+ instr = (unsigned char*) te->start_addr;
364+ /* make sure we don't clobber something wrong */
365+ if (*instr == BYTE_JUMP) {
366+ delta = (((unsigned char*) te->start_addr) + 1);
367+ *delta = 0;
368+ }
369+ }
370+ if (te->id == id)
371+ count++;
372+ te++;
373+ }
374+ return count;
375+}
376+
377+int ft_disable_event(unsigned long id)
378+{
379+ struct trace_event* te = __start___event_table;
380+ int count = 0;
381+ char* delta;
382+ unsigned char* instr;
383+
384+ while (te < __stop___event_table) {
385+ if (te->id == id && --te->count == 0) {
386+ instr = (unsigned char*) te->start_addr;
387+ if (*instr == BYTE_JUMP) {
388+ delta = (((unsigned char*) te->start_addr) + 1);
389+ *delta = te->end_addr - te->start_addr -
390+ BYTE_JUMP_LEN;
391+ }
392+ }
393+ if (te->id == id)
394+ count++;
395+ te++;
396+ }
397+ return count;
398+}
399+
400+int ft_disable_all_events(void)
401+{
402+ struct trace_event* te = __start___event_table;
403+ int count = 0;
404+ char* delta;
405+ unsigned char* instr;
406+
407+ while (te < __stop___event_table) {
408+ if (te->count) {
409+ instr = (unsigned char*) te->start_addr;
410+ if (*instr == BYTE_JUMP) {
411+ delta = (((unsigned char*) te->start_addr)
412+ + 1);
413+ *delta = te->end_addr - te->start_addr -
414+ BYTE_JUMP_LEN;
415+ te->count = 0;
416+ count++;
417+ }
418+ }
419+ te++;
420+ }
421+ return count;
422+}
423+
424+int ft_is_event_enabled(unsigned long id)
425+{
426+ struct trace_event* te = __start___event_table;
427+
428+ while (te < __stop___event_table) {
429+ if (te->id == id)
430+ return te->count;
431+ te++;
432+ }
433+ return 0;
434+}
435diff --git a/arch/x86/kernel/smp_32.c b/arch/x86/kernel/smp_32.c
436index fcaa026..8d28cee 100644
437--- a/arch/x86/kernel/smp_32.c
438+++ b/arch/x86/kernel/smp_32.c
439@@ -25,6 +25,9 @@
440 #include <asm/mmu_context.h>
441 #include <mach_apic.h>
442
443+#include <litmus/litmus.h>
444+#include <litmus/trace.h>
445+
446 /*
447 * Some notes on x86 processor bugs affecting SMP operation:
448 *
449@@ -472,9 +475,16 @@ void flush_tlb_all(void)
450 static void native_smp_send_reschedule(int cpu)
451 {
452 WARN_ON(cpu_is_offline(cpu));
453+ TS_SEND_RESCHED_START(cpu);
454 send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
455 }
456
457+void smp_send_pull_timers(int cpu)
458+{
459+ WARN_ON(cpu_is_offline(cpu));
460+ send_IPI_mask(cpumask_of_cpu(cpu), PULL_TIMERS_VECTOR);
461+}
462+
463 /*
464 * Structure and data for smp_call_function(). This is designed to minimise
465 * static memory requirements. It also looks cleaner.
466@@ -641,7 +651,18 @@ static void native_smp_send_stop(void)
467 fastcall void smp_reschedule_interrupt(struct pt_regs *regs)
468 {
469 ack_APIC_irq();
470+ set_tsk_need_resched(current);
471 __get_cpu_var(irq_stat).irq_resched_count++;
472+ TS_SEND_RESCHED_END;
473+}
474+
475+extern void hrtimer_pull(void);
476+
477+fastcall void smp_pull_timers_interrupt(struct pt_regs *regs)
478+{
479+ ack_APIC_irq();
480+ TRACE("pull timers interrupt\n");
481+ hrtimer_pull();
482 }
483
484 fastcall void smp_call_function_interrupt(struct pt_regs *regs)
485diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
486index 4ea80cb..133cbb6 100644
487--- a/arch/x86/kernel/smpboot_32.c
488+++ b/arch/x86/kernel/smpboot_32.c
489@@ -1323,6 +1323,8 @@ void __init smp_intr_init(void)
490
491 /* IPI for generic function call */
492 set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
493+
494+ set_intr_gate(PULL_TIMERS_VECTOR, pull_timers_interrupt);
495 }
496
497 /*
498diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
499index 8344c70..65496c2 100644
500--- a/arch/x86/kernel/syscall_table_32.S
501+++ b/arch/x86/kernel/syscall_table_32.S
502@@ -324,3 +324,20 @@ ENTRY(sys_call_table)
503 .long sys_timerfd
504 .long sys_eventfd
505 .long sys_fallocate
506+ /* LITMUS */
507+ .long sys_set_rt_task_param /* 325 */
508+ .long sys_get_rt_task_param
509+ .long sys_complete_job
510+ .long sys_register_np_flag
511+ .long sys_exit_np
512+ .long sys_od_open /* 330 */
513+ .long sys_od_close
514+ .long sys_fmlp_down
515+ .long sys_fmlp_up
516+ .long sys_srp_down
517+ .long sys_srp_up /* 335 */
518+ .long sys_query_job_no
519+ .long sys_wait_for_job_release
520+ .long sys_wait_for_ts_release
521+ .long sys_release_ts
522+ .long sys_null_call /* 340 */
523diff --git a/fs/exec.c b/fs/exec.c
524index 282240a..6f47786 100644
525--- a/fs/exec.c
526+++ b/fs/exec.c
527@@ -56,6 +56,8 @@
528 #include <asm/mmu_context.h>
529 #include <asm/tlb.h>
530
531+#include <litmus/litmus.h>
532+
533 #ifdef CONFIG_KMOD
534 #include <linux/kmod.h>
535 #endif
536@@ -1309,6 +1311,7 @@ int do_execve(char * filename,
537 goto out_kfree;
538
539 sched_exec();
540+ litmus_exec();
541
542 bprm->file = file;
543 bprm->filename = filename;
544diff --git a/fs/inode.c b/fs/inode.c
545index ed35383..ef71ea0 100644
546--- a/fs/inode.c
547+++ b/fs/inode.c
548@@ -220,6 +220,8 @@ void inode_init_once(struct inode *inode)
549 INIT_LIST_HEAD(&inode->inotify_watches);
550 mutex_init(&inode->inotify_mutex);
551 #endif
552+ INIT_LIST_HEAD(&inode->i_obj_list);
553+ mutex_init(&inode->i_obj_mutex);
554 }
555
556 EXPORT_SYMBOL(inode_init_once);
557diff --git a/include/asm-sparc64/feather_trace.h b/include/asm-sparc64/feather_trace.h
558new file mode 100644
559index 0000000..35ec70f
560--- /dev/null
561+++ b/include/asm-sparc64/feather_trace.h
562@@ -0,0 +1,22 @@
563+#ifndef _ARCH_FEATHER_TRACE_H
564+#define _ARCH_FEATHER_TRACE_H
565+
566+#include <asm/atomic.h>
567+#include <asm/timex.h>
568+
569+static inline int fetch_and_inc(int *val)
570+{
571+ return atomic_add_ret(1, (atomic_t*) val) - 1;
572+}
573+
574+static inline int fetch_and_dec(int *val)
575+{
576+ return atomic_sub_ret(1, (atomic_t*) val) + 1;
577+}
578+
579+static inline unsigned long long ft_timestamp(void)
580+{
581+ return get_cycles();
582+}
583+
584+#endif
585diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h
586index 7292774..5b36432 100644
587--- a/include/asm-sparc64/pil.h
588+++ b/include/asm-sparc64/pil.h
589@@ -18,6 +18,7 @@
590 #define PIL_SMP_CAPTURE 3
591 #define PIL_SMP_CTX_NEW_VERSION 4
592 #define PIL_DEVICE_IRQ 5
593+#define PIL_SMP_PULL_TIMERS 6
594
595 #ifndef __ASSEMBLY__
596 #define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \
597diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h
598index 0006fe9..16931d4 100644
599--- a/include/asm-sparc64/spinlock.h
600+++ b/include/asm-sparc64/spinlock.h
601@@ -15,93 +15,80 @@
602 * and rebuild your kernel.
603 */
604
605-/* All of these locking primitives are expected to work properly
606- * even in an RMO memory model, which currently is what the kernel
607- * runs in.
608- *
609- * There is another issue. Because we play games to save cycles
610- * in the non-contention case, we need to be extra careful about
611- * branch targets into the "spinning" code. They live in their
612- * own section, but the newer V9 branches have a shorter range
613- * than the traditional 32-bit sparc branch variants. The rule
614- * is that the branches that go into and out of the spinner sections
615- * must be pre-V9 branches.
616- */
617-
618-#define __raw_spin_is_locked(lp) ((lp)->lock != 0)
619+#define __raw_spin_is_locked(lp) ((lp)->tail != (lp)->head)
620
621 #define __raw_spin_unlock_wait(lp) \
622 do { rmb(); \
623- } while((lp)->lock)
624+ } while((lp)->tail != (lp)->head)
625+
626+
627
628 static inline void __raw_spin_lock(raw_spinlock_t *lock)
629 {
630- unsigned long tmp;
631-
632+ int ticket, tmp;
633 __asm__ __volatile__(
634-"1: ldstub [%1], %0\n"
635-" membar #StoreLoad | #StoreStore\n"
636-" brnz,pn %0, 2f\n"
637-" nop\n"
638-" .subsection 2\n"
639-"2: ldub [%1], %0\n"
640-" membar #LoadLoad\n"
641-" brnz,pt %0, 2b\n"
642-" nop\n"
643-" ba,a,pt %%xcc, 1b\n"
644-" .previous"
645- : "=&r" (tmp)
646- : "r" (lock)
647+"1: lduw [%2], %0 \n" /* read ticket */
648+" add %0, 1, %1 \n"
649+" cas [%2], %0, %1 \n"
650+" cmp %0, %1 \n"
651+" be,a,pt %%icc, 2f \n"
652+" nop \n"
653+" membar #LoadLoad | #StoreLoad | #LoadStore\n"
654+" ba 1b\n"
655+" nop \n"
656+"2: lduw [%3], %1 \n"
657+" cmp %0, %1 \n"
658+" be,a,pt %%icc, 3f \n"
659+" nop \n"
660+" membar #LoadLoad | #StoreLoad | #LoadStore\n"
661+" ba 2b\n"
662+"3: membar #StoreStore | #StoreLoad"
663+ : "=&r" (ticket), "=&r" (tmp)
664+ : "r" (&lock->tail), "r" (&lock->head)
665 : "memory");
666 }
667
668 static inline int __raw_spin_trylock(raw_spinlock_t *lock)
669 {
670- unsigned long result;
671-
672+ int tail, head;
673 __asm__ __volatile__(
674-" ldstub [%1], %0\n"
675-" membar #StoreLoad | #StoreStore"
676- : "=r" (result)
677- : "r" (lock)
678+" lduw [%2], %0 \n" /* read tail */
679+" lduw [%3], %1 \n" /* read head */
680+" cmp %0, %1 \n"
681+" bne,a,pn %%icc, 1f \n"
682+" nop \n"
683+" inc %1 \n"
684+" cas [%2], %0, %1 \n" /* try to inc ticket */
685+" membar #StoreStore | #StoreLoad \n"
686+"1: "
687+ : "=&r" (tail), "=&r" (head)
688+ : "r" (&lock->tail), "r" (&lock->head)
689 : "memory");
690
691- return (result == 0UL);
692+ return tail == head;
693 }
694
695 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
696 {
697+ int tmp;
698 __asm__ __volatile__(
699-" membar #StoreStore | #LoadStore\n"
700-" stb %%g0, [%0]"
701- : /* No outputs */
702- : "r" (lock)
703+" membar #StoreStore | #LoadStore \n"
704+" lduw [%1], %0 \n"
705+" inc %0 \n"
706+" st %0, [%1] \n"
707+" membar #StoreStore | #StoreLoad"
708+ : "=&r" (tmp)
709+ : "r" (&lock->head)
710 : "memory");
711 }
712
713-static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags)
714-{
715- unsigned long tmp1, tmp2;
716+/* We don't handle this yet, but it looks like not re-enabling the interrupts
717+ * works fine, too. For example, lockdep also does it like this.
718+ */
719+#define __raw_spin_lock_flags(l, f) __raw_spin_lock(l)
720+
721+
722
723- __asm__ __volatile__(
724-"1: ldstub [%2], %0\n"
725-" membar #StoreLoad | #StoreStore\n"
726-" brnz,pn %0, 2f\n"
727-" nop\n"
728-" .subsection 2\n"
729-"2: rdpr %%pil, %1\n"
730-" wrpr %3, %%pil\n"
731-"3: ldub [%2], %0\n"
732-" membar #LoadLoad\n"
733-" brnz,pt %0, 3b\n"
734-" nop\n"
735-" ba,pt %%xcc, 1b\n"
736-" wrpr %1, %%pil\n"
737-" .previous"
738- : "=&r" (tmp1), "=&r" (tmp2)
739- : "r"(lock), "r"(flags)
740- : "memory");
741-}
742
743 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
744
745diff --git a/include/asm-sparc64/spinlock_types.h b/include/asm-sparc64/spinlock_types.h
746index e128112..1a2e24b 100644
747--- a/include/asm-sparc64/spinlock_types.h
748+++ b/include/asm-sparc64/spinlock_types.h
749@@ -6,10 +6,11 @@
750 #endif
751
752 typedef struct {
753- volatile unsigned char lock;
754+ int tail;
755+ int head;
756 } raw_spinlock_t;
757
758-#define __RAW_SPIN_LOCK_UNLOCKED { 0 }
759+#define __RAW_SPIN_LOCK_UNLOCKED { 0, 0 }
760
761 typedef struct {
762 volatile unsigned int lock;
763diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
764index cb751b4..ebebde6 100644
765--- a/include/asm-sparc64/unistd.h
766+++ b/include/asm-sparc64/unistd.h
767@@ -333,7 +333,11 @@
768 #define __NR_eventfd 313
769 #define __NR_fallocate 314
770
771-#define NR_SYSCALLS 315
772+#define __NR_LITMUS 315
773+
774+#include "litmus/unistd.h"
775+
776+#define NR_SYSCALLS 315 + NR_litmus_syscalls
777
778 #ifdef __KERNEL__
779 /* sysconf options, for SunOS compatibility */
780diff --git a/include/asm-x86/feather_trace.h b/include/asm-x86/feather_trace.h
781new file mode 100644
782index 0000000..253067e
783--- /dev/null
784+++ b/include/asm-x86/feather_trace.h
785@@ -0,0 +1,104 @@
786+#ifndef _ARCH_FEATHER_TRACE_H
787+#define _ARCH_FEATHER_TRACE_H
788+
789+static inline int fetch_and_inc(int *val)
790+{
791+ int ret = 1;
792+ __asm__ __volatile__("lock; xaddl %0, %1" : "+r" (ret), "+m" (*val) : : "memory" );
793+ return ret;
794+}
795+
796+static inline int fetch_and_dec(int *val)
797+{
798+ int ret = -1;
799+ __asm__ __volatile__("lock; xaddl %0, %1" : "+r" (ret), "+m" (*val) : : "memory" );
800+ return ret;
801+}
802+
803+#define feather_callback __attribute__((regparm(0)))
804+
805+/* make the compiler reload any register that is not saved in
806+ * a cdecl function call
807+ */
808+#define CLOBBER_LIST "memory", "cc", "eax", "ecx", "edx"
809+
810+#define ft_event(id, callback) \
811+ __asm__ __volatile__( \
812+ "1: jmp 2f \n\t" \
813+ " call " #callback " \n\t" \
814+ ".section __event_table, \"aw\" \n\t" \
815+ ".long " #id ", 0, 1b, 2f \n\t" \
816+ ".previous \n\t" \
817+ "2: \n\t" \
818+ : : : CLOBBER_LIST)
819+
820+#define ft_event0(id, callback) \
821+ __asm__ __volatile__( \
822+ "1: jmp 2f \n\t" \
823+ " subl $4, %%esp \n\t" \
824+ " movl $" #id ", (%%esp) \n\t" \
825+ " call " #callback " \n\t" \
826+ " addl $4, %%esp \n\t" \
827+ ".section __event_table, \"aw\" \n\t" \
828+ ".long " #id ", 0, 1b, 2f \n\t" \
829+ ".previous \n\t" \
830+ "2: \n\t" \
831+ : : : CLOBBER_LIST)
832+
833+#define ft_event1(id, callback, param) \
834+ __asm__ __volatile__( \
835+ "1: jmp 2f \n\t" \
836+ " subl $8, %%esp \n\t" \
837+ " movl %0, 4(%%esp) \n\t" \
838+ " movl $" #id ", (%%esp) \n\t" \
839+ " call " #callback " \n\t" \
840+ " addl $8, %%esp \n\t" \
841+ ".section __event_table, \"aw\" \n\t" \
842+ ".long " #id ", 0, 1b, 2f \n\t" \
843+ ".previous \n\t" \
844+ "2: \n\t" \
845+ : : "r" (param) : CLOBBER_LIST)
846+
847+#define ft_event2(id, callback, param, param2) \
848+ __asm__ __volatile__( \
849+ "1: jmp 2f \n\t" \
850+ " subl $12, %%esp \n\t" \
851+ " movl %1, 8(%%esp) \n\t" \
852+ " movl %0, 4(%%esp) \n\t" \
853+ " movl $" #id ", (%%esp) \n\t" \
854+ " call " #callback " \n\t" \
855+ " addl $12, %%esp \n\t" \
856+ ".section __event_table, \"aw\" \n\t" \
857+ ".long " #id ", 0, 1b, 2f \n\t" \
858+ ".previous \n\t" \
859+ "2: \n\t" \
860+ : : "r" (param), "r" (param2) : CLOBBER_LIST)
861+
862+
863+#define ft_event3(id, callback, p, p2, p3) \
864+ __asm__ __volatile__( \
865+ "1: jmp 2f \n\t" \
866+ " subl $16, %%esp \n\t" \
867+ " movl %1, 12(%%esp) \n\t" \
868+ " movl %1, 8(%%esp) \n\t" \
869+ " movl %0, 4(%%esp) \n\t" \
870+ " movl $" #id ", (%%esp) \n\t" \
871+ " call " #callback " \n\t" \
872+ " addl $16, %%esp \n\t" \
873+ ".section __event_table, \"aw\" \n\t" \
874+ ".long " #id ", 0, 1b, 2f \n\t" \
875+ ".previous \n\t" \
876+ "2: \n\t" \
877+ : : "r" (p), "r" (p2), "r" (p3) : CLOBBER_LIST)
878+
879+
880+static inline unsigned long long ft_timestamp(void)
881+{
882+ unsigned long long ret;
883+ __asm__ __volatile__("rdtsc" : "=A" (ret));
884+ return ret;
885+}
886+
887+#define __ARCH_HAS_FEATHER_TRACE
888+
889+#endif
890diff --git a/include/asm-x86/hw_irq_32.h b/include/asm-x86/hw_irq_32.h
891index 0bedbdf..d5d7c67 100644
892--- a/include/asm-x86/hw_irq_32.h
893+++ b/include/asm-x86/hw_irq_32.h
894@@ -32,6 +32,7 @@ extern void (*interrupt[NR_IRQS])(void);
895 fastcall void reschedule_interrupt(void);
896 fastcall void invalidate_interrupt(void);
897 fastcall void call_function_interrupt(void);
898+fastcall void pull_timers_interrupt(void);
899 #endif
900
901 #ifdef CONFIG_X86_LOCAL_APIC
902diff --git a/include/asm-x86/mach-default/entry_arch.h b/include/asm-x86/mach-default/entry_arch.h
903index bc86146..f76a086 100644
904--- a/include/asm-x86/mach-default/entry_arch.h
905+++ b/include/asm-x86/mach-default/entry_arch.h
906@@ -13,6 +13,7 @@
907 BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
908 BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
909 BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
910+BUILD_INTERRUPT(pull_timers_interrupt,PULL_TIMERS_VECTOR)
911 #endif
912
913 /*
914diff --git a/include/asm-x86/mach-default/irq_vectors.h b/include/asm-x86/mach-default/irq_vectors.h
915index 881c63c..fd42e2a 100644
916--- a/include/asm-x86/mach-default/irq_vectors.h
917+++ b/include/asm-x86/mach-default/irq_vectors.h
918@@ -49,6 +49,8 @@
919 #define RESCHEDULE_VECTOR 0xfc
920 #define CALL_FUNCTION_VECTOR 0xfb
921
922+#define PULL_TIMERS_VECTOR 0xfa /* LITMUS hrtimer hack */
923+
924 #define THERMAL_APIC_VECTOR 0xf0
925 /*
926 * Local APIC timer IRQ vector is on a different priority level,
927diff --git a/include/asm-x86/unistd_32.h b/include/asm-x86/unistd_32.h
928index 9b15545..36fec84 100644
929--- a/include/asm-x86/unistd_32.h
930+++ b/include/asm-x86/unistd_32.h
931@@ -331,9 +331,13 @@
932 #define __NR_eventfd 323
933 #define __NR_fallocate 324
934
935+#define __NR_LITMUS 325
936+
937+#include "litmus/unistd.h"
938+
939 #ifdef __KERNEL__
940
941-#define NR_syscalls 325
942+#define NR_syscalls 324 + NR_litmus_syscalls
943
944 #define __ARCH_WANT_IPC_PARSE_VERSION
945 #define __ARCH_WANT_OLD_READDIR
946diff --git a/include/linux/completion.h b/include/linux/completion.h
947index 33d6aaf..5b55e97 100644
948--- a/include/linux/completion.h
949+++ b/include/linux/completion.h
950@@ -51,7 +51,7 @@ extern unsigned long wait_for_completion_interruptible_timeout(
951
952 extern void complete(struct completion *);
953 extern void complete_all(struct completion *);
954-
955+extern void complete_n(struct completion *, int n);
956 #define INIT_COMPLETION(x) ((x).done = 0)
957
958 #endif
959diff --git a/include/linux/fs.h b/include/linux/fs.h
960index b3ec4a4..22f856c 100644
961--- a/include/linux/fs.h
962+++ b/include/linux/fs.h
963@@ -588,6 +588,8 @@ static inline int mapping_writably_mapped(struct address_space *mapping)
964 #define i_size_ordered_init(inode) do { } while (0)
965 #endif
966
967+struct inode_obj_id_table;
968+
969 struct inode {
970 struct hlist_node i_hash;
971 struct list_head i_list;
972@@ -653,6 +655,9 @@ struct inode {
973 void *i_security;
974 #endif
975 void *i_private; /* fs or device private pointer */
976+
977+ struct list_head i_obj_list;
978+ struct mutex i_obj_mutex;
979 };
980
981 /*
982diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
983index 7a9398e..32d456e 100644
984--- a/include/linux/hrtimer.h
985+++ b/include/linux/hrtimer.h
986@@ -200,6 +200,18 @@ struct hrtimer_cpu_base {
987 struct list_head cb_pending;
988 unsigned long nr_events;
989 #endif
990+ struct list_head to_pull;
991+};
992+
993+#define HRTIMER_START_ON_INACTIVE 0
994+#define HRTIMER_START_ON_QUEUED 1
995+
996+struct hrtimer_start_on_info {
997+ struct list_head list;
998+ struct hrtimer* timer;
999+ ktime_t time;
1000+ enum hrtimer_mode mode;
1001+ atomic_t state;
1002 };
1003
1004 #ifdef CONFIG_HIGH_RES_TIMERS
1005@@ -262,6 +274,9 @@ extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock,
1006 /* Basic timer operations: */
1007 extern int hrtimer_start(struct hrtimer *timer, ktime_t tim,
1008 const enum hrtimer_mode mode);
1009+extern int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
1010+ struct hrtimer *timer, ktime_t time,
1011+ const enum hrtimer_mode mode);
1012 extern int hrtimer_cancel(struct hrtimer *timer);
1013 extern int hrtimer_try_to_cancel(struct hrtimer *timer);
1014
1015diff --git a/include/linux/sched.h b/include/linux/sched.h
1016index cc14656..76e28f1 100644
1017--- a/include/linux/sched.h
1018+++ b/include/linux/sched.h
1019@@ -37,6 +37,7 @@
1020 #define SCHED_BATCH 3
1021 /* SCHED_ISO: reserved but not implemented yet */
1022 #define SCHED_IDLE 5
1023+#define SCHED_LITMUS 6
1024
1025 #ifdef __KERNEL__
1026
1027@@ -91,6 +92,8 @@ struct sched_param {
1028
1029 #include <asm/processor.h>
1030
1031+#include <litmus/rt_param.h>
1032+
1033 struct exec_domain;
1034 struct futex_pi_state;
1035 struct bio;
1036@@ -914,6 +917,8 @@ struct sched_entity {
1037 #endif
1038 };
1039
1040+struct od_table_entry;
1041+
1042 struct task_struct {
1043 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
1044 void *stack;
1045@@ -1178,6 +1183,12 @@ struct task_struct {
1046 int make_it_fail;
1047 #endif
1048 struct prop_local_single dirties;
1049+
1050+ /* litmus parameters and state */
1051+ struct rt_param rt_param;
1052+
1053+ /* references to PI semaphores, etc. */
1054+ struct od_table_entry* od_table;
1055 };
1056
1057 /*
1058diff --git a/include/linux/smp.h b/include/linux/smp.h
1059index c25e66b..84df090 100644
1060--- a/include/linux/smp.h
1061+++ b/include/linux/smp.h
1062@@ -35,6 +35,12 @@ extern void smp_send_reschedule(int cpu);
1063
1064
1065 /*
1066+ * sends a 'pull timers' event to another CPU:
1067+ */
1068+extern void smp_send_pull_timers(int cpu);
1069+
1070+
1071+/*
1072 * Prepare machine for booting other CPUs.
1073 */
1074 extern void smp_prepare_cpus(unsigned int max_cpus);
1075diff --git a/include/linux/tick.h b/include/linux/tick.h
1076index f4a1395..7eae358 100644
1077--- a/include/linux/tick.h
1078+++ b/include/linux/tick.h
1079@@ -64,6 +64,9 @@ extern int tick_is_oneshot_available(void);
1080 extern struct tick_device *tick_get_device(int cpu);
1081
1082 # ifdef CONFIG_HIGH_RES_TIMERS
1083+#define LINUX_DEFAULT_TICKS 0
1084+#define LITMUS_ALIGNED_TICKS 1
1085+#define LITMUS_STAGGERED_TICKS 2
1086 extern int tick_init_highres(void);
1087 extern int tick_program_event(ktime_t expires, int force);
1088 extern void tick_setup_sched_timer(void);
1089diff --git a/include/linux/time.h b/include/linux/time.h
1090index b04136d..3e8fd9e 100644
1091--- a/include/linux/time.h
1092+++ b/include/linux/time.h
1093@@ -173,6 +173,10 @@ static inline void timespec_add_ns(struct timespec *a, u64 ns)
1094 {
1095 ns += a->tv_nsec;
1096 while(unlikely(ns >= NSEC_PER_SEC)) {
1097+ /* The following asm() prevents the compiler from
1098+ * optimising this loop into a modulo operation. */
1099+ asm("" : "+r"(ns));
1100+
1101 ns -= NSEC_PER_SEC;
1102 a->tv_sec++;
1103 }
1104diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
1105index 975c963..6ae0ff9 100644
1106--- a/include/linux/uaccess.h
1107+++ b/include/linux/uaccess.h
1108@@ -84,4 +84,20 @@ static inline unsigned long __copy_from_user_nocache(void *to,
1109 ret; \
1110 })
1111
1112+/* This is a naive attempt at a write version of the above native Linux macro.
1113+ */
1114+#define poke_kernel_address(val, addr) \
1115+ ({ \
1116+ long ret; \
1117+ mm_segment_t old_fs = get_fs(); \
1118+ \
1119+ set_fs(KERNEL_DS); \
1120+ pagefault_disable(); \
1121+ ret = __put_user(val, (__force typeof(val) __user *)(addr)); \
1122+ pagefault_enable(); \
1123+ set_fs(old_fs); \
1124+ ret; \
1125+ })
1126+
1127+
1128 #endif /* __LINUX_UACCESS_H__ */
1129diff --git a/include/litmus/edf_common.h b/include/litmus/edf_common.h
1130new file mode 100644
1131index 0000000..5060926
1132--- /dev/null
1133+++ b/include/litmus/edf_common.h
1134@@ -0,0 +1,26 @@
1135+/* EDF common data structures and utility functions shared by all EDF
1136+ * based scheduler plugins
1137+ */
1138+
1139+/* CLEANUP: Add comments and make it less messy.
1140+ *
1141+ */
1142+
1143+#ifndef __UNC_EDF_COMMON_H__
1144+#define __UNC_EDF_COMMON_H__
1145+
1146+#include <litmus/rt_domain.h>
1147+
1148+
1149+void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched,
1150+ release_jobs_t release);
1151+
1152+int edf_higher_prio(struct task_struct* first,
1153+ struct task_struct* second);
1154+int edf_ready_order(struct heap_node* a, struct heap_node* b);
1155+
1156+int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t);
1157+
1158+int edf_set_hp_task(struct pi_semaphore *sem);
1159+int edf_set_hp_cpu_task(struct pi_semaphore *sem, int cpu);
1160+#endif
1161diff --git a/include/litmus/fdso.h b/include/litmus/fdso.h
1162new file mode 100644
1163index 0000000..286e10f
1164--- /dev/null
1165+++ b/include/litmus/fdso.h
1166@@ -0,0 +1,69 @@
1167+/* fdso.h - file descriptor attached shared objects
1168+ *
1169+ * (c) 2007 B. Brandenburg, LITMUS^RT project
1170+ */
1171+
1172+#ifndef _LINUX_FDSO_H_
1173+#define _LINUX_FDSO_H_
1174+
1175+#include <linux/list.h>
1176+#include <asm/atomic.h>
1177+
1178+#include <linux/fs.h>
1179+
1180+#define MAX_OBJECT_DESCRIPTORS 32
1181+
1182+typedef enum {
1183+ MIN_OBJ_TYPE = 0,
1184+
1185+ FMLP_SEM = 0,
1186+ SRP_SEM = 1,
1187+
1188+ MAX_OBJ_TYPE = 1
1189+} obj_type_t;
1190+
1191+struct inode_obj_id {
1192+ struct list_head list;
1193+ atomic_t count;
1194+ struct inode* inode;
1195+
1196+ obj_type_t type;
1197+ void* obj;
1198+ unsigned int id;
1199+};
1200+
1201+
1202+struct od_table_entry {
1203+ unsigned int used;
1204+
1205+ struct inode_obj_id* obj;
1206+ void* extra;
1207+};
1208+
1209+struct fdso_ops {
1210+ void* (*create) (void);
1211+ void (*destroy)(void*);
1212+ int (*open) (struct od_table_entry*, void* __user);
1213+ int (*close) (struct od_table_entry*);
1214+};
1215+
1216+/* translate a userspace supplied od into the raw table entry
1217+ * returns NULL if od is invalid
1218+ */
1219+struct od_table_entry* __od_lookup(int od);
1220+
1221+/* translate a userspace supplied od into the associated object
1222+ * returns NULL if od is invalid
1223+ */
1224+static inline void* od_lookup(int od, obj_type_t type)
1225+{
1226+ struct od_table_entry* e = __od_lookup(od);
1227+ return e && e->obj->type == type ? e->obj->obj : NULL;
1228+}
1229+
1230+#define lookup_fmlp_sem(od)((struct pi_semaphore*) od_lookup(od, FMLP_SEM))
1231+#define lookup_srp_sem(od) ((struct srp_semaphore*) od_lookup(od, SRP_SEM))
1232+#define lookup_ics(od) ((struct ics*) od_lookup(od, ICS_ID))
1233+
1234+
1235+#endif
1236diff --git a/include/litmus/feather_buffer.h b/include/litmus/feather_buffer.h
1237new file mode 100644
1238index 0000000..6c18277
1239--- /dev/null
1240+++ b/include/litmus/feather_buffer.h
1241@@ -0,0 +1,94 @@
1242+#ifndef _FEATHER_BUFFER_H_
1243+#define _FEATHER_BUFFER_H_
1244+
1245+/* requires UINT_MAX and memcpy */
1246+
1247+#define SLOT_FREE 0
1248+#define SLOT_BUSY 1
1249+#define SLOT_READY 2
1250+
1251+struct ft_buffer {
1252+ unsigned int slot_count;
1253+ unsigned int slot_size;
1254+
1255+ int free_count;
1256+ unsigned int write_idx;
1257+ unsigned int read_idx;
1258+
1259+ char* slots;
1260+ void* buffer_mem;
1261+ unsigned int failed_writes;
1262+};
1263+
1264+static inline int init_ft_buffer(struct ft_buffer* buf,
1265+ unsigned int slot_count,
1266+ unsigned int slot_size,
1267+ char* slots,
1268+ void* buffer_mem)
1269+{
1270+ int i = 0;
1271+ if (!slot_count || UINT_MAX % slot_count != slot_count - 1) {
1272+ /* The slot count must divide UNIT_MAX + 1 so that when it
1273+ * wraps around the index correctly points to 0.
1274+ */
1275+ return 0;
1276+ } else {
1277+ buf->slot_count = slot_count;
1278+ buf->slot_size = slot_size;
1279+ buf->slots = slots;
1280+ buf->buffer_mem = buffer_mem;
1281+ buf->free_count = slot_count;
1282+ buf->write_idx = 0;
1283+ buf->read_idx = 0;
1284+ buf->failed_writes = 0;
1285+ for (i = 0; i < slot_count; i++)
1286+ buf->slots[i] = SLOT_FREE;
1287+ return 1;
1288+ }
1289+}
1290+
1291+static inline int ft_buffer_start_write(struct ft_buffer* buf, void **ptr)
1292+{
1293+ int free = fetch_and_dec(&buf->free_count);
1294+ unsigned int idx;
1295+ if (free <= 0) {
1296+ fetch_and_inc(&buf->free_count);
1297+ *ptr = 0;
1298+ fetch_and_inc(&buf->failed_writes);
1299+ return 0;
1300+ } else {
1301+ idx = fetch_and_inc((int*) &buf->write_idx) % buf->slot_count;
1302+ buf->slots[idx] = SLOT_BUSY;
1303+ *ptr = ((char*) buf->buffer_mem) + idx * buf->slot_size;
1304+ return 1;
1305+ }
1306+}
1307+
1308+static inline void ft_buffer_finish_write(struct ft_buffer* buf, void *ptr)
1309+{
1310+ unsigned int idx = ((char*) ptr - (char*) buf->buffer_mem) / buf->slot_size;
1311+ buf->slots[idx] = SLOT_READY;
1312+}
1313+
1314+
1315+/* exclusive reader access is assumed */
1316+static inline int ft_buffer_read(struct ft_buffer* buf, void* dest)
1317+{
1318+ unsigned int idx;
1319+ if (buf->free_count == buf->slot_count)
1320+ /* nothing available */
1321+ return 0;
1322+ idx = buf->read_idx % buf->slot_count;
1323+ if (buf->slots[idx] == SLOT_READY) {
1324+ memcpy(dest, ((char*) buf->buffer_mem) + idx * buf->slot_size,
1325+ buf->slot_size);
1326+ buf->slots[idx] = SLOT_FREE;
1327+ buf->read_idx++;
1328+ fetch_and_inc(&buf->free_count);
1329+ return 1;
1330+ } else
1331+ return 0;
1332+}
1333+
1334+
1335+#endif
1336diff --git a/include/litmus/feather_trace.h b/include/litmus/feather_trace.h
1337new file mode 100644
1338index 0000000..f8fb7ba
1339--- /dev/null
1340+++ b/include/litmus/feather_trace.h
1341@@ -0,0 +1,37 @@
1342+#ifndef _FEATHER_TRACE_H_
1343+#define _FEATHER_TRACE_H_
1344+
1345+#include <asm/feather_trace.h>
1346+
1347+int ft_enable_event(unsigned long id);
1348+int ft_disable_event(unsigned long id);
1349+int ft_is_event_enabled(unsigned long id);
1350+int ft_disable_all_events(void);
1351+
1352+#ifndef __ARCH_HAS_FEATHER_TRACE
1353+/* provide default implementation */
1354+
1355+#define feather_callback
1356+
1357+#define MAX_EVENTS 1024
1358+
1359+extern int ft_events[MAX_EVENTS];
1360+
1361+#define ft_event(id, callback) \
1362+ if (ft_events[id]) callback();
1363+
1364+#define ft_event0(id, callback) \
1365+ if (ft_events[id]) callback(id);
1366+
1367+#define ft_event1(id, callback, param) \
1368+ if (ft_events[id]) callback(id, param);
1369+
1370+#define ft_event2(id, callback, param, param2) \
1371+ if (ft_events[id]) callback(id, param, param2);
1372+
1373+#define ft_event3(id, callback, p, p2, p3) \
1374+ if (ft_events[id]) callback(id, p, p2, p3);
1375+#endif
1376+
1377+
1378+#endif
1379diff --git a/include/litmus/ftdev.h b/include/litmus/ftdev.h
1380new file mode 100644
1381index 0000000..7697b46
1382--- /dev/null
1383+++ b/include/litmus/ftdev.h
1384@@ -0,0 +1,49 @@
1385+#ifndef _LITMUS_FTDEV_H_
1386+#define _LITMUS_FTDEV_H_
1387+
1388+#include <litmus/feather_trace.h>
1389+#include <litmus/feather_buffer.h>
1390+#include <linux/mutex.h>
1391+#include <linux/cdev.h>
1392+
1393+#define MAX_FTDEV_MINORS NR_CPUS
1394+
1395+#define FTDEV_ENABLE_CMD 0
1396+#define FTDEV_DISABLE_CMD 1
1397+
1398+struct ftdev;
1399+
1400+/* return 0 if buffer can be opened, otherwise -$REASON */
1401+typedef int (*ftdev_can_open_t)(struct ftdev* dev, unsigned int buf_no);
1402+/* return 0 on success, otherwise -$REASON */
1403+typedef int (*ftdev_alloc_t)(struct ftdev* dev, unsigned int buf_no);
1404+typedef void (*ftdev_free_t)(struct ftdev* dev, unsigned int buf_no);
1405+
1406+
1407+struct ftdev_event;
1408+
1409+struct ftdev_minor {
1410+ struct ft_buffer* buf;
1411+ unsigned int readers;
1412+ struct mutex lock;
1413+ /* FIXME: filter for authorized events */
1414+ struct ftdev_event* events;
1415+};
1416+
1417+struct ftdev {
1418+ struct cdev cdev;
1419+ /* FIXME: don't waste memory, allocate dynamically */
1420+ struct ftdev_minor minor[MAX_FTDEV_MINORS];
1421+ unsigned int minor_cnt;
1422+ ftdev_alloc_t alloc;
1423+ ftdev_free_t free;
1424+ ftdev_can_open_t can_open;
1425+};
1426+
1427+struct ft_buffer* alloc_ft_buffer(unsigned int count, size_t size);
1428+void free_ft_buffer(struct ft_buffer* buf);
1429+
1430+void ftdev_init(struct ftdev* ftdev, struct module* owner);
1431+int register_ftdev(struct ftdev* ftdev, const char* name, int major);
1432+
1433+#endif
1434diff --git a/include/litmus/heap.h b/include/litmus/heap.h
1435new file mode 100644
1436index 0000000..19230f5
1437--- /dev/null
1438+++ b/include/litmus/heap.h
1439@@ -0,0 +1,74 @@
1440+/* heaps.h -- Binomial Heaps
1441+ *
1442+ * (c) 2008 Bjoern Brandenburg
1443+ */
1444+
1445+#ifndef HEAP_H
1446+#define HEAP_H
1447+
1448+#define NOT_IN_HEAP UINT_MAX
1449+
1450+struct heap_node {
1451+ struct heap_node* parent;
1452+ struct heap_node* next;
1453+ struct heap_node* child;
1454+
1455+ unsigned int degree;
1456+ void* value;
1457+ struct heap_node** ref;
1458+};
1459+
1460+struct heap {
1461+ struct heap_node* head;
1462+ /* We cache the minimum of the heap.
1463+ * This speeds up repeated peek operations.
1464+ */
1465+ struct heap_node* min;
1466+};
1467+
1468+typedef int (*heap_prio_t)(struct heap_node* a, struct heap_node* b);
1469+
1470+void heap_init(struct heap* heap);
1471+void heap_node_init(struct heap_node** ref_to_heap_node_ptr, void* value);
1472+
1473+static inline int heap_node_in_heap(struct heap_node* h)
1474+{
1475+ return h->degree != NOT_IN_HEAP;
1476+}
1477+
1478+static inline int heap_empty(struct heap* heap)
1479+{
1480+ return heap->head == NULL && heap->min == NULL;
1481+}
1482+
1483+/* insert (and reinitialize) a node into the heap */
1484+void heap_insert(heap_prio_t higher_prio,
1485+ struct heap* heap,
1486+ struct heap_node* node);
1487+
1488+/* merge addition into target */
1489+void heap_union(heap_prio_t higher_prio,
1490+ struct heap* target,
1491+ struct heap* addition);
1492+
1493+struct heap_node* heap_peek(heap_prio_t higher_prio,
1494+ struct heap* heap);
1495+
1496+struct heap_node* heap_take(heap_prio_t higher_prio,
1497+ struct heap* heap);
1498+
1499+void heap_delete(heap_prio_t higher_prio,
1500+ struct heap* heap,
1501+ struct heap_node* node);
1502+
1503+/* allocate from memcache */
1504+struct heap_node* heap_node_alloc(int gfp_flags);
1505+void heap_node_free(struct heap_node* hn);
1506+
1507+/* allocate a heap node for value and insert into the heap */
1508+int heap_add(heap_prio_t higher_prio, struct heap* heap,
1509+ void* value, int gfp_flags);
1510+
1511+void* heap_take_del(heap_prio_t higher_prio,
1512+ struct heap* heap);
1513+#endif
1514diff --git a/include/litmus/jobs.h b/include/litmus/jobs.h
1515new file mode 100644
1516index 0000000..9bd361e
1517--- /dev/null
1518+++ b/include/litmus/jobs.h
1519@@ -0,0 +1,9 @@
1520+#ifndef __LITMUS_JOBS_H__
1521+#define __LITMUS_JOBS_H__
1522+
1523+void prepare_for_next_period(struct task_struct *t);
1524+void release_at(struct task_struct *t, lt_t start);
1525+long complete_job(void);
1526+
1527+#endif
1528+
1529diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h
1530new file mode 100644
1531index 0000000..6c7a4c5
1532--- /dev/null
1533+++ b/include/litmus/litmus.h
1534@@ -0,0 +1,202 @@
1535+/*
1536+ * Constant definitions related to
1537+ * scheduling policy.
1538+ */
1539+
1540+#ifndef _LINUX_LITMUS_H_
1541+#define _LINUX_LITMUS_H_
1542+
1543+#include <linux/jiffies.h>
1544+#include <litmus/sched_trace.h>
1545+
1546+extern atomic_t release_master_cpu;
1547+
1548+extern atomic_t __log_seq_no;
1549+
1550+#define TRACE(fmt, args...) \
1551+ sched_trace_log_message("%d P%d: " fmt, atomic_add_return(1, &__log_seq_no), \
1552+ raw_smp_processor_id(), ## args)
1553+
1554+#define TRACE_TASK(t, fmt, args...) \
1555+ TRACE("(%s/%d) " fmt, (t)->comm, (t)->pid, ##args)
1556+
1557+#define TRACE_CUR(fmt, args...) \
1558+ TRACE_TASK(current, fmt, ## args)
1559+
1560+#define TRACE_BUG_ON(cond) \
1561+ do { if (cond) TRACE("BUG_ON(%s) at %s:%d " \
1562+ "called from %p current=%s/%d state=%d " \
1563+ "flags=%x partition=%d cpu=%d rtflags=%d"\
1564+ " job=%u knp=%d timeslice=%u\n", \
1565+ #cond, __FILE__, __LINE__, __builtin_return_address(0), current->comm, \
1566+ current->pid, current->state, current->flags, \
1567+ get_partition(current), smp_processor_id(), get_rt_flags(current), \
1568+ current->rt_param.job_params.job_no, current->rt_param.kernel_np, \
1569+ current->time_slice\
1570+ ); } while(0);
1571+
1572+
1573+/* in_list - is a given list_head queued on some list?
1574+ */
1575+static inline int in_list(struct list_head* list)
1576+{
1577+ return !( /* case 1: deleted */
1578+ (list->next == LIST_POISON1 &&
1579+ list->prev == LIST_POISON2)
1580+ ||
1581+ /* case 2: initialized */
1582+ (list->next == list &&
1583+ list->prev == list)
1584+ );
1585+}
1586+
1587+#define NO_CPU 0xffffffff
1588+
1589+#define RT_PREEMPTIVE 0x2050 /* = NP */
1590+#define RT_NON_PREEMPTIVE 0x4e50 /* = P */
1591+#define RT_EXIT_NP_REQUESTED 0x5251 /* = RQ */
1592+
1593+
1594+/* kill naughty tasks
1595+ */
1596+void scheduler_signal(struct task_struct *t, unsigned int signal);
1597+void send_scheduler_signals(void);
1598+void np_mem_kill(struct task_struct *t);
1599+
1600+void litmus_fork(struct task_struct *tsk);
1601+void litmus_exec(void);
1602+/* clean up real-time state of a task */
1603+void exit_litmus(struct task_struct *dead_tsk);
1604+
1605+long litmus_admit_task(struct task_struct *tsk);
1606+void litmus_exit_task(struct task_struct *tsk);
1607+
1608+#define is_realtime(t) ((t)->policy == SCHED_LITMUS)
1609+#define rt_transition_pending(t) \
1610+ ((t)->rt_param.transition_pending)
1611+
1612+#define tsk_rt(t) (&(t)->rt_param)
1613+
1614+/* Realtime utility macros */
1615+#define get_rt_flags(t) (tsk_rt(t)->flags)
1616+#define set_rt_flags(t,f) (tsk_rt(t)->flags=(f))
1617+#define get_exec_cost(t) (tsk_rt(t)->task_params.exec_cost)
1618+#define get_exec_time(t) (tsk_rt(t)->job_params.exec_time)
1619+#define get_rt_period(t) (tsk_rt(t)->task_params.period)
1620+#define get_rt_phase(t) (tsk_rt(t)->task_params.phase)
1621+#define get_partition(t) (tsk_rt(t)->task_params.cpu)
1622+#define get_deadline(t) (tsk_rt(t)->job_params.deadline)
1623+#define get_release(t) (tsk_rt(t)->job_params.release)
1624+#define get_class(t) (tsk_rt(t)->task_params.cls)
1625+
1626+inline static int budget_exhausted(struct task_struct* t)
1627+{
1628+ return get_exec_time(t) >= get_exec_cost(t);
1629+}
1630+
1631+
1632+#define is_hrt(t) \
1633+ (tsk_rt(t)->task_params.class == RT_CLASS_HARD)
1634+#define is_srt(t) \
1635+ (tsk_rt(t)->task_params.class == RT_CLASS_SOFT)
1636+#define is_be(t) \
1637+ (tsk_rt(t)->task_params.class == RT_CLASS_BEST_EFFORT)
1638+
1639+/* Our notion of time within LITMUS: kernel monotonic time. */
1640+static inline lt_t litmus_clock(void)
1641+{
1642+ return ktime_to_ns(ktime_get());
1643+}
1644+
1645+/* A macro to convert from nanoseconds to ktime_t. */
1646+#define ns_to_ktime(t) ktime_add_ns(ktime_set(0, 0), t)
1647+
1648+#define get_domain(t) (tsk_rt(t)->domain)
1649+
1650+/* Honor the flag in the preempt_count variable that is set
1651+ * when scheduling is in progress.
1652+ */
1653+#define is_running(t) \
1654+ ((t)->state == TASK_RUNNING || \
1655+ task_thread_info(t)->preempt_count & PREEMPT_ACTIVE)
1656+
1657+#define is_blocked(t) \
1658+ (!is_running(t))
1659+#define is_released(t, now) \
1660+ (lt_before_eq(get_release(t), now))
1661+#define is_tardy(t, now) \
1662+ (lt_before_eq(tsk_rt(t)->job_params.deadline, now))
1663+
1664+/* real-time comparison macros */
1665+#define earlier_deadline(a, b) (lt_before(\
1666+ (a)->rt_param.job_params.deadline,\
1667+ (b)->rt_param.job_params.deadline))
1668+#define earlier_release(a, b) (lt_before(\
1669+ (a)->rt_param.job_params.release,\
1670+ (b)->rt_param.job_params.release))
1671+
1672+#define make_np(t) do {t->rt_param.kernel_np++;} while(0);
1673+#define take_np(t) do {t->rt_param.kernel_np--;} while(0);
1674+
1675+#ifdef CONFIG_SRP
1676+void srp_ceiling_block(void);
1677+#else
1678+#define srp_ceiling_block() /* nothing */
1679+#endif
1680+
1681+#define heap2task(hn) ((struct task_struct*) hn->value)
1682+
1683+
1684+#ifdef CONFIG_NP_SECTION
1685+/* returns 1 if task t has registered np flag and set it to RT_NON_PREEMPTIVE
1686+ */
1687+int is_np(struct task_struct *t);
1688+
1689+/* request that the task should call sys_exit_np()
1690+ */
1691+void request_exit_np(struct task_struct *t);
1692+
1693+#else
1694+
1695+static inline int is_np(struct task_struct *t)
1696+{
1697+ return tsk_rt(t)->kernel_np;
1698+}
1699+
1700+#define request_exit_np(t)
1701+
1702+#endif
1703+
1704+static inline int is_present(struct task_struct* t)
1705+{
1706+ return t && tsk_rt(t)->present;
1707+}
1708+
1709+
1710+/* make the unit explicit */
1711+typedef unsigned long quanta_t;
1712+
1713+enum round {
1714+ FLOOR,
1715+ CEIL
1716+};
1717+
1718+
1719+/* Tick period is used to convert ns-specified execution
1720+ * costs and periods into tick-based equivalents.
1721+ */
1722+extern ktime_t tick_period;
1723+
1724+static inline quanta_t time2quanta(lt_t time, enum round round)
1725+{
1726+ s64 quantum_length = ktime_to_ns(tick_period);
1727+
1728+ if (do_div(time, quantum_length) && round == CEIL)
1729+ time++;
1730+ return (quanta_t) time;
1731+}
1732+
1733+/* By how much is cpu staggered behind CPU 0? */
1734+u64 cpu_stagger_offset(int cpu);
1735+
1736+#endif
1737diff --git a/include/litmus/norqlock.h b/include/litmus/norqlock.h
1738new file mode 100644
1739index 0000000..e4c1d06
1740--- /dev/null
1741+++ b/include/litmus/norqlock.h
1742@@ -0,0 +1,26 @@
1743+#ifndef NORQLOCK_H
1744+#define NORQLOCK_H
1745+
1746+typedef void (*work_t)(unsigned long arg);
1747+
1748+struct no_rqlock_work {
1749+ int active;
1750+ work_t work;
1751+ unsigned long arg;
1752+ struct no_rqlock_work* next;
1753+};
1754+
1755+void init_no_rqlock_work(struct no_rqlock_work* w, work_t work,
1756+ unsigned long arg);
1757+
1758+void __do_without_rqlock(struct no_rqlock_work *work);
1759+
1760+static inline void do_without_rqlock(struct no_rqlock_work *work)
1761+{
1762+ if (!test_and_set_bit(0, (void*)&work->active))
1763+ __do_without_rqlock(work);
1764+}
1765+
1766+void tick_no_rqlock(void);
1767+
1768+#endif
1769diff --git a/include/litmus/rt_domain.h b/include/litmus/rt_domain.h
1770new file mode 100644
1771index 0000000..ea9de02
1772--- /dev/null
1773+++ b/include/litmus/rt_domain.h
1774@@ -0,0 +1,164 @@
1775+/* CLEANUP: Add comments and make it less messy.
1776+ *
1777+ */
1778+
1779+#ifndef __UNC_RT_DOMAIN_H__
1780+#define __UNC_RT_DOMAIN_H__
1781+
1782+#include <litmus/norqlock.h>
1783+#include <litmus/heap.h>
1784+
1785+#define RELEASE_QUEUE_SLOTS 127 /* prime */
1786+
1787+struct _rt_domain;
1788+
1789+typedef int (*check_resched_needed_t)(struct _rt_domain *rt);
1790+typedef void (*release_jobs_t)(struct _rt_domain *rt, struct heap* tasks);
1791+
1792+struct release_queue {
1793+ /* each slot maintains a list of release heaps sorted
1794+ * by release time */
1795+ struct list_head slot[RELEASE_QUEUE_SLOTS];
1796+};
1797+
1798+typedef struct _rt_domain {
1799+ struct no_rqlock_work arm_timer;
1800+
1801+ /* runnable rt tasks are in here */
1802+ spinlock_t ready_lock;
1803+ struct heap ready_queue;
1804+
1805+ /* real-time tasks waiting for release are in here */
1806+ spinlock_t release_lock;
1807+ struct release_queue release_queue;
1808+ int release_master;
1809+
1810+ /* for moving tasks to the release queue */
1811+ spinlock_t tobe_lock;
1812+ struct list_head tobe_released;
1813+
1814+ /* how do we check if we need to kick another CPU? */
1815+ check_resched_needed_t check_resched;
1816+
1817+ /* how do we release jobs? */
1818+ release_jobs_t release_jobs;
1819+
1820+ /* how are tasks ordered in the ready queue? */
1821+ heap_prio_t order;
1822+} rt_domain_t;
1823+
1824+struct release_heap {
1825+ /* list_head for per-time-slot list */
1826+ struct list_head list;
1827+ lt_t release_time;
1828+ /* all tasks to be released at release_time */
1829+ struct heap heap;
1830+ /* used to trigger the release */
1831+ struct hrtimer timer;
1832+ /* used to delegate releases */
1833+ struct hrtimer_start_on_info info;
1834+ /* required for the timer callback */
1835+ rt_domain_t* dom;
1836+};
1837+
1838+
1839+static inline struct task_struct* __next_ready(rt_domain_t* rt)
1840+{
1841+ struct heap_node *hn = heap_peek(rt->order, &rt->ready_queue);
1842+ if (hn)
1843+ return heap2task(hn);
1844+ else
1845+ return NULL;
1846+}
1847+
1848+void rt_domain_init(rt_domain_t *rt, heap_prio_t order,
1849+ check_resched_needed_t check,
1850+ release_jobs_t relase);
1851+
1852+void __add_ready(rt_domain_t* rt, struct task_struct *new);
1853+void __merge_ready(rt_domain_t* rt, struct heap *tasks);
1854+void __add_release(rt_domain_t* rt, struct task_struct *task);
1855+
1856+static inline struct task_struct* __take_ready(rt_domain_t* rt)
1857+{
1858+ struct heap_node* hn = heap_take(rt->order, &rt->ready_queue);
1859+ if (hn)
1860+ return heap2task(hn);
1861+ else
1862+ return NULL;
1863+}
1864+
1865+static inline struct task_struct* __peek_ready(rt_domain_t* rt)
1866+{
1867+ struct heap_node* hn = heap_peek(rt->order, &rt->ready_queue);
1868+ if (hn)
1869+ return heap2task(hn);
1870+ else
1871+ return NULL;
1872+}
1873+
1874+static inline int is_queued(struct task_struct *t)
1875+{
1876+ return heap_node_in_heap(tsk_rt(t)->heap_node);
1877+}
1878+
1879+static inline void remove(rt_domain_t* rt, struct task_struct *t)
1880+{
1881+ heap_delete(rt->order, &rt->ready_queue, tsk_rt(t)->heap_node);
1882+}
1883+
1884+static inline void add_ready(rt_domain_t* rt, struct task_struct *new)
1885+{
1886+ unsigned long flags;
1887+ /* first we need the write lock for rt_ready_queue */
1888+ spin_lock_irqsave(&rt->ready_lock, flags);
1889+ __add_ready(rt, new);
1890+ spin_unlock_irqrestore(&rt->ready_lock, flags);
1891+}
1892+
1893+static inline void merge_ready(rt_domain_t* rt, struct heap* tasks)
1894+{
1895+ unsigned long flags;
1896+ spin_lock_irqsave(&rt->ready_lock, flags);
1897+ __merge_ready(rt, tasks);
1898+ spin_unlock_irqrestore(&rt->ready_lock, flags);
1899+}
1900+
1901+static inline struct task_struct* take_ready(rt_domain_t* rt)
1902+{
1903+ unsigned long flags;
1904+ struct task_struct* ret;
1905+ /* first we need the write lock for rt_ready_queue */
1906+ spin_lock_irqsave(&rt->ready_lock, flags);
1907+ ret = __take_ready(rt);
1908+ spin_unlock_irqrestore(&rt->ready_lock, flags);
1909+ return ret;
1910+}
1911+
1912+
1913+static inline void add_release(rt_domain_t* rt, struct task_struct *task)
1914+{
1915+ unsigned long flags;
1916+ /* first we need the write lock for rt_ready_queue */
1917+ spin_lock_irqsave(&rt->tobe_lock, flags);
1918+ __add_release(rt, task);
1919+ spin_unlock_irqrestore(&rt->tobe_lock, flags);
1920+}
1921+
1922+static inline int __jobs_pending(rt_domain_t* rt)
1923+{
1924+ return !heap_empty(&rt->ready_queue);
1925+}
1926+
1927+static inline int jobs_pending(rt_domain_t* rt)
1928+{
1929+ unsigned long flags;
1930+ int ret;
1931+ /* first we need the write lock for rt_ready_queue */
1932+ spin_lock_irqsave(&rt->ready_lock, flags);
1933+ ret = !heap_empty(&rt->ready_queue);
1934+ spin_unlock_irqrestore(&rt->ready_lock, flags);
1935+ return ret;
1936+}
1937+
1938+#endif
1939diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
1940new file mode 100644
1941index 0000000..c599f84
1942--- /dev/null
1943+++ b/include/litmus/rt_param.h
1944@@ -0,0 +1,175 @@
1945+/*
1946+ * Definition of the scheduler plugin interface.
1947+ *
1948+ */
1949+#ifndef _LINUX_RT_PARAM_H_
1950+#define _LINUX_RT_PARAM_H_
1951+
1952+/* Litmus time type. */
1953+typedef unsigned long long lt_t;
1954+
1955+static inline int lt_after(lt_t a, lt_t b)
1956+{
1957+ return ((long long) b) - ((long long) a) < 0;
1958+}
1959+#define lt_before(a, b) lt_after(b, a)
1960+
1961+static inline int lt_after_eq(lt_t a, lt_t b)
1962+{
1963+ return ((long long) a) - ((long long) b) >= 0;
1964+}
1965+#define lt_before_eq(a, b) lt_after_eq(b, a)
1966+
1967+/* different types of clients */
1968+typedef enum {
1969+ RT_CLASS_HARD,
1970+ RT_CLASS_SOFT,
1971+ RT_CLASS_BEST_EFFORT
1972+} task_class_t;
1973+
1974+struct rt_task {
1975+ lt_t exec_cost;
1976+ lt_t period;
1977+ lt_t phase;
1978+ unsigned int cpu;
1979+ task_class_t cls;
1980+};
1981+
1982+/* don't export internal data structures to user space (liblitmus) */
1983+#ifdef __KERNEL__
1984+
1985+struct _rt_domain;
1986+struct heap_node;
1987+struct release_heap;
1988+
1989+struct rt_job {
1990+ /* Time instant the the job was or will be released. */
1991+ lt_t release;
1992+ /* What is the current deadline? */
1993+ lt_t deadline;
1994+
1995+ /* How much service has this job received so far? */
1996+ lt_t exec_time;
1997+
1998+ /* Which job is this. This is used to let user space
1999+ * specify which job to wait for, which is important if jobs
2000+ * overrun. If we just call sys_sleep_next_period() then we
2001+ * will unintentionally miss jobs after an overrun.
2002+ *
2003+ * Increase this sequence number when a job is released.
2004+ */
2005+ unsigned int job_no;
2006+};
2007+
2008+
2009+struct pfair_param;
2010+
2011+/* RT task parameters for scheduling extensions
2012+ * These parameters are inherited during clone and therefore must
2013+ * be explicitly set up before the task set is launched.
2014+ */
2015+struct rt_param {
2016+ /* is the task sleeping? */
2017+ unsigned int flags:8;
2018+
2019+ /* do we need to check for srp blocking? */
2020+ unsigned int srp_non_recurse:1;
2021+
2022+ /* is the task present? (true if it can be scheduled) */
2023+ unsigned int present:1;
2024+
2025+ /* user controlled parameters */
2026+ struct rt_task task_params;
2027+
2028+ /* timing parameters */
2029+ struct rt_job job_params;
2030+
2031+ /* task representing the current "inherited" task
2032+ * priority, assigned by inherit_priority and
2033+ * return priority in the scheduler plugins.
2034+ * could point to self if PI does not result in
2035+ * an increased task priority.
2036+ */
2037+ struct task_struct* inh_task;
2038+
2039+ /* Don't just dereference this pointer in kernel space!
2040+ * It might very well point to junk or nothing at all.
2041+ * NULL indicates that the task has not requested any non-preemptable
2042+ * section support.
2043+ * Not inherited upon fork.
2044+ */
2045+ short* np_flag;
2046+
2047+ /* re-use unused counter in plugins that don't need it */
2048+ union {
2049+ /* For the FMLP under PSN-EDF, it is required to make the task
2050+ * non-preemptive from kernel space. In order not to interfere with
2051+ * user space, this counter indicates the kernel space np setting.
2052+ * kernel_np > 0 => task is non-preemptive
2053+ */
2054+ unsigned int kernel_np;
2055+
2056+ /* Used by GQ-EDF */
2057+ unsigned int last_cpu;
2058+ };
2059+
2060+ /* This field can be used by plugins to store where the task
2061+ * is currently scheduled. It is the responsibility of the
2062+ * plugin to avoid race conditions.
2063+ *
2064+ * This used by GSN-EDF and PFAIR.
2065+ */
2066+ volatile int scheduled_on;
2067+
2068+ /* Is the stack of the task currently in use? This is updated by
2069+ * the LITMUS core.
2070+ *
2071+ * Be careful to avoid deadlocks!
2072+ */
2073+ volatile int stack_in_use;
2074+
2075+ /* This field can be used by plugins to store where the task
2076+ * is currently linked. It is the responsibility of the plugin
2077+ * to avoid race conditions.
2078+ *
2079+ * Used by GSN-EDF.
2080+ */
2081+ volatile int linked_on;
2082+
2083+ /* PFAIR/PD^2 state. Allocated on demand. */
2084+ struct pfair_param* pfair;
2085+
2086+ /* Fields saved before BE->RT transition.
2087+ */
2088+ int old_policy;
2089+ int old_prio;
2090+
2091+ /* ready queue for this task */
2092+ struct _rt_domain* domain;
2093+
2094+ /* heap element for this task
2095+ *
2096+ * Warning: Don't statically allocate this node. The heap
2097+ * implementation swaps these between tasks, thus after
2098+ * dequeuing from a heap you may end up with a different node
2099+ * then the one you had when enqueuing the task. For the same
2100+ * reason, don't obtain and store references to this node
2101+ * other than this pointer (which is updated by the heap
2102+ * implementation).
2103+ */
2104+ struct heap_node* heap_node;
2105+ struct release_heap* rel_heap;
2106+
2107+ /* Used by rt_domain to queue task in release list.
2108+ */
2109+ struct list_head list;
2110+};
2111+
2112+/* Possible RT flags */
2113+#define RT_F_RUNNING 0x00000000
2114+#define RT_F_SLEEP 0x00000001
2115+#define RT_F_EXIT_SEM 0x00000008
2116+
2117+#endif
2118+
2119+#endif
2120diff --git a/include/litmus/sched_plugin.h b/include/litmus/sched_plugin.h
2121new file mode 100644
2122index 0000000..94952f6
2123--- /dev/null
2124+++ b/include/litmus/sched_plugin.h
2125@@ -0,0 +1,159 @@
2126+/*
2127+ * Definition of the scheduler plugin interface.
2128+ *
2129+ */
2130+#ifndef _LINUX_SCHED_PLUGIN_H_
2131+#define _LINUX_SCHED_PLUGIN_H_
2132+
2133+#include <linux/sched.h>
2134+
2135+/* struct for semaphore with priority inheritance */
2136+struct pi_semaphore {
2137+ atomic_t count;
2138+ int sleepers;
2139+ wait_queue_head_t wait;
2140+ union {
2141+ /* highest-prio holder/waiter */
2142+ struct task_struct *task;
2143+ struct task_struct* cpu_task[NR_CPUS];
2144+ } hp;
2145+ /* current lock holder */
2146+ struct task_struct *holder;
2147+};
2148+
2149+/************************ setup/tear down ********************/
2150+
2151+typedef long (*activate_plugin_t) (void);
2152+typedef long (*deactivate_plugin_t) (void);
2153+
2154+
2155+
2156+/********************* scheduler invocation ******************/
2157+
2158+/* Plugin-specific realtime tick handler */
2159+typedef void (*scheduler_tick_t) (struct task_struct *cur);
2160+/* Novell make sched decision function */
2161+typedef struct task_struct* (*schedule_t)(struct task_struct * prev);
2162+/* Clean up after the task switch has occured.
2163+ * This function is called after every (even non-rt) task switch.
2164+ */
2165+typedef void (*finish_switch_t)(struct task_struct *prev);
2166+
2167+
2168+/********************* task state changes ********************/
2169+
2170+/* Called to setup a new real-time task.
2171+ * Release the first job, enqueue, etc.
2172+ * Task may already be running.
2173+ */
2174+typedef void (*task_new_t) (struct task_struct *task,
2175+ int on_rq,
2176+ int running);
2177+
2178+/* Called to re-introduce a task after blocking.
2179+ * Can potentially be called multiple times.
2180+ */
2181+typedef void (*task_wake_up_t) (struct task_struct *task);
2182+/* called to notify the plugin of a blocking real-time task
2183+ * it will only be called for real-time tasks and before schedule is called */
2184+typedef void (*task_block_t) (struct task_struct *task);
2185+/* Called when a real-time task exits or changes to a different scheduling
2186+ * class.
2187+ * Free any allocated resources
2188+ */
2189+typedef void (*task_exit_t) (struct task_struct *);
2190+
2191+/* Called when the new_owner is released from the wait queue
2192+ * it should now inherit the priority from sem, _before_ it gets readded
2193+ * to any queue
2194+ */
2195+typedef long (*inherit_priority_t) (struct pi_semaphore *sem,
2196+ struct task_struct *new_owner);
2197+
2198+/* Called when the current task releases a semahpore where it might have
2199+ * inherited a piority from
2200+ */
2201+typedef long (*return_priority_t) (struct pi_semaphore *sem);
2202+
2203+/* Called when a task tries to acquire a semaphore and fails. Check if its
2204+ * priority is higher than that of the current holder.
2205+ */
2206+typedef long (*pi_block_t) (struct pi_semaphore *sem, struct task_struct *t);
2207+
2208+
2209+
2210+
2211+/********************* sys call backends ********************/
2212+/* This function causes the caller to sleep until the next release */
2213+typedef long (*complete_job_t) (void);
2214+
2215+typedef long (*admit_task_t)(struct task_struct* tsk);
2216+
2217+typedef void (*release_at_t)(struct task_struct *t, lt_t start);
2218+
2219+struct sched_plugin {
2220+ struct list_head list;
2221+ /* basic info */
2222+ char *plugin_name;
2223+
2224+ /* setup */
2225+ activate_plugin_t activate_plugin;
2226+ deactivate_plugin_t deactivate_plugin;
2227+
2228+#ifdef CONFIG_SRP
2229+ unsigned int srp_active;
2230+#endif
2231+
2232+ /* scheduler invocation */
2233+ scheduler_tick_t tick;
2234+ schedule_t schedule;
2235+ finish_switch_t finish_switch;
2236+
2237+ /* syscall backend */
2238+ complete_job_t complete_job;
2239+ release_at_t release_at;
2240+
2241+ /* task state changes */
2242+ admit_task_t admit_task;
2243+
2244+ task_new_t task_new;
2245+ task_wake_up_t task_wake_up;
2246+ task_block_t task_block;
2247+ task_exit_t task_exit;
2248+
2249+#ifdef CONFIG_FMLP
2250+ /* priority inheritance */
2251+ unsigned int fmlp_active;
2252+ inherit_priority_t inherit_priority;
2253+ return_priority_t return_priority;
2254+ pi_block_t pi_block;
2255+#endif
2256+} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
2257+
2258+
2259+extern struct sched_plugin *litmus;
2260+
2261+int register_sched_plugin(struct sched_plugin* plugin);
2262+struct sched_plugin* find_sched_plugin(const char* name);
2263+int print_sched_plugins(char* buf, int max);
2264+
2265+static inline int srp_active(void)
2266+{
2267+#ifdef CONFIG_SRP
2268+ return litmus->srp_active;
2269+#else
2270+ return 0;
2271+#endif
2272+}
2273+static inline int fmlp_active(void)
2274+{
2275+#ifdef CONFIG_FMLP
2276+ return litmus->fmlp_active;
2277+#else
2278+ return 0;
2279+#endif
2280+}
2281+
2282+extern struct sched_plugin linux_sched_plugin;
2283+
2284+#endif
2285diff --git a/include/litmus/sched_trace.h b/include/litmus/sched_trace.h
2286new file mode 100644
2287index 0000000..afd0391
2288--- /dev/null
2289+++ b/include/litmus/sched_trace.h
2290@@ -0,0 +1,191 @@
2291+/* sched_trace.h -- record scheduler events to a byte stream for offline analysis.
2292+ */
2293+#ifndef _LINUX_SCHED_TRACE_H_
2294+#define _LINUX_SCHED_TRACE_H_
2295+
2296+/* all times in nanoseconds */
2297+
2298+struct st_trace_header {
2299+ u8 type; /* Of what type is this record? */
2300+ u8 cpu; /* On which CPU was it recorded? */
2301+ u16 pid; /* PID of the task. */
2302+ u32 job; /* The job sequence number. */
2303+};
2304+
2305+#define ST_NAME_LEN 16
2306+struct st_name_data {
2307+ char cmd[ST_NAME_LEN];/* The name of the executable of this process. */
2308+};
2309+
2310+struct st_param_data { /* regular params */
2311+ u32 wcet;
2312+ u32 period;
2313+ u32 phase;
2314+ u8 partition;
2315+ u8 __unused[3];
2316+};
2317+
2318+struct st_release_data { /* A job is was/is going to be released. */
2319+ u64 release; /* What's the release time? */
2320+ u64 deadline; /* By when must it finish? */
2321+};
2322+
2323+struct st_assigned_data { /* A job was asigned to a CPU. */
2324+ u64 when;
2325+ u8 target; /* Where should it execute? */
2326+ u8 __unused[3];
2327+};
2328+
2329+struct st_switch_to_data { /* A process was switched to on a given CPU. */
2330+ u64 when; /* When did this occur? */
2331+ u32 exec_time; /* Time the current job has executed. */
2332+
2333+};
2334+
2335+struct st_switch_away_data { /* A process was switched away from on a given CPU. */
2336+ u64 when;
2337+ u64 exec_time;
2338+};
2339+
2340+struct st_completion_data { /* A job completed. */
2341+ u64 when;
2342+ u8 forced:1; /* Set to 1 if job overran and kernel advanced to the
2343+ * next task automatically; set to 0 otherwise.
2344+ */
2345+ u8 __uflags:7;
2346+ u8 __unused[3];
2347+};
2348+
2349+struct st_block_data { /* A task blocks. */
2350+ u64 when;
2351+ u64 __unused;
2352+};
2353+
2354+struct st_resume_data { /* A task resumes. */
2355+ u64 when;
2356+ u64 __unused;
2357+};
2358+
2359+struct st_sys_release_data {
2360+ u64 when;
2361+ u64 release;
2362+};
2363+
2364+#define DATA(x) struct st_ ## x ## _data x;
2365+
2366+typedef enum {
2367+ ST_NAME = 1, /* Start at one, so that we can spot
2368+ * uninitialized records. */
2369+ ST_PARAM,
2370+ ST_RELEASE,
2371+ ST_ASSIGNED,
2372+ ST_SWITCH_TO,
2373+ ST_SWITCH_AWAY,
2374+ ST_COMPLETION,
2375+ ST_BLOCK,
2376+ ST_RESUME,
2377+ ST_SYS_RELEASE,
2378+} st_event_record_type_t;
2379+
2380+struct st_event_record {
2381+ struct st_trace_header hdr;
2382+ union {
2383+ u64 raw[2];
2384+
2385+ DATA(name);
2386+ DATA(param);
2387+ DATA(release);
2388+ DATA(assigned);
2389+ DATA(switch_to);
2390+ DATA(switch_away);
2391+ DATA(completion);
2392+ DATA(block);
2393+ DATA(resume);
2394+ DATA(sys_release);
2395+
2396+ } data;
2397+};
2398+
2399+#undef DATA
2400+
2401+#ifdef __KERNEL__
2402+
2403+#include <linux/sched.h>
2404+#include <litmus/feather_trace.h>
2405+
2406+#ifdef CONFIG_SCHED_TASK_TRACE
2407+
2408+#define SCHED_TRACE(id, callback, task) \
2409+ ft_event1(id, callback, task)
2410+#define SCHED_TRACE2(id, callback, task, xtra) \
2411+ ft_event2(id, callback, task, xtra)
2412+
2413+/* provide prototypes; needed on sparc64 */
2414+#ifndef NO_TASK_TRACE_DECLS
2415+feather_callback void do_sched_trace_task_name(unsigned long id,
2416+ struct task_struct* task);
2417+feather_callback void do_sched_trace_task_param(unsigned long id,
2418+ struct task_struct* task);
2419+feather_callback void do_sched_trace_task_release(unsigned long id,
2420+ struct task_struct* task);
2421+feather_callback void do_sched_trace_task_switch_to(unsigned long id,
2422+ struct task_struct* task);
2423+feather_callback void do_sched_trace_task_switch_away(unsigned long id,
2424+ struct task_struct* task);
2425+feather_callback void do_sched_trace_task_completion(unsigned long id,
2426+ struct task_struct* task,
2427+ unsigned long forced);
2428+feather_callback void do_sched_trace_task_block(unsigned long id,
2429+ struct task_struct* task);
2430+feather_callback void do_sched_trace_task_resume(unsigned long id,
2431+ struct task_struct* task);
2432+feather_callback void do_sched_trace_sys_release(unsigned long id,
2433+ lt_t* start);
2434+#endif
2435+
2436+#else
2437+
2438+#define SCHED_TRACE(id, callback, task) /* no tracing */
2439+#define SCHED_TRACE2(id, callback, task, xtra) /* no tracing */
2440+
2441+#endif
2442+
2443+
2444+#define SCHED_TRACE_BASE_ID 500
2445+
2446+
2447+#define sched_trace_task_name(t) \
2448+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 1, do_sched_trace_task_name, t)
2449+#define sched_trace_task_param(t) \
2450+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 2, do_sched_trace_task_param, t)
2451+#define sched_trace_task_release(t) \
2452+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 3, do_sched_trace_task_release, t)
2453+#define sched_trace_task_switch_to(t) \
2454+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 4, do_sched_trace_task_switch_to, t)
2455+#define sched_trace_task_switch_away(t) \
2456+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 5, do_sched_trace_task_switch_away, t)
2457+#define sched_trace_task_completion(t, forced) \
2458+ SCHED_TRACE2(SCHED_TRACE_BASE_ID + 6, do_sched_trace_task_completion, t, \
2459+ forced)
2460+#define sched_trace_task_block(t) \
2461+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 7, do_sched_trace_task_block, t)
2462+#define sched_trace_task_resume(t) \
2463+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 8, do_sched_trace_task_resume, t)
2464+
2465+#define sched_trace_sys_release(when) \
2466+ SCHED_TRACE(SCHED_TRACE_BASE_ID + 9, do_sched_trace_sys_release, when)
2467+
2468+#define sched_trace_quantum_boundary() /* NOT IMPLEMENTED */
2469+
2470+#ifdef CONFIG_SCHED_DEBUG_TRACE
2471+void sched_trace_log_message(const char* fmt, ...);
2472+void dump_trace_buffer(int max);
2473+#else
2474+
2475+#define sched_trace_log_message(fmt, ...)
2476+
2477+#endif
2478+
2479+#endif /* __KERNEL__ */
2480+
2481+#endif
2482diff --git a/include/litmus/trace.h b/include/litmus/trace.h
2483new file mode 100644
2484index 0000000..e8e0c7b
2485--- /dev/null
2486+++ b/include/litmus/trace.h
2487@@ -0,0 +1,113 @@
2488+#ifndef _SYS_TRACE_H_
2489+#define _SYS_TRACE_H_
2490+
2491+#ifdef CONFIG_SCHED_OVERHEAD_TRACE
2492+
2493+#include <litmus/feather_trace.h>
2494+#include <litmus/feather_buffer.h>
2495+
2496+
2497+/*********************** TIMESTAMPS ************************/
2498+
2499+enum task_type_marker {
2500+ TSK_BE,
2501+ TSK_RT,
2502+ TSK_UNKNOWN
2503+};
2504+
2505+struct timestamp {
2506+ uint64_t timestamp;
2507+ uint32_t seq_no;
2508+ uint8_t cpu;
2509+ uint8_t event;
2510+ uint8_t task_type;
2511+};
2512+
2513+/* tracing callbacks */
2514+feather_callback void save_timestamp(unsigned long event);
2515+feather_callback void save_timestamp_def(unsigned long event, unsigned long type);
2516+feather_callback void save_timestamp_task(unsigned long event, unsigned long t_ptr);
2517+feather_callback void save_timestamp_cpu(unsigned long event, unsigned long cpu);
2518+
2519+
2520+#define TIMESTAMP(id) ft_event0(id, save_timestamp)
2521+
2522+#define DTIMESTAMP(id, def) ft_event1(id, save_timestamp_def, def)
2523+
2524+#define TTIMESTAMP(id, task) \
2525+ ft_event1(id, save_timestamp_task, (unsigned long) task)
2526+
2527+#define CTIMESTAMP(id, cpu) \
2528+ ft_event1(id, save_timestamp_cpu, cpu)
2529+
2530+#else /* !CONFIG_SCHED_OVERHEAD_TRACE */
2531+
2532+#define TIMESTAMP(id) /* no tracing */
2533+
2534+#define DTIMESTAMP(id, def) /* no tracing */
2535+
2536+#define TTIMESTAMP(id, task) /* no tracing */
2537+
2538+#define CTIMESTAMP(id, cpu) /* no tracing */
2539+
2540+#endif
2541+
2542+
2543+/* Convention for timestamps
2544+ * =========================
2545+ *
2546+ * In order to process the trace files with a common tool, we use the following
2547+ * convention to measure execution times: The end time id of a code segment is
2548+ * always the next number after the start time event id.
2549+ */
2550+
2551+#define TS_SCHED_START DTIMESTAMP(100, TSK_UNKNOWN) /* we only
2552+ * care
2553+ * about
2554+ * next */
2555+#define TS_SCHED_END(t) TTIMESTAMP(101, t)
2556+#define TS_SCHED2_START(t) TTIMESTAMP(102, t)
2557+#define TS_SCHED2_END(t) TTIMESTAMP(103, t)
2558+
2559+#define TS_CXS_START(t) TTIMESTAMP(104, t)
2560+#define TS_CXS_END(t) TTIMESTAMP(105, t)
2561+
2562+#define TS_RELEASE_START DTIMESTAMP(106, TSK_RT)
2563+#define TS_RELEASE_END DTIMESTAMP(107, TSK_RT)
2564+
2565+#define TS_TICK_START(t) TTIMESTAMP(110, t)
2566+#define TS_TICK_END(t) TTIMESTAMP(111, t)
2567+
2568+
2569+#define TS_PLUGIN_SCHED_START /* TIMESTAMP(120) */ /* currently unused */
2570+#define TS_PLUGIN_SCHED_END /* TIMESTAMP(121) */
2571+
2572+#define TS_PLUGIN_TICK_START /* TIMESTAMP(130) */
2573+#define TS_PLUGIN_TICK_END /* TIMESTAMP(131) */
2574+
2575+#define TS_ENTER_NP_START TIMESTAMP(140)
2576+#define TS_ENTER_NP_END TIMESTAMP(141)
2577+
2578+#define TS_EXIT_NP_START TIMESTAMP(150)
2579+#define TS_EXIT_NP_END TIMESTAMP(151)
2580+
2581+#define TS_SRP_UP_START TIMESTAMP(160)
2582+#define TS_SRP_UP_END TIMESTAMP(161)
2583+#define TS_SRP_DOWN_START TIMESTAMP(162)
2584+#define TS_SRP_DOWN_END TIMESTAMP(163)
2585+
2586+#define TS_PI_UP_START TIMESTAMP(170)
2587+#define TS_PI_UP_END TIMESTAMP(171)
2588+#define TS_PI_DOWN_START TIMESTAMP(172)
2589+#define TS_PI_DOWN_END TIMESTAMP(173)
2590+
2591+#define TS_FIFO_UP_START TIMESTAMP(180)
2592+#define TS_FIFO_UP_END TIMESTAMP(181)
2593+#define TS_FIFO_DOWN_START TIMESTAMP(182)
2594+#define TS_FIFO_DOWN_END TIMESTAMP(183)
2595+
2596+#define TS_SEND_RESCHED_START(c) CTIMESTAMP(190, c)
2597+#define TS_SEND_RESCHED_END DTIMESTAMP(191, TSK_UNKNOWN)
2598+
2599+
2600+#endif /* !_SYS_TRACE_H_ */
2601diff --git a/include/litmus/unistd.h b/include/litmus/unistd.h
2602new file mode 100644
2603index 0000000..5ef367f
2604--- /dev/null
2605+++ b/include/litmus/unistd.h
2606@@ -0,0 +1,21 @@
2607+
2608+#define __LSC(x) (__NR_LITMUS + x)
2609+
2610+#define __NR_set_rt_task_param __LSC(0)
2611+#define __NR_get_rt_task_param __LSC(1)
2612+#define __NR_sleep_next_period __LSC(2)
2613+#define __NR_register_np_flag __LSC(3)
2614+#define __NR_exit_np __LSC(4)
2615+#define __NR_od_open __LSC(5)
2616+#define __NR_od_close __LSC(6)
2617+#define __NR_fmlp_down __LSC(7)
2618+#define __NR_fmlp_up __LSC(8)
2619+#define __NR_srp_down __LSC(9)
2620+#define __NR_srp_up __LSC(10)
2621+#define __NR_query_job_no __LSC(11)
2622+#define __NR_wait_for_job_release __LSC(12)
2623+#define __NR_wait_for_ts_release __LSC(13)
2624+#define __NR_release_ts __LSC(14)
2625+#define __NR_null_call __LSC(15)
2626+
2627+#define NR_litmus_syscalls 16
2628diff --git a/kernel/exit.c b/kernel/exit.c
2629index 549c055..bc313b7 100644
2630--- a/kernel/exit.c
2631+++ b/kernel/exit.c
2632@@ -52,6 +52,8 @@
2633
2634 extern void sem_exit (void);
2635
2636+extern void exit_od_table(struct task_struct* t);
2637+
2638 static void exit_mm(struct task_struct * tsk);
2639
2640 static void __unhash_process(struct task_struct *p)
2641@@ -987,6 +989,8 @@ fastcall NORET_TYPE void do_exit(long code)
2642 if (unlikely(tsk->audit_context))
2643 audit_free(tsk);
2644
2645+ exit_od_table(tsk);
2646+
2647 tsk->exit_code = code;
2648 taskstats_exit(tsk, group_dead);
2649
2650diff --git a/kernel/fork.c b/kernel/fork.c
2651index 8dd8ff2..4c322d4 100644
2652--- a/kernel/fork.c
2653+++ b/kernel/fork.c
2654@@ -59,6 +59,9 @@
2655 #include <asm/cacheflush.h>
2656 #include <asm/tlbflush.h>
2657
2658+#include <litmus/litmus.h>
2659+#include <litmus/sched_plugin.h>
2660+
2661 /*
2662 * Protected counters by write_lock_irq(&tasklist_lock)
2663 */
2664@@ -121,6 +124,8 @@ void __put_task_struct(struct task_struct *tsk)
2665 WARN_ON(atomic_read(&tsk->usage));
2666 WARN_ON(tsk == current);
2667
2668+ exit_litmus(tsk);
2669+
2670 security_task_free(tsk);
2671 free_uid(tsk->user);
2672 put_group_info(tsk->group_info);
2673@@ -182,6 +187,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
2674 *tsk = *orig;
2675 tsk->stack = ti;
2676
2677+ /* Don't let the new task be a real-time task. */
2678+ memset(&tsk->rt_param, 0, sizeof(struct rt_task));
2679+
2680 err = prop_local_init_single(&tsk->dirties);
2681 if (err) {
2682 free_thread_info(ti);
2683diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
2684index f994bb8..7b8576b 100644
2685--- a/kernel/hrtimer.c
2686+++ b/kernel/hrtimer.c
2687@@ -46,6 +46,9 @@
2688
2689 #include <asm/uaccess.h>
2690
2691+#include <litmus/litmus.h>
2692+
2693+
2694 /**
2695 * ktime_get - get the monotonic time in ktime_t format
2696 *
2697@@ -813,6 +816,70 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
2698 return 0;
2699 }
2700
2701+void hrtimer_pull(void)
2702+{
2703+ struct hrtimer_cpu_base* base = &__get_cpu_var(hrtimer_bases);
2704+ struct hrtimer_start_on_info* info;
2705+ struct list_head *pos, *safe, list;
2706+
2707+ spin_lock(&base->lock);
2708+ list_replace_init(&base->to_pull, &list);
2709+ spin_unlock(&base->lock);
2710+
2711+ list_for_each_safe(pos, safe, &list) {
2712+ info = list_entry(pos, struct hrtimer_start_on_info, list);
2713+ TRACE("pulled timer 0x%x\n", info->timer);
2714+ list_del(pos);
2715+ hrtimer_start(info->timer, info->time, info->mode);
2716+ }
2717+}
2718+
2719+int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info,
2720+ struct hrtimer *timer, ktime_t time,
2721+ const enum hrtimer_mode mode)
2722+{
2723+ unsigned long flags;
2724+ struct hrtimer_cpu_base* base;
2725+ int in_use = 0, was_empty;
2726+
2727+ /* serialize access to info through the timer base */
2728+ lock_hrtimer_base(timer, &flags);
2729+
2730+ in_use = atomic_read(&info->state) != HRTIMER_START_ON_INACTIVE;
2731+ if (!in_use) {
2732+ INIT_LIST_HEAD(&info->list);
2733+ info->timer = timer;
2734+ info->time = time;
2735+ info->mode = mode;
2736+ /* mark as in use */
2737+ atomic_set(&info->state, HRTIMER_START_ON_QUEUED);
2738+ }
2739+
2740+ unlock_hrtimer_base(timer, &flags);
2741+
2742+ if (!in_use) {
2743+ /* initiate pull */
2744+ preempt_disable();
2745+ if (cpu == smp_processor_id()) {
2746+ /* start timer locally */
2747+ hrtimer_start(info->timer, info->time, info->mode);
2748+ } else {
2749+ base = &per_cpu(hrtimer_bases, cpu);
2750+ spin_lock_irqsave(&base->lock, flags);
2751+ was_empty = list_empty(&base->to_pull);
2752+ list_add(&info->list, &base->to_pull);
2753+ spin_unlock_irqrestore(&base->lock, flags);
2754+ if (was_empty)
2755+ /* only send IPI if other no else
2756+ * has done so already
2757+ */
2758+ smp_send_pull_timers(cpu);
2759+ }
2760+ preempt_enable();
2761+ }
2762+ return in_use;
2763+}
2764+
2765 /**
2766 * hrtimer_start - (re)start an relative timer on the current CPU
2767 * @timer: the timer to be added
2768@@ -1247,6 +1314,9 @@ void hrtimer_run_queues(void)
2769 run_hrtimer_queue(cpu_base, i);
2770 }
2771
2772+/* FIXME: this won't be needed anymore once we port to Linux > 2.6.24 */
2773+void hrtimer_wakeup_hack(int onoff);
2774+
2775 /*
2776 * Sleep related functions:
2777 */
2778@@ -1257,8 +1327,11 @@ static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer)
2779 struct task_struct *task = t->task;
2780
2781 t->task = NULL;
2782- if (task)
2783+ if (task) {
2784+ hrtimer_wakeup_hack(1);
2785 wake_up_process(task);
2786+ hrtimer_wakeup_hack(0);
2787+ }
2788
2789 return HRTIMER_NORESTART;
2790 }
2791@@ -1384,12 +1457,14 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
2792 int i;
2793
2794 spin_lock_init(&cpu_base->lock);
2795+
2796 lockdep_set_class(&cpu_base->lock, &cpu_base->lock_key);
2797
2798 for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++)
2799 cpu_base->clock_base[i].cpu_base = cpu_base;
2800
2801 hrtimer_init_hres(cpu_base);
2802+ INIT_LIST_HEAD(&cpu_base->to_pull);
2803 }
2804
2805 #ifdef CONFIG_HOTPLUG_CPU
2806diff --git a/kernel/printk.c b/kernel/printk.c
2807index 89011bf..4423a55 100644
2808--- a/kernel/printk.c
2809+++ b/kernel/printk.c
2810@@ -54,6 +54,13 @@ int console_printk[4] = {
2811 DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
2812 };
2813
2814+/* divert printk() messages when we have a LITMUS^RT
2815+ * debug listener
2816+ */
2817+#include <litmus/litmus.h>
2818+int trace_override = 0;
2819+int trace_recurse = 0;
2820+
2821 /*
2822 * Low level drivers may need that to know if they can schedule in
2823 * their unblank() callback or not. So let's export it.
2824@@ -652,6 +659,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
2825
2826 /* Emit the output into the temporary buffer */
2827 printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
2828+ if (trace_override && !trace_recurse)
2829+ TRACE("%s", printk_buf);
2830
2831 /*
2832 * Copy the output into log_buf. If the caller didn't provide
2833@@ -932,7 +941,7 @@ int is_console_locked(void)
2834
2835 void wake_up_klogd(void)
2836 {
2837- if (!oops_in_progress && waitqueue_active(&log_wait))
2838+ if (!trace_override && !oops_in_progress && waitqueue_active(&log_wait))
2839 wake_up_interruptible(&log_wait);
2840 }
2841
2842diff --git a/kernel/sched.c b/kernel/sched.c
2843index e76b11c..a3e4ad1 100644
2844--- a/kernel/sched.c
2845+++ b/kernel/sched.c
2846@@ -67,6 +67,11 @@
2847 #include <asm/tlb.h>
2848 #include <asm/irq_regs.h>
2849
2850+#include <litmus/sched_trace.h>
2851+#include <litmus/trace.h>
2852+
2853+#include <litmus/norqlock.h>
2854+
2855 /*
2856 * Scheduler clock - returns current time in nanosec units.
2857 * This is default implementation.
2858@@ -324,6 +329,8 @@ struct rq {
2859
2860 atomic_t nr_iowait;
2861
2862+ struct task_struct* litmus_next;
2863+
2864 #ifdef CONFIG_SMP
2865 struct sched_domain *sd;
2866
2867@@ -875,11 +882,12 @@ static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) {}
2868 #include "sched_idletask.c"
2869 #include "sched_fair.c"
2870 #include "sched_rt.c"
2871+#include "../litmus/sched_litmus.c"
2872 #ifdef CONFIG_SCHED_DEBUG
2873 # include "sched_debug.c"
2874 #endif
2875
2876-#define sched_class_highest (&rt_sched_class)
2877+#define sched_class_highest (&litmus_sched_class)
2878
2879 /*
2880 * Update delta_exec, delta_fair fields for rq.
2881@@ -1516,6 +1524,8 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
2882 int new_cpu;
2883 #endif
2884
2885+ if (is_realtime(p))
2886+ TRACE_TASK(p, "try_to_wake_up() state:%d\n", p->state);
2887 rq = task_rq_lock(p, &flags);
2888 old_state = p->state;
2889 if (!(old_state & state))
2890@@ -1529,7 +1539,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
2891 this_cpu = smp_processor_id();
2892
2893 #ifdef CONFIG_SMP
2894- if (unlikely(task_running(rq, p)))
2895+ if (unlikely(task_running(rq, p) || is_realtime(p)))
2896 goto out_activate;
2897
2898 new_cpu = cpu;
2899@@ -1650,8 +1660,10 @@ out_activate:
2900 out_running:
2901 p->state = TASK_RUNNING;
2902 out:
2903+ if (is_realtime(p))
2904+ TRACE_TASK(p, "try_to_wake_up() done state:%d\n", p->state);
2905 task_rq_unlock(rq, &flags);
2906-
2907+ tick_no_rqlock();
2908 return success;
2909 }
2910
2911@@ -1890,6 +1902,8 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
2912 */
2913 prev_state = prev->state;
2914 finish_arch_switch(prev);
2915+ litmus->finish_switch(prev);
2916+ prev->rt_param.stack_in_use = NO_CPU;
2917 finish_lock_switch(rq, prev);
2918 fire_sched_in_preempt_notifiers(current);
2919 if (mm)
2920@@ -3480,6 +3494,7 @@ void scheduler_tick(void)
2921 struct task_struct *curr = rq->curr;
2922 u64 next_tick = rq->tick_timestamp + TICK_NSEC;
2923
2924+ TS_TICK_START(current);
2925 spin_lock(&rq->lock);
2926 __update_rq_clock(rq);
2927 /*
2928@@ -3491,12 +3506,17 @@ void scheduler_tick(void)
2929 update_cpu_load(rq);
2930 if (curr != rq->idle) /* FIXME: needed? */
2931 curr->sched_class->task_tick(rq, curr);
2932+ TS_PLUGIN_TICK_START;
2933+ litmus_tick(rq, curr);
2934+ TS_PLUGIN_TICK_END;
2935 spin_unlock(&rq->lock);
2936
2937 #ifdef CONFIG_SMP
2938 rq->idle_at_tick = idle_cpu(cpu);
2939- trigger_load_balance(rq, cpu);
2940+ if (!is_realtime(current))
2941+ trigger_load_balance(rq, cpu);
2942 #endif
2943+ TS_TICK_END(current);
2944 }
2945
2946 #if defined(CONFIG_PREEMPT) && defined(CONFIG_DEBUG_PREEMPT)
2947@@ -3594,11 +3614,13 @@ pick_next_task(struct rq *rq, struct task_struct *prev)
2948 * Optimization: we know that if all tasks are in
2949 * the fair class we can call that function directly:
2950 */
2951- if (likely(rq->nr_running == rq->cfs.nr_running)) {
2952+ /* Don't do that for LITMUS.
2953+ if (likely(rq->nr_running == rq->cfs.nr_running)) {
2954 p = fair_sched_class.pick_next_task(rq);
2955 if (likely(p))
2956 return p;
2957 }
2958+ */
2959
2960 class = sched_class_highest;
2961 for ( ; ; ) {
2962@@ -3633,6 +3655,9 @@ need_resched:
2963
2964 release_kernel_lock(prev);
2965 need_resched_nonpreemptible:
2966+ TS_SCHED_START;
2967+
2968+ sched_trace_task_switch_away(prev);
2969
2970 schedule_debug(prev);
2971
2972@@ -3643,6 +3668,9 @@ need_resched_nonpreemptible:
2973 __update_rq_clock(rq);
2974 spin_lock(&rq->lock);
2975 clear_tsk_need_resched(prev);
2976+ TS_PLUGIN_SCHED_START;
2977+ litmus_schedule(rq, prev);
2978+ TS_PLUGIN_SCHED_END;
2979
2980 if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
2981 if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
2982@@ -3667,18 +3695,34 @@ need_resched_nonpreemptible:
2983 rq->curr = next;
2984 ++*switch_count;
2985
2986+ TS_SCHED_END(next);
2987+ TS_CXS_START(next);
2988 context_switch(rq, prev, next); /* unlocks the rq */
2989- } else
2990+ TS_CXS_END(current);
2991+ } else {
2992+ TS_SCHED_END(prev);
2993 spin_unlock_irq(&rq->lock);
2994+ }
2995+ TS_SCHED2_START(current);
2996+
2997+ tick_no_rqlock();
2998+
2999+ sched_trace_task_switch_to(current);
3000
3001 if (unlikely(reacquire_kernel_lock(current) < 0)) {
3002 cpu = smp_processor_id();
3003 rq = cpu_rq(cpu);
3004+ TS_SCHED2_END(current);
3005 goto need_resched_nonpreemptible;
3006 }
3007 preempt_enable_no_resched();
3008- if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
3009+ if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) {
3010+ TS_SCHED2_END(current);
3011 goto need_resched;
3012+ }
3013+ TS_SCHED2_END(current);
3014+ if (srp_active())
3015+ srp_ceiling_block();
3016 }
3017 EXPORT_SYMBOL(schedule);
3018
3019@@ -3886,6 +3930,18 @@ void complete_all(struct completion *x)
3020 }
3021 EXPORT_SYMBOL(complete_all);
3022
3023+void complete_n(struct completion *x, int n)
3024+{
3025+ unsigned long flags;
3026+
3027+ spin_lock_irqsave(&x->wait.lock, flags);
3028+ x->done += n;
3029+ __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,
3030+ n, 0, NULL);
3031+ spin_unlock_irqrestore(&x->wait.lock, flags);
3032+}
3033+EXPORT_SYMBOL(complete_n);
3034+
3035 static inline long __sched
3036 do_wait_for_common(struct completion *x, long timeout, int state)
3037 {
3038@@ -4236,6 +4292,9 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
3039 case SCHED_RR:
3040 p->sched_class = &rt_sched_class;
3041 break;
3042+ case SCHED_LITMUS:
3043+ p->sched_class = &litmus_sched_class;
3044+ break;
3045 }
3046
3047 p->rt_priority = prio;
3048@@ -4268,7 +4327,7 @@ recheck:
3049 policy = oldpolicy = p->policy;
3050 else if (policy != SCHED_FIFO && policy != SCHED_RR &&
3051 policy != SCHED_NORMAL && policy != SCHED_BATCH &&
3052- policy != SCHED_IDLE)
3053+ policy != SCHED_IDLE && policy != SCHED_LITMUS)
3054 return -EINVAL;
3055 /*
3056 * Valid priorities for SCHED_FIFO and SCHED_RR are
3057@@ -4282,6 +4341,9 @@ recheck:
3058 if (rt_policy(policy) != (param->sched_priority != 0))
3059 return -EINVAL;
3060
3061+ if (policy == SCHED_LITMUS && policy == p->policy)
3062+ return -EINVAL;
3063+
3064 /*
3065 * Allow unprivileged RT tasks to decrease priority:
3066 */
3067@@ -4316,6 +4378,12 @@ recheck:
3068 return -EPERM;
3069 }
3070
3071+ if (policy == SCHED_LITMUS) {
3072+ retval = litmus_admit_task(p);
3073+ if (retval)
3074+ return retval;
3075+ }
3076+
3077 retval = security_task_setscheduler(p, policy, param);
3078 if (retval)
3079 return retval;
3080@@ -4345,9 +4413,18 @@ recheck:
3081 p->sched_class->put_prev_task(rq, p);
3082 }
3083
3084+ if (p->policy == SCHED_LITMUS)
3085+ litmus_exit_task(p);
3086+
3087 oldprio = p->prio;
3088 __setscheduler(rq, p, policy, param->sched_priority);
3089
3090+ if (policy == SCHED_LITMUS) {
3091+ p->rt_param.stack_in_use = running ? rq->cpu : NO_CPU;
3092+ p->rt_param.present = running;
3093+ litmus->task_new(p, on_rq, running);
3094+ }
3095+
3096 if (on_rq) {
3097 if (running)
3098 p->sched_class->set_curr_task(rq);
3099@@ -4364,6 +4441,7 @@ recheck:
3100 check_preempt_curr(rq, p);
3101 }
3102 }
3103+
3104 __task_rq_unlock(rq);
3105 spin_unlock_irqrestore(&p->pi_lock, flags);
3106
3107@@ -4494,10 +4572,11 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
3108 read_lock(&tasklist_lock);
3109
3110 p = find_process_by_pid(pid);
3111- if (!p) {
3112+ if (!p || is_realtime(p)) {
3113+ /* LITMUS tasks don't get to do this, transition to BE first */
3114 read_unlock(&tasklist_lock);
3115 mutex_unlock(&sched_hotcpu_mutex);
3116- return -ESRCH;
3117+ return p ? -EPERM : -ESRCH;
3118 }
3119
3120 /*
3121diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
3122index da7c061..de30496 100644
3123--- a/kernel/sched_fair.c
3124+++ b/kernel/sched_fair.c
3125@@ -845,7 +845,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
3126 struct sched_entity *se = &curr->se, *pse = &p->se;
3127 unsigned long gran;
3128
3129- if (unlikely(rt_prio(p->prio))) {
3130+ if (unlikely(rt_prio(p->prio) || p->policy == SCHED_LITMUS)) {
3131 update_rq_clock(rq);
3132 update_curr(cfs_rq);
3133 resched_task(curr);
3134diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
3135index 9ba3daa..c7c938c 100644
3136--- a/kernel/sched_rt.c
3137+++ b/kernel/sched_rt.c
3138@@ -70,7 +70,7 @@ yield_task_rt(struct rq *rq)
3139 */
3140 static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p)
3141 {
3142- if (p->prio < rq->curr->prio)
3143+ if (p->prio < rq->curr->prio || p->policy == SCHED_LITMUS)
3144 resched_task(rq->curr);
3145 }
3146
3147diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
3148index cb89fa8..d6dad22 100644
3149--- a/kernel/time/tick-sched.c
3150+++ b/kernel/time/tick-sched.c
3151@@ -568,6 +568,42 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
3152 }
3153
3154 /**
3155+ * tick_set_quanta_type - get the quanta type as a boot option
3156+ * Default is standard setup with ticks staggered over first
3157+ * half of tick period.
3158+ */
3159+int quanta_type = LINUX_DEFAULT_TICKS;
3160+static int __init tick_set_quanta_type(char *str)
3161+{
3162+ if (strcmp("aligned", str) == 0)
3163+ quanta_type = LITMUS_ALIGNED_TICKS;
3164+ else if (strcmp("staggered", str) == 0)
3165+ quanta_type = LITMUS_STAGGERED_TICKS;
3166+ return 1;
3167+}
3168+__setup("quanta=", tick_set_quanta_type);
3169+
3170+u64 cpu_stagger_offset(int cpu)
3171+{
3172+ u64 offset = 0;
3173+ switch (quanta_type) {
3174+ case LITMUS_ALIGNED_TICKS:
3175+ offset = 0;
3176+ break;
3177+ case LITMUS_STAGGERED_TICKS:
3178+ offset = ktime_to_ns(tick_period);
3179+ do_div(offset, num_possible_cpus());
3180+ offset *= cpu;
3181+ break;
3182+ default:
3183+ offset = ktime_to_ns(tick_period) >> 1;
3184+ do_div(offset, num_possible_cpus());
3185+ offset *= cpu;
3186+ }
3187+ return offset;
3188+}
3189+
3190+/**
3191 * tick_setup_sched_timer - setup the tick emulation timer
3192 */
3193 void tick_setup_sched_timer(void)
3194@@ -585,9 +621,11 @@ void tick_setup_sched_timer(void)
3195
3196 /* Get the next period (per cpu) */
3197 ts->sched_timer.expires = tick_init_jiffy_update();
3198- offset = ktime_to_ns(tick_period) >> 1;
3199- do_div(offset, num_possible_cpus());
3200- offset *= smp_processor_id();
3201+
3202+ /* Offset must be set correctly to achieve desired quanta type. */
3203+ offset = cpu_stagger_offset(smp_processor_id());
3204+
3205+ /* Add correct offset to expiration time. */
3206 ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);
3207
3208 for (;;) {
3209diff --git a/litmus/Kconfig b/litmus/Kconfig
3210new file mode 100644
3211index 0000000..f73a454
3212--- /dev/null
3213+++ b/litmus/Kconfig
3214@@ -0,0 +1,85 @@
3215+menu "LITMUS^RT"
3216+
3217+menu "Real-Time Synchronization"
3218+
3219+config NP_SECTION
3220+ bool "Non-preemptive section support"
3221+ depends on !SPARC64
3222+ default n
3223+ help
3224+ Include support for flag-based non-preemptive section signaling
3225+ from userspace.
3226+
3227+ (currently broken on SPARC64)
3228+
3229+ Say Yes if you want FMLP short critical section synchronization support.
3230+
3231+
3232+config SRP
3233+ bool "Stack Resource Policy (SRP)"
3234+ default n
3235+ help
3236+ Include support for Baker's Stack Resource Policy.
3237+
3238+ Say Yes if you want FMLP local long critical section synchronization support.
3239+
3240+config FMLP
3241+ bool "FMLP support"
3242+ depends on NP_SECTION
3243+ default n
3244+ help
3245+ Include support for deterministic multiprocessor real-time
3246+ synchronization support.
3247+
3248+ Say Yes if you want FMLP long critical section synchronization support.
3249+
3250+endmenu
3251+
3252+menu "Tracing"
3253+
3254+config FEATHER_TRACE
3255+ bool "Feather-Trace Infrastructure"
3256+ default y
3257+ help
3258+ Feather-Trace basic tracing infrastructure. Includes device file
3259+ driver and instrumentation point support.
3260+
3261+
3262+config SCHED_TASK_TRACE
3263+ bool "Trace real-time tasks"
3264+ depends on FEATHER_TRACE
3265+ default y
3266+ help
3267+ Include support for the sched_trace_XXX() tracing functions. This
3268+ allows the collection of real-time task events such as job
3269+ completions, job releases, early completions, etc. This results in a
3270+ small overhead in the scheduling code. Disable if the overhead is not
3271+ acceptable (e.g., benchmarking).
3272+
3273+ Say Yes for debugging.
3274+ Say No for overhead tracing.
3275+
3276+config SCHED_OVERHEAD_TRACE
3277+ bool "Record timestamps for overhead measurements"
3278+ depends on FEATHER_TRACE
3279+ default n
3280+ help
3281+ Export event stream for overhead tracing.
3282+ Say Yes for overhead tracing.
3283+
3284+config SCHED_DEBUG_TRACE
3285+ bool "TRACE() debugging"
3286+ default y
3287+ help
3288+ Include support for sched_trace_log_messageg(), which is used to
3289+ implement TRACE(). If disabled, no TRACE() messages will be included
3290+ in the kernel, and no overheads due to debugging statements will be
3291+ incurred by the scheduler. Disable if the overhead is not acceptable
3292+ (e.g. benchmarking).
3293+
3294+ Say Yes for debugging.
3295+ Say No for overhead tracing.
3296+
3297+endmenu
3298+
3299+endmenu
3300diff --git a/litmus/Makefile b/litmus/Makefile
3301new file mode 100644
3302index 0000000..837f697
3303--- /dev/null
3304+++ b/litmus/Makefile
3305@@ -0,0 +1,18 @@
3306+#
3307+# Makefile for LITMUS^RT
3308+#
3309+
3310+obj-y = sched_plugin.o litmus.o \
3311+ edf_common.o jobs.o \
3312+ rt_domain.o fdso.o sync.o \
3313+ fmlp.o srp.o norqlock.o \
3314+ heap.o \
3315+ sched_gsn_edf.o \
3316+ sched_psn_edf.o \
3317+ sched_cedf.o \
3318+ sched_pfair.o
3319+
3320+obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o
3321+obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o
3322+obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o
3323+obj-$(CONFIG_SCHED_OVERHEAD_TRACE) += trace.o
3324diff --git a/litmus/edf_common.c b/litmus/edf_common.c
3325new file mode 100644
3326index 0000000..8149e0c
3327--- /dev/null
3328+++ b/litmus/edf_common.c
3329@@ -0,0 +1,103 @@
3330+/*
3331+ * kernel/edf_common.c
3332+ *
3333+ * Common functions for EDF based scheduler.
3334+ */
3335+
3336+#include <linux/percpu.h>
3337+#include <linux/sched.h>
3338+#include <linux/list.h>
3339+
3340+#include <litmus/litmus.h>
3341+#include <litmus/sched_plugin.h>
3342+#include <litmus/sched_trace.h>
3343+
3344+
3345+#include <litmus/edf_common.h>
3346+
3347+/* edf_higher_prio - returns true if first has a higher EDF priority
3348+ * than second. Deadline ties are broken by PID.
3349+ *
3350+ * both first and second may be NULL
3351+ */
3352+int edf_higher_prio(struct task_struct* first,
3353+ struct task_struct* second)
3354+{
3355+ struct task_struct *first_task = first;
3356+ struct task_struct *second_task = second;
3357+
3358+ /* There is no point in comparing a task to itself. */
3359+ if (first && first == second) {
3360+ TRACE_TASK(first,
3361+ "WARNING: pointless edf priority comparison.\n");
3362+ return 0;
3363+ }
3364+
3365+
3366+ /* Check for inherited priorities. Change task
3367+ * used for comparison in such a case.
3368+ */
3369+ if (first && first->rt_param.inh_task)
3370+ first_task = first->rt_param.inh_task;
3371+ if (second && second->rt_param.inh_task)
3372+ second_task = second->rt_param.inh_task;
3373+
3374+ return
3375+ /* it has to exist in order to have higher priority */
3376+ first_task && (
3377+ /* does the second task exist and is it a real-time task? If
3378+ * not, the first task (which is a RT task) has higher
3379+ * priority.
3380+ */
3381+ !second_task || !is_realtime(second_task) ||
3382+
3383+ /* is the deadline of the first task earlier?
3384+ * Then it has higher priority.
3385+ */
3386+ earlier_deadline(first_task, second_task) ||
3387+
3388+ /* Do we have a deadline tie?
3389+ * Then break by PID.
3390+ */
3391+ (get_deadline(first_task) == get_deadline(second_task) &&
3392+ (first_task->pid < second_task->pid ||
3393+
3394+ /* If the PIDs are the same then the task with the inherited
3395+ * priority wins.
3396+ */
3397+ (first_task->pid == second_task->pid &&
3398+ !second->rt_param.inh_task))));
3399+}
3400+
3401+int edf_ready_order(struct heap_node* a, struct heap_node* b)
3402+{
3403+ return edf_higher_prio(heap2task(a), heap2task(b));
3404+}
3405+
3406+void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched,
3407+ release_jobs_t release)
3408+{
3409+ rt_domain_init(rt, edf_ready_order, resched, release);
3410+}
3411+
3412+/* need_to_preempt - check whether the task t needs to be preempted
3413+ * call only with irqs disabled and with ready_lock acquired
3414+ * THIS DOES NOT TAKE NON-PREEMPTIVE SECTIONS INTO ACCOUNT!
3415+ */
3416+int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t)
3417+{
3418+ /* we need the read lock for edf_ready_queue */
3419+ /* no need to preempt if there is nothing pending */
3420+ if (!__jobs_pending(rt))
3421+ return 0;
3422+ /* we need to reschedule if t doesn't exist */
3423+ if (!t)
3424+ return 1;
3425+
3426+ /* NOTE: We cannot check for non-preemptibility since we
3427+ * don't know what address space we're currently in.
3428+ */
3429+
3430+ /* make sure to get non-rt stuff out of the way */
3431+ return !is_realtime(t) || edf_higher_prio(__next_ready(rt), t);
3432+}
3433diff --git a/litmus/fdso.c b/litmus/fdso.c
3434new file mode 100644
3435index 0000000..7a16f64
3436--- /dev/null
3437+++ b/litmus/fdso.c
3438@@ -0,0 +1,281 @@
3439+/* fdso.c - file descriptor attached shared objects
3440+ *
3441+ * (c) 2007 B. Brandenburg, LITMUS^RT project
3442+ *
3443+ * Notes:
3444+ * - objects descriptor (OD) tables are not cloned during a fork.
3445+ * - objects are created on-demand, and freed after the last reference
3446+ * is dropped.
3447+ * - for now, object types are hard coded.
3448+ * - As long as we have live objects, we keep a reference to the inode.
3449+ */
3450+
3451+#include <linux/errno.h>
3452+#include <linux/sched.h>
3453+#include <linux/mutex.h>
3454+#include <linux/file.h>
3455+#include <asm/uaccess.h>
3456+
3457+#include <litmus/fdso.h>
3458+
3459+extern struct fdso_ops fmlp_sem_ops;
3460+extern struct fdso_ops srp_sem_ops;
3461+
3462+static const struct fdso_ops* fdso_ops[] = {
3463+ &fmlp_sem_ops,
3464+ &srp_sem_ops,
3465+};
3466+
3467+static void* fdso_create(obj_type_t type)
3468+{
3469+ if (fdso_ops[type]->create)
3470+ return fdso_ops[type]->create();
3471+ else
3472+ return NULL;
3473+}
3474+
3475+static void fdso_destroy(obj_type_t type, void* obj)
3476+{
3477+ fdso_ops[type]->destroy(obj);
3478+}
3479+
3480+static int fdso_open(struct od_table_entry* entry, void* __user config)
3481+{
3482+ if (fdso_ops[entry->obj->type]->open)
3483+ return fdso_ops[entry->obj->type]->open(entry, config);
3484+ else
3485+ return 0;
3486+}
3487+
3488+static int fdso_close(struct od_table_entry* entry)
3489+{
3490+ if (fdso_ops[entry->obj->type]->close)
3491+ return fdso_ops[entry->obj->type]->close(entry);
3492+ else
3493+ return 0;
3494+}
3495+
3496+/* inode must be locked already */
3497+static struct inode_obj_id* alloc_inode_obj(struct inode* inode,
3498+ obj_type_t type,
3499+ unsigned int id)
3500+{
3501+ struct inode_obj_id* obj;
3502+ void* raw_obj;
3503+
3504+ raw_obj = fdso_create(type);
3505+ if (!raw_obj)
3506+ return NULL;
3507+
3508+ obj = kmalloc(sizeof(*obj), GFP_KERNEL);
3509+ if (!obj)
3510+ return NULL;
3511+ INIT_LIST_HEAD(&obj->list);
3512+ atomic_set(&obj->count, 1);
3513+ obj->type = type;
3514+ obj->id = id;
3515+ obj->obj = raw_obj;
3516+ obj->inode = inode;
3517+
3518+ list_add(&obj->list, &inode->i_obj_list);
3519+ atomic_inc(&inode->i_count);
3520+
3521+ printk(KERN_DEBUG "alloc_inode_obj(%p, %d, %d): object created\n", inode, type, id);
3522+ return obj;
3523+}
3524+
3525+/* inode must be locked already */
3526+static struct inode_obj_id* get_inode_obj(struct inode* inode,
3527+ obj_type_t type,
3528+ unsigned int id)
3529+{
3530+ struct list_head* pos;
3531+ struct inode_obj_id* obj = NULL;
3532+
3533+ list_for_each(pos, &inode->i_obj_list) {
3534+ obj = list_entry(pos, struct inode_obj_id, list);
3535+ if (obj->id == id && obj->type == type) {
3536+ atomic_inc(&obj->count);
3537+ return obj;
3538+ }
3539+ }
3540+ printk(KERN_DEBUG "get_inode_obj(%p, %d, %d): couldn't find object\n", inode, type, id);
3541+ return NULL;
3542+}
3543+
3544+
3545+static void put_inode_obj(struct inode_obj_id* obj)
3546+{
3547+ struct inode* inode;
3548+ int let_go = 0;
3549+
3550+ inode = obj->inode;
3551+ if (atomic_dec_and_test(&obj->count)) {
3552+
3553+ mutex_lock(&inode->i_obj_mutex);
3554+ /* no new references can be obtained */
3555+ if (!atomic_read(&obj->count)) {
3556+ list_del(&obj->list);
3557+ fdso_destroy(obj->type, obj->obj);
3558+ kfree(obj);
3559+ let_go = 1;
3560+ }
3561+ mutex_unlock(&inode->i_obj_mutex);
3562+ if (let_go)
3563+ iput(inode);
3564+ }
3565+}
3566+
3567+static struct od_table_entry* get_od_entry(struct task_struct* t)
3568+{
3569+ struct od_table_entry* table;
3570+ int i;
3571+
3572+
3573+ table = t->od_table;
3574+ if (!table) {
3575+ table = kzalloc(sizeof(*table) * MAX_OBJECT_DESCRIPTORS,
3576+ GFP_KERNEL);
3577+ t->od_table = table;
3578+ }
3579+
3580+ for (i = 0; table && i < MAX_OBJECT_DESCRIPTORS; i++)
3581+ if (!table[i].used) {
3582+ table[i].used = 1;
3583+ return table + i;
3584+ }
3585+ return NULL;
3586+}
3587+
3588+static int put_od_entry(struct od_table_entry* od)
3589+{
3590+ put_inode_obj(od->obj);
3591+ od->used = 0;
3592+ return 0;
3593+}
3594+
3595+void exit_od_table(struct task_struct* t)
3596+{
3597+ int i;
3598+
3599+ if (t->od_table) {
3600+ for (i = 0; i < MAX_OBJECT_DESCRIPTORS; i++)
3601+ if (t->od_table[i].used)
3602+ put_od_entry(t->od_table + i);
3603+ kfree(t->od_table);
3604+ t->od_table = NULL;
3605+ }
3606+}
3607+
3608+static int do_sys_od_open(struct file* file, obj_type_t type, int id,
3609+ void* __user config)
3610+{
3611+ int idx = 0, err;
3612+ struct inode* inode;
3613+ struct inode_obj_id* obj = NULL;
3614+ struct od_table_entry* entry;
3615+
3616+ inode = file->f_dentry->d_inode;
3617+
3618+ entry = get_od_entry(current);
3619+ if (!entry)
3620+ return -ENOMEM;
3621+
3622+ mutex_lock(&inode->i_obj_mutex);
3623+ obj = get_inode_obj(inode, type, id);
3624+ if (!obj)
3625+ obj = alloc_inode_obj(inode, type, id);
3626+ if (!obj) {
3627+ idx = -ENOMEM;
3628+ entry->used = 0;
3629+ } else {
3630+ entry->obj = obj;
3631+ entry->extra = NULL;
3632+ idx = entry - current->od_table;
3633+ }
3634+
3635+ mutex_unlock(&inode->i_obj_mutex);
3636+
3637+ err = fdso_open(entry, config);
3638+ if (err < 0) {
3639+ /* The class rejected the open call.
3640+ * We need to clean up and tell user space.
3641+ */
3642+ put_od_entry(entry);
3643+ idx = err;
3644+ }
3645+
3646+ return idx;
3647+}
3648+
3649+
3650+struct od_table_entry* __od_lookup(int od)
3651+{
3652+ struct task_struct *t = current;
3653+
3654+ if (!t->od_table)
3655+ return NULL;
3656+ if (od < 0 || od >= MAX_OBJECT_DESCRIPTORS)
3657+ return NULL;
3658+ if (!t->od_table[od].used)
3659+ return NULL;
3660+ return t->od_table + od;
3661+}
3662+
3663+
3664+asmlinkage int sys_od_open(int fd, int type, int obj_id, void* __user config)
3665+{
3666+ int ret = 0;
3667+ struct file* file;
3668+
3669+ /*
3670+ 1) get file from fd, get inode from file
3671+ 2) lock inode
3672+ 3) try to lookup object
3673+ 4) if not present create and enqueue object, inc inode refcnt
3674+ 5) increment refcnt of object
3675+ 6) alloc od_table_entry, setup ptrs
3676+ 7) unlock inode
3677+ 8) return offset in od_table as OD
3678+ */
3679+
3680+ if (type < MIN_OBJ_TYPE || type > MAX_OBJ_TYPE) {
3681+ ret = -EINVAL;
3682+ goto out;
3683+ }
3684+
3685+ file = fget(fd);
3686+ if (!file) {
3687+ ret = -EBADF;
3688+ goto out;
3689+ }
3690+
3691+ ret = do_sys_od_open(file, type, obj_id, config);
3692+
3693+ fput(file);
3694+
3695+out:
3696+ return ret;
3697+}
3698+
3699+
3700+asmlinkage int sys_od_close(int od)
3701+{
3702+ int ret = -EINVAL;
3703+ struct task_struct *t = current;
3704+
3705+ if (od < 0 || od >= MAX_OBJECT_DESCRIPTORS)
3706+ return ret;
3707+
3708+ if (!t->od_table || !t->od_table[od].used)
3709+ return ret;
3710+
3711+
3712+ /* give the class a chance to reject the close
3713+ */
3714+ ret = fdso_close(t->od_table + od);
3715+ if (ret == 0)
3716+ ret = put_od_entry(t->od_table + od);
3717+
3718+ return ret;
3719+}
3720diff --git a/litmus/fmlp.c b/litmus/fmlp.c
3721new file mode 100644
3722index 0000000..820af8e
3723--- /dev/null
3724+++ b/litmus/fmlp.c
3725@@ -0,0 +1,262 @@
3726+/*
3727+ * FMLP implementation.
3728+ * Much of the code here is borrowed from include/asm-i386/semaphore.h.
3729+ */
3730+
3731+#include <asm/atomic.h>
3732+#include <asm/semaphore.h>
3733+#include <linux/sched.h>
3734+#include <linux/wait.h>
3735+#include <linux/spinlock.h>
3736+#include <litmus/litmus.h>
3737+#include <litmus/sched_plugin.h>
3738+#include <litmus/edf_common.h>
3739+
3740+#include <litmus/fdso.h>
3741+
3742+#include <litmus/trace.h>
3743+
3744+#ifdef CONFIG_FMLP
3745+
3746+static void* create_fmlp_semaphore(void)
3747+{
3748+ struct pi_semaphore* sem;
3749+ int i;
3750+
3751+ sem = kmalloc(sizeof(*sem), GFP_KERNEL);
3752+ if (!sem)
3753+ return NULL;
3754+ atomic_set(&sem->count, 1);
3755+ sem->sleepers = 0;
3756+ init_waitqueue_head(&sem->wait);
3757+ sem->hp.task = NULL;
3758+ sem->holder = NULL;
3759+ for (i = 0; i < NR_CPUS; i++)
3760+ sem->hp.cpu_task[i] = NULL;
3761+ return sem;
3762+}
3763+
3764+static int open_fmlp_semaphore(struct od_table_entry* entry, void* __user arg)
3765+{
3766+ if (!fmlp_active())
3767+ return -EBUSY;
3768+ return 0;
3769+}
3770+
3771+static void destroy_fmlp_semaphore(void* sem)
3772+{
3773+ /* XXX assert invariants */
3774+ kfree(sem);
3775+}
3776+
3777+struct fdso_ops fmlp_sem_ops = {
3778+ .create = create_fmlp_semaphore,
3779+ .open = open_fmlp_semaphore,
3780+ .destroy = destroy_fmlp_semaphore
3781+};
3782+
3783+struct wq_pair {
3784+ struct task_struct* tsk;
3785+ struct pi_semaphore* sem;
3786+};
3787+
3788+static int rt_pi_wake_up(wait_queue_t *wait, unsigned mode, int sync,
3789+ void *key)
3790+{
3791+ struct wq_pair* wqp = (struct wq_pair*) wait->private;
3792+ set_rt_flags(wqp->tsk, RT_F_EXIT_SEM);
3793+ litmus->inherit_priority(wqp->sem, wqp->tsk);
3794+ TRACE_TASK(wqp->tsk,
3795+ "woken up by rt_pi_wake_up() (RT_F_SEM_EXIT, PI)\n");
3796+ /* point to task for default_wake_function() */
3797+ wait->private = wqp->tsk;
3798+ default_wake_function(wait, mode, sync, key);
3799+
3800+ /* Always return true since we know that if we encountered a task
3801+ * that was already running the wake_up raced with the schedule in
3802+ * rt_pi_down(). In that case the task in rt_pi_down() will be scheduled
3803+ * immediately and own the lock. We must not wake up another task in
3804+ * any case.
3805+ */
3806+ return 1;
3807+}
3808+
3809+/* caller is responsible for locking */
3810+int edf_set_hp_task(struct pi_semaphore *sem)
3811+{
3812+ struct list_head *tmp, *next;
3813+ struct task_struct *queued;
3814+ int ret = 0;
3815+
3816+ sem->hp.task = NULL;
3817+ list_for_each_safe(tmp, next, &sem->wait.task_list) {
3818+ queued = ((struct wq_pair*)
3819+ list_entry(tmp, wait_queue_t,
3820+ task_list)->private)->tsk;
3821+
3822+ /* Compare task prios, find high prio task. */
3823+ if (edf_higher_prio(queued, sem->hp.task)) {
3824+ sem->hp.task = queued;
3825+ ret = 1;
3826+ }
3827+ }
3828+ return ret;
3829+}
3830+
3831+/* caller is responsible for locking */
3832+int edf_set_hp_cpu_task(struct pi_semaphore *sem, int cpu)
3833+{
3834+ struct list_head *tmp, *next;
3835+ struct task_struct *queued;
3836+ int ret = 0;
3837+
3838+ sem->hp.cpu_task[cpu] = NULL;
3839+ list_for_each_safe(tmp, next, &sem->wait.task_list) {
3840+ queued = ((struct wq_pair*)
3841+ list_entry(tmp, wait_queue_t,
3842+ task_list)->private)->tsk;
3843+
3844+ /* Compare task prios, find high prio task. */
3845+ if (get_partition(queued) == cpu &&
3846+ edf_higher_prio(queued, sem->hp.cpu_task[cpu])) {
3847+ sem->hp.cpu_task[cpu] = queued;
3848+ ret = 1;
3849+ }
3850+ }
3851+ return ret;
3852+}
3853+
3854+static int do_fmlp_down(struct pi_semaphore* sem)
3855+{
3856+ unsigned long flags;
3857+ struct task_struct *tsk = current;
3858+ struct wq_pair pair;
3859+ int suspended = 1;
3860+ wait_queue_t wait = {
3861+ .private = &pair,
3862+ .func = rt_pi_wake_up,
3863+ .task_list = {NULL, NULL}
3864+ };
3865+
3866+ pair.tsk = tsk;
3867+ pair.sem = sem;
3868+ spin_lock_irqsave(&sem->wait.lock, flags);
3869+
3870+ if (atomic_dec_return(&sem->count) < 0 ||
3871+ waitqueue_active(&sem->wait)) {
3872+ /* we need to suspend */
3873+ tsk->state = TASK_UNINTERRUPTIBLE;
3874+ add_wait_queue_exclusive_locked(&sem->wait, &wait);
3875+
3876+ TRACE_CUR("suspends on PI lock %p\n", sem);
3877+ litmus->pi_block(sem, tsk);
3878+
3879+ /* release lock before sleeping */
3880+ spin_unlock_irqrestore(&sem->wait.lock, flags);
3881+
3882+ TS_PI_DOWN_END;
3883+ preempt_enable_no_resched();
3884+
3885+
3886+ /* we depend on the FIFO order
3887+ * Thus, we don't need to recheck when we wake up, we
3888+ * are guaranteed to have the lock since there is only one
3889+ * wake up per release
3890+ */
3891+ schedule();
3892+
3893+ TRACE_CUR("woke up, now owns PI lock %p\n", sem);
3894+
3895+ /* try_to_wake_up() set our state to TASK_RUNNING,
3896+ * all we need to do is to remove our wait queue entry
3897+ */
3898+ remove_wait_queue(&sem->wait, &wait);
3899+ } else {
3900+ /* no priority inheritance necessary, since there are no queued
3901+ * tasks.
3902+ */
3903+ suspended = 0;
3904+ TRACE_CUR("acquired PI lock %p, no contention\n", sem);
3905+ sem->holder = tsk;
3906+ sem->hp.task = tsk;
3907+ litmus->inherit_priority(sem, tsk);
3908+ spin_unlock_irqrestore(&sem->wait.lock, flags);
3909+ }
3910+ return suspended;
3911+}
3912+
3913+static void do_fmlp_up(struct pi_semaphore* sem)
3914+{
3915+ unsigned long flags;
3916+
3917+ spin_lock_irqsave(&sem->wait.lock, flags);
3918+
3919+ TRACE_CUR("releases PI lock %p\n", sem);
3920+ litmus->return_priority(sem);
3921+ sem->holder = NULL;
3922+ if (atomic_inc_return(&sem->count) < 1)
3923+ /* there is a task queued */
3924+ wake_up_locked(&sem->wait);
3925+
3926+ spin_unlock_irqrestore(&sem->wait.lock, flags);
3927+}
3928+
3929+asmlinkage long sys_fmlp_down(int sem_od)
3930+{
3931+ long ret = 0;
3932+ struct pi_semaphore * sem;
3933+ int suspended = 0;
3934+
3935+ preempt_disable();
3936+ TS_PI_DOWN_START;
3937+
3938+ sem = lookup_fmlp_sem(sem_od);
3939+ if (sem)
3940+ suspended = do_fmlp_down(sem);
3941+ else
3942+ ret = -EINVAL;
3943+
3944+ if (!suspended) {
3945+ TS_PI_DOWN_END;
3946+ preempt_enable();
3947+ }
3948+
3949+ return ret;
3950+}
3951+
3952+asmlinkage long sys_fmlp_up(int sem_od)
3953+{
3954+ long ret = 0;
3955+ struct pi_semaphore * sem;
3956+
3957+ preempt_disable();
3958+ TS_PI_UP_START;
3959+
3960+ sem = lookup_fmlp_sem(sem_od);
3961+ if (sem)
3962+ do_fmlp_up(sem);
3963+ else
3964+ ret = -EINVAL;
3965+
3966+
3967+ TS_PI_UP_END;
3968+ preempt_enable();
3969+
3970+ return ret;
3971+}
3972+
3973+#else
3974+
3975+struct fdso_ops fmlp_sem_ops = {};
3976+
3977+asmlinkage long sys_fmlp_down(int sem_od)
3978+{
3979+ return -ENOSYS;
3980+}
3981+
3982+asmlinkage long sys_fmlp_up(int sem_od)
3983+{
3984+ return -ENOSYS;
3985+}
3986+
3987+#endif
3988diff --git a/litmus/ft_event.c b/litmus/ft_event.c
3989new file mode 100644
3990index 0000000..6084b6d
3991--- /dev/null
3992+++ b/litmus/ft_event.c
3993@@ -0,0 +1,43 @@
3994+#include <linux/types.h>
3995+
3996+#include <litmus/feather_trace.h>
3997+
3998+#ifndef __ARCH_HAS_FEATHER_TRACE
3999+/* provide dummy implementation */
4000+
4001+int ft_events[MAX_EVENTS];
4002+
4003+int ft_enable_event(unsigned long id)
4004+{
4005+ if (id < MAX_EVENTS) {
4006+ ft_events[id]++;
4007+ return 1;
4008+ } else
4009+ return 0;
4010+}
4011+
4012+int ft_disable_event(unsigned long id)
4013+{
4014+ if (id < MAX_EVENTS && ft_events[id]) {
4015+ ft_events[id]--;
4016+ return 1;
4017+ } else
4018+ return 0;
4019+}
4020+
4021+int ft_disable_all_events(void)
4022+{
4023+ int i;
4024+
4025+ for (i = 0; i < MAX_EVENTS; i++)
4026+ ft_events[i] = 0;
4027+
4028+ return MAX_EVENTS;
4029+}
4030+
4031+int ft_is_event_enabled(unsigned long id)
4032+{
4033+ return id < MAX_EVENTS && ft_events[id];
4034+}
4035+
4036+#endif
4037diff --git a/litmus/ftdev.c b/litmus/ftdev.c
4038new file mode 100644
4039index 0000000..1c1c241
4040--- /dev/null
4041+++ b/litmus/ftdev.c
4042@@ -0,0 +1,352 @@
4043+#include <linux/sched.h>
4044+#include <linux/fs.h>
4045+#include <linux/cdev.h>
4046+#include <asm/uaccess.h>
4047+#include <linux/module.h>
4048+
4049+#include <litmus/litmus.h>
4050+#include <litmus/feather_trace.h>
4051+#include <litmus/ftdev.h>
4052+
4053+struct ft_buffer* alloc_ft_buffer(unsigned int count, size_t size)
4054+{
4055+ struct ft_buffer* buf;
4056+ size_t total = (size + 1) * count;
4057+ char* mem;
4058+ int order = 0, pages = 1;
4059+
4060+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
4061+ if (!buf)
4062+ return NULL;
4063+
4064+ total = (total / PAGE_SIZE) + (total % PAGE_SIZE != 0);
4065+ while (pages < total) {
4066+ order++;
4067+ pages *= 2;
4068+ }
4069+
4070+ mem = (char*) __get_free_pages(GFP_KERNEL, order);
4071+ if (!mem) {
4072+ kfree(buf);
4073+ return NULL;
4074+ }
4075+
4076+ if (!init_ft_buffer(buf, count, size,
4077+ mem + (count * size), /* markers at the end */
4078+ mem)) { /* buffer objects */
4079+ free_pages((unsigned long) mem, order);
4080+ kfree(buf);
4081+ return NULL;
4082+ }
4083+ return buf;
4084+}
4085+
4086+void free_ft_buffer(struct ft_buffer* buf)
4087+{
4088+ int order = 0, pages = 1;
4089+ size_t total;
4090+
4091+ if (buf) {
4092+ total = (buf->slot_size + 1) * buf->slot_count;
4093+ total = (total / PAGE_SIZE) + (total % PAGE_SIZE != 0);
4094+ while (pages < total) {
4095+ order++;
4096+ pages *= 2;
4097+ }
4098+ free_pages((unsigned long) buf->buffer_mem, order);
4099+ kfree(buf);
4100+ }
4101+}
4102+
4103+struct ftdev_event {
4104+ int id;
4105+ struct ftdev_event* next;
4106+};
4107+
4108+static int activate(struct ftdev_event** chain, int id)
4109+{
4110+ struct ftdev_event* ev = kmalloc(sizeof(*ev), GFP_KERNEL);
4111+ if (ev) {
4112+ printk(KERN_INFO
4113+ "Enabling feather-trace event %d.\n", (int) id);
4114+ ft_enable_event(id);
4115+ ev->id = id;
4116+ ev->next = *chain;
4117+ *chain = ev;
4118+ }
4119+ return ev ? 0 : -ENOMEM;
4120+}
4121+
4122+static void deactivate(struct ftdev_event** chain, int id)
4123+{
4124+ struct ftdev_event **cur = chain;
4125+ struct ftdev_event *nxt;
4126+ while (*cur) {
4127+ if ((*cur)->id == id) {
4128+ nxt = (*cur)->next;
4129+ kfree(*cur);
4130+ *cur = nxt;
4131+ printk(KERN_INFO
4132+ "Disabling feather-trace event %d.\n", (int) id);
4133+ ft_disable_event(id);
4134+ break;
4135+ }
4136+ cur = &(*cur)->next;
4137+ }
4138+}
4139+
4140+static int ftdev_open(struct inode *in, struct file *filp)
4141+{
4142+ struct ftdev* ftdev;
4143+ struct ftdev_minor* ftdm;
4144+ unsigned int buf_idx = iminor(in);
4145+ int err = 0;
4146+
4147+ ftdev = container_of(in->i_cdev, struct ftdev, cdev);
4148+
4149+ if (buf_idx >= ftdev->minor_cnt) {
4150+ err = -ENODEV;
4151+ goto out;
4152+ }
4153+ if (ftdev->can_open && (err = ftdev->can_open(ftdev, buf_idx)))
4154+ goto out;
4155+
4156+ ftdm = ftdev->minor + buf_idx;
4157+ filp->private_data = ftdm;
4158+
4159+ if (mutex_lock_interruptible(&ftdm->lock)) {
4160+ err = -ERESTARTSYS;
4161+ goto out;
4162+ }
4163+
4164+ if (!ftdm->readers && ftdev->alloc)
4165+ err = ftdev->alloc(ftdev, buf_idx);
4166+ if (0 == err)
4167+ ftdm->readers++;
4168+
4169+ mutex_unlock(&ftdm->lock);
4170+out:
4171+ return err;
4172+}
4173+
4174+static int ftdev_release(struct inode *in, struct file *filp)
4175+{
4176+ struct ftdev* ftdev;
4177+ struct ftdev_minor* ftdm;
4178+ unsigned int buf_idx = iminor(in);
4179+ int err = 0;
4180+
4181+ ftdev = container_of(in->i_cdev, struct ftdev, cdev);
4182+
4183+ if (buf_idx >= ftdev->minor_cnt) {
4184+ err = -ENODEV;
4185+ goto out;
4186+ }
4187+ ftdm = ftdev->minor + buf_idx;
4188+
4189+ if (mutex_lock_interruptible(&ftdm->lock)) {
4190+ err = -ERESTARTSYS;
4191+ goto out;
4192+ }
4193+
4194+ if (ftdm->readers == 1) {
4195+ while (ftdm->events)
4196+ deactivate(&ftdm->events, ftdm->events->id);
4197+
4198+ /* wait for any pending events to complete */
4199+ set_current_state(TASK_UNINTERRUPTIBLE);
4200+ schedule_timeout(HZ);
4201+
4202+ printk(KERN_ALERT "Failed trace writes: %u\n",
4203+ ftdm->buf->failed_writes);
4204+
4205+ if (ftdev->free)
4206+ ftdev->free(ftdev, buf_idx);
4207+ }
4208+
4209+ ftdm->readers--;
4210+ mutex_unlock(&ftdm->lock);
4211+out:
4212+ return err;
4213+}
4214+
4215+/* based on ft_buffer_read
4216+ * @returns < 0 : page fault
4217+ * = 0 : no data available
4218+ * = 1 : one slot copied
4219+ */
4220+static int ft_buffer_copy_to_user(struct ft_buffer* buf, char __user *dest)
4221+{
4222+ unsigned int idx;
4223+ int err = 0;
4224+ if (buf->free_count != buf->slot_count) {
4225+ /* data available */
4226+ idx = buf->read_idx % buf->slot_count;
4227+ if (buf->slots[idx] == SLOT_READY) {
4228+ err = copy_to_user(dest, ((char*) buf->buffer_mem) +
4229+ idx * buf->slot_size,
4230+ buf->slot_size);
4231+ if (err == 0) {
4232+ /* copy ok */
4233+ buf->slots[idx] = SLOT_FREE;
4234+ buf->read_idx++;
4235+ fetch_and_inc(&buf->free_count);
4236+ err = 1;
4237+ }
4238+ }
4239+ }
4240+ return err;
4241+}
4242+
4243+static ssize_t ftdev_read(struct file *filp,
4244+ char __user *to, size_t len, loff_t *f_pos)
4245+{
4246+ /* we ignore f_pos, this is strictly sequential */
4247+
4248+ ssize_t err = 0;
4249+ size_t chunk;
4250+ int copied;
4251+ struct ftdev_minor* ftdm = filp->private_data;
4252+
4253+ if (mutex_lock_interruptible(&ftdm->lock)) {
4254+ err = -ERESTARTSYS;
4255+ goto out;
4256+ }
4257+
4258+
4259+ chunk = ftdm->buf->slot_size;
4260+ while (len >= chunk) {
4261+ copied = ft_buffer_copy_to_user(ftdm->buf, to);
4262+ if (copied == 1) {
4263+ len -= chunk;
4264+ to += chunk;
4265+ err += chunk;
4266+ } else if (err == 0 && copied == 0 && ftdm->events) {
4267+ /* Only wait if there are any events enabled and only
4268+ * if we haven't copied some data yet. We cannot wait
4269+ * here with copied data because that data would get
4270+ * lost if the task is interrupted (e.g., killed).
4271+ */
4272+ set_current_state(TASK_INTERRUPTIBLE);
4273+ schedule_timeout(50);
4274+ if (signal_pending(current)) {
4275+ if (err == 0)
4276+ /* nothing read yet, signal problem */
4277+ err = -ERESTARTSYS;
4278+ break;
4279+ }
4280+ } else if (copied < 0) {
4281+ /* page fault */
4282+ err = copied;
4283+ break;
4284+ } else
4285+ /* nothing left to get, return to user space */
4286+ break;
4287+ }
4288+ mutex_unlock(&ftdm->lock);
4289+out:
4290+ return err;
4291+}
4292+
4293+typedef uint32_t cmd_t;
4294+
4295+static ssize_t ftdev_write(struct file *filp, const char __user *from,
4296+ size_t len, loff_t *f_pos)
4297+{
4298+ struct ftdev_minor* ftdm = filp->private_data;
4299+ ssize_t err = -EINVAL;
4300+ cmd_t cmd;
4301+ cmd_t id;
4302+
4303+ if (len % sizeof(cmd) || len < 2 * sizeof(cmd))
4304+ goto out;
4305+
4306+ if (copy_from_user(&cmd, from, sizeof(cmd))) {
4307+ err = -EFAULT;
4308+ goto out;
4309+ }
4310+ len -= sizeof(cmd);
4311+ from += sizeof(cmd);
4312+
4313+ if (cmd != FTDEV_ENABLE_CMD && cmd != FTDEV_DISABLE_CMD)
4314+ goto out;
4315+
4316+ if (mutex_lock_interruptible(&ftdm->lock)) {
4317+ err = -ERESTARTSYS;
4318+ goto out;
4319+ }
4320+
4321+ err = sizeof(cmd);
4322+ while (len) {
4323+ if (copy_from_user(&id, from, sizeof(cmd))) {
4324+ err = -EFAULT;
4325+ goto out_unlock;
4326+ }
4327+ /* FIXME: check id against list of acceptable events */
4328+ len -= sizeof(cmd);
4329+ from += sizeof(cmd);
4330+ if (cmd == FTDEV_DISABLE_CMD)
4331+ deactivate(&ftdm->events, id);
4332+ else if (activate(&ftdm->events, id) != 0) {
4333+ err = -ENOMEM;
4334+ goto out_unlock;
4335+ }
4336+ err += sizeof(cmd);
4337+ }
4338+
4339+out_unlock:
4340+ mutex_unlock(&ftdm->lock);
4341+out:
4342+ return err;
4343+}
4344+
4345+struct file_operations ftdev_fops = {
4346+ .owner = THIS_MODULE,
4347+ .open = ftdev_open,
4348+ .release = ftdev_release,
4349+ .write = ftdev_write,
4350+ .read = ftdev_read,
4351+};
4352+
4353+
4354+void ftdev_init(struct ftdev* ftdev, struct module* owner)
4355+{
4356+ int i;
4357+ cdev_init(&ftdev->cdev, &ftdev_fops);
4358+ ftdev->cdev.owner = owner;
4359+ ftdev->cdev.ops = &ftdev_fops;
4360+ ftdev->minor_cnt = 0;
4361+ for (i = 0; i < MAX_FTDEV_MINORS; i++) {
4362+ mutex_init(&ftdev->minor[i].lock);
4363+ ftdev->minor[i].readers = 0;
4364+ ftdev->minor[i].buf = NULL;
4365+ ftdev->minor[i].events = NULL;
4366+ }
4367+ ftdev->alloc = NULL;
4368+ ftdev->free = NULL;
4369+ ftdev->can_open = NULL;
4370+}
4371+
4372+int register_ftdev(struct ftdev* ftdev, const char* name, int major)
4373+{
4374+ dev_t trace_dev;
4375+ int error = 0;
4376+
4377+ trace_dev = MKDEV(major, 0);
4378+ error = register_chrdev_region(trace_dev, ftdev->minor_cnt, name);
4379+ if (error)
4380+ {
4381+ printk(KERN_WARNING "ftdev(%s): "
4382+ "Could not register major/minor number %d/%u\n",
4383+ name, major, ftdev->minor_cnt);
4384+ return error;
4385+ }
4386+ error = cdev_add(&ftdev->cdev, trace_dev, ftdev->minor_cnt);
4387+ if (error) {
4388+ printk(KERN_WARNING "ftdev(%s): "
4389+ "Could not add cdev for major/minor = %d/%u.\n",
4390+ name, major, ftdev->minor_cnt);
4391+ return error;
4392+ }
4393+ return error;
4394+}
4395diff --git a/litmus/heap.c b/litmus/heap.c
4396new file mode 100644
4397index 0000000..4d0d7b9
4398--- /dev/null
4399+++ b/litmus/heap.c
4400@@ -0,0 +1,287 @@
4401+#include "linux/kernel.h"
4402+#include "litmus/heap.h"
4403+
4404+void heap_init(struct heap* heap)
4405+{
4406+ heap->head = NULL;
4407+ heap->min = NULL;
4408+}
4409+
4410+void heap_node_init(struct heap_node** _h, void* value)
4411+{
4412+ struct heap_node* h = *_h;
4413+ h->parent = NULL;
4414+ h->next = NULL;
4415+ h->child = NULL;
4416+ h->degree = NOT_IN_HEAP;
4417+ h->value = value;
4418+ h->ref = _h;
4419+}
4420+
4421+
4422+/* make child a subtree of root */
4423+static void __heap_link(struct heap_node* root,
4424+ struct heap_node* child)
4425+{
4426+ child->parent = root;
4427+ child->next = root->child;
4428+ root->child = child;
4429+ root->degree++;
4430+}
4431+
4432+/* merge root lists */
4433+static struct heap_node* __heap_merge(struct heap_node* a,
4434+ struct heap_node* b)
4435+{
4436+ struct heap_node* head = NULL;
4437+ struct heap_node** pos = &head;
4438+
4439+ while (a && b) {
4440+ if (a->degree < b->degree) {
4441+ *pos = a;
4442+ a = a->next;
4443+ } else {
4444+ *pos = b;
4445+ b = b->next;
4446+ }
4447+ pos = &(*pos)->next;
4448+ }
4449+ if (a)
4450+ *pos = a;
4451+ else
4452+ *pos = b;
4453+ return head;
4454+}
4455+
4456+/* reverse a linked list of nodes. also clears parent pointer */
4457+static struct heap_node* __heap_reverse(struct heap_node* h)
4458+{
4459+ struct heap_node* tail = NULL;
4460+ struct heap_node* next;
4461+
4462+ if (!h)
4463+ return h;
4464+
4465+ h->parent = NULL;
4466+ while (h->next) {
4467+ next = h->next;
4468+ h->next = tail;
4469+ tail = h;
4470+ h = next;
4471+ h->parent = NULL;
4472+ }
4473+ h->next = tail;
4474+ return h;
4475+}
4476+
4477+static void __heap_min(heap_prio_t higher_prio, struct heap* heap,
4478+ struct heap_node** prev, struct heap_node** node)
4479+{
4480+ struct heap_node *_prev, *cur;
4481+ *prev = NULL;
4482+
4483+ if (!heap->head) {
4484+ *node = NULL;
4485+ return;
4486+ }
4487+
4488+ *node = heap->head;
4489+ _prev = heap->head;
4490+ cur = heap->head->next;
4491+ while (cur) {
4492+ if (higher_prio(cur, *node)) {
4493+ *node = cur;
4494+ *prev = _prev;
4495+ }
4496+ _prev = cur;
4497+ cur = cur->next;
4498+ }
4499+}
4500+
4501+static void __heap_union(heap_prio_t higher_prio, struct heap* heap,
4502+ struct heap_node* h2)
4503+{
4504+ struct heap_node* h1;
4505+ struct heap_node *prev, *x, *next;
4506+ if (!h2)
4507+ return;
4508+ h1 = heap->head;
4509+ if (!h1) {
4510+ heap->head = h2;
4511+ return;
4512+ }
4513+ h1 = __heap_merge(h1, h2);
4514+ prev = NULL;
4515+ x = h1;
4516+ next = x->next;
4517+ while (next) {
4518+ if (x->degree != next->degree ||
4519+ (next->next && next->next->degree == x->degree)) {
4520+ /* nothing to do, advance */
4521+ prev = x;
4522+ x = next;
4523+ } else if (higher_prio(x, next)) {
4524+ /* x becomes the root of next */
4525+ x->next = next->next;
4526+ __heap_link(x, next);
4527+ } else {
4528+ /* next becomes the root of x */
4529+ if (prev)
4530+ prev->next = next;
4531+ else
4532+ h1 = next;
4533+ __heap_link(next, x);
4534+ x = next;
4535+ }
4536+ next = x->next;
4537+ }
4538+ heap->head = h1;
4539+}
4540+
4541+static struct heap_node* __heap_extract_min(heap_prio_t higher_prio,
4542+ struct heap* heap)
4543+{
4544+ struct heap_node *prev, *node;
4545+ __heap_min(higher_prio, heap, &prev, &node);
4546+ if (!node)
4547+ return NULL;
4548+ if (prev)
4549+ prev->next = node->next;
4550+ else
4551+ heap->head = node->next;
4552+ __heap_union(higher_prio, heap, __heap_reverse(node->child));
4553+ return node;
4554+}
4555+
4556+/* insert (and reinitialize) a node into the heap */
4557+void heap_insert(heap_prio_t higher_prio, struct heap* heap,
4558+ struct heap_node* node)
4559+{
4560+ struct heap_node *min;
4561+ node->child = NULL;
4562+ node->parent = NULL;
4563+ node->next = NULL;
4564+ node->degree = 0;
4565+ if (heap->min && higher_prio(node, heap->min)) {
4566+ /* swap min cache */
4567+ min = heap->min;
4568+ min->child = NULL;
4569+ min->parent = NULL;
4570+ min->next = NULL;
4571+ min->degree = 0;
4572+ __heap_union(higher_prio, heap, min);
4573+ heap->min = node;
4574+ } else
4575+ __heap_union(higher_prio, heap, node);
4576+}
4577+
4578+static void __uncache_min(heap_prio_t higher_prio, struct heap* heap)
4579+{
4580+ struct heap_node* min;
4581+ if (heap->min) {
4582+ min = heap->min;
4583+ heap->min = NULL;
4584+ heap_insert(higher_prio, heap, min);
4585+ }
4586+}
4587+
4588+/* merge addition into target */
4589+void heap_union(heap_prio_t higher_prio,
4590+ struct heap* target, struct heap* addition)
4591+{
4592+ /* first insert any cached minima, if necessary */
4593+ __uncache_min(higher_prio, target);
4594+ __uncache_min(higher_prio, addition);
4595+ __heap_union(higher_prio, target, addition->head);
4596+ /* this is a destructive merge */
4597+ addition->head = NULL;
4598+}
4599+
4600+struct heap_node* heap_peek(heap_prio_t higher_prio,
4601+ struct heap* heap)
4602+{
4603+ if (!heap->min)
4604+ heap->min = __heap_extract_min(higher_prio, heap);
4605+ return heap->min;
4606+}
4607+
4608+struct heap_node* heap_take(heap_prio_t higher_prio,
4609+ struct heap* heap)
4610+{
4611+ struct heap_node *node;
4612+ if (!heap->min)
4613+ heap->min = __heap_extract_min(higher_prio, heap);
4614+ node = heap->min;
4615+ heap->min = NULL;
4616+ if (node)
4617+ node->degree = NOT_IN_HEAP;
4618+ return node;
4619+}
4620+
4621+void heap_delete(heap_prio_t higher_prio, struct heap* heap,
4622+ struct heap_node* node)
4623+{
4624+ struct heap_node *parent, *prev, *pos;
4625+ struct heap_node** tmp_ref;
4626+ void* tmp;
4627+
4628+ if (heap->min != node) {
4629+ /* bubble up */
4630+ parent = node->parent;
4631+ while (parent) {
4632+ /* swap parent and node */
4633+ tmp = parent->value;
4634+ parent->value = node->value;
4635+ node->value = tmp;
4636+ /* swap references */
4637+ *(parent->ref) = node;
4638+ *(node->ref) = parent;
4639+ tmp_ref = parent->ref;
4640+ parent->ref = node->ref;
4641+ node->ref = tmp_ref;
4642+ /* step up */
4643+ node = parent;
4644+ parent = node->parent;
4645+ }
4646+ /* now delete:
4647+ * first find prev */
4648+ prev = NULL;
4649+ pos = heap->head;
4650+ while (pos != node) {
4651+ prev = pos;
4652+ pos = pos->next;
4653+ }
4654+ /* we have prev, now remove node */
4655+ if (prev)
4656+ prev->next = node->next;
4657+ else
4658+ heap->head = node->next;
4659+ __heap_union(higher_prio, heap, __heap_reverse(node->child));
4660+ } else
4661+ heap->min = NULL;
4662+ node->degree = NOT_IN_HEAP;
4663+}
4664+
4665+/* allocate a heap node for value and insert into the heap */
4666+int heap_add(heap_prio_t higher_prio, struct heap* heap,
4667+ void* value, int gfp_flags)
4668+{
4669+ struct heap_node* hn = heap_node_alloc(gfp_flags);
4670+ if (likely(hn)) {
4671+ heap_node_init(&hn, value);
4672+ heap_insert(higher_prio, heap, hn);
4673+ }
4674+ return hn != NULL;
4675+}
4676+
4677+void* heap_take_del(heap_prio_t higher_prio,
4678+ struct heap* heap)
4679+{
4680+ struct heap_node* hn = heap_take(higher_prio, heap);
4681+ void* ret = NULL;
4682+ if (hn) {
4683+ ret = hn->value;
4684+ heap_node_free(hn);
4685+ }
4686+ return ret;
4687+}
4688diff --git a/litmus/jobs.c b/litmus/jobs.c
4689new file mode 100644
4690index 0000000..e294bc5
4691--- /dev/null
4692+++ b/litmus/jobs.c
4693@@ -0,0 +1,43 @@
4694+/* litmus/jobs.c - common job control code
4695+ */
4696+
4697+#include <linux/sched.h>
4698+
4699+#include <litmus/litmus.h>
4700+#include <litmus/jobs.h>
4701+
4702+void prepare_for_next_period(struct task_struct *t)
4703+{
4704+ BUG_ON(!t);
4705+ /* prepare next release */
4706+ t->rt_param.job_params.release = t->rt_param.job_params.deadline;
4707+ t->rt_param.job_params.deadline += get_rt_period(t);
4708+ t->rt_param.job_params.exec_time = 0;
4709+ /* update job sequence number */
4710+ t->rt_param.job_params.job_no++;
4711+
4712+ /* don't confuse Linux */
4713+ t->time_slice = 1;
4714+}
4715+
4716+void release_at(struct task_struct *t, lt_t start)
4717+{
4718+ t->rt_param.job_params.deadline = start;
4719+ prepare_for_next_period(t);
4720+ set_rt_flags(t, RT_F_RUNNING);
4721+}
4722+
4723+
4724+/*
4725+ * Deactivate current task until the beginning of the next period.
4726+ */
4727+long complete_job(void)
4728+{
4729+ /* Mark that we do not excute anymore */
4730+ set_rt_flags(current, RT_F_SLEEP);
4731+ /* call schedule, this will return when a new job arrives
4732+ * it also takes care of preparing for the next release
4733+ */
4734+ schedule();
4735+ return 0;
4736+}
4737diff --git a/litmus/litmus.c b/litmus/litmus.c
4738new file mode 100644
4739index 0000000..3562322
4740--- /dev/null
4741+++ b/litmus/litmus.c
4742@@ -0,0 +1,913 @@
4743+/* litmus.c -- Implementation of the LITMUS syscalls, the LITMUS intialization code,
4744+ * and the procfs interface..
4745+ */
4746+#include <asm/uaccess.h>
4747+#include <linux/uaccess.h>
4748+#include <linux/sysrq.h>
4749+
4750+#include <linux/module.h>
4751+#include <linux/proc_fs.h>
4752+#include <linux/slab.h>
4753+
4754+#include <litmus/litmus.h>
4755+#include <linux/sched.h>
4756+#include <litmus/sched_plugin.h>
4757+
4758+#include <litmus/heap.h>
4759+
4760+#include <litmus/trace.h>
4761+
4762+#include <litmus/rt_domain.h>
4763+
4764+/* Number of RT tasks that exist in the system */
4765+atomic_t rt_task_count = ATOMIC_INIT(0);
4766+static DEFINE_SPINLOCK(task_transition_lock);
4767+
4768+/* Give log messages sequential IDs. */
4769+atomic_t __log_seq_no = ATOMIC_INIT(0);
4770+
4771+/* current master CPU for handling timer IRQs */
4772+atomic_t release_master_cpu = ATOMIC_INIT(NO_CPU);
4773+
4774+/* To send signals from the scheduler
4775+ * Must drop locks first.
4776+ */
4777+static LIST_HEAD(sched_sig_list);
4778+static DEFINE_SPINLOCK(sched_sig_list_lock);
4779+
4780+static struct kmem_cache * heap_node_cache;
4781+extern struct kmem_cache * release_heap_cache;
4782+
4783+struct heap_node* heap_node_alloc(int gfp_flags)
4784+{
4785+ return kmem_cache_alloc(heap_node_cache, gfp_flags);
4786+}
4787+
4788+void heap_node_free(struct heap_node* hn)
4789+{
4790+ kmem_cache_free(heap_node_cache, hn);
4791+}
4792+
4793+struct release_heap* release_heap_alloc(int gfp_flags);
4794+void release_heap_free(struct release_heap* rh);
4795+
4796+/*
4797+ * sys_set_task_rt_param
4798+ * @pid: Pid of the task which scheduling parameters must be changed
4799+ * @param: New real-time extension parameters such as the execution cost and
4800+ * period
4801+ * Syscall for manipulating with task rt extension params
4802+ * Returns EFAULT if param is NULL.
4803+ * ESRCH if pid is not corrsponding
4804+ * to a valid task.
4805+ * EINVAL if either period or execution cost is <=0
4806+ * EPERM if pid is a real-time task
4807+ * 0 if success
4808+ *
4809+ * Only non-real-time tasks may be configured with this system call
4810+ * to avoid races with the scheduler. In practice, this means that a
4811+ * task's parameters must be set _before_ calling sys_prepare_rt_task()
4812+ */
4813+asmlinkage long sys_set_rt_task_param(pid_t pid, struct rt_task __user * param)
4814+{
4815+ struct rt_task tp;
4816+ struct task_struct *target;
4817+ int retval = -EINVAL;
4818+
4819+ printk("Setting up rt task parameters for process %d.\n", pid);
4820+
4821+ if (pid < 0 || param == 0) {
4822+ goto out;
4823+ }
4824+ if (copy_from_user(&tp, param, sizeof(tp))) {
4825+ retval = -EFAULT;
4826+ goto out;
4827+ }
4828+
4829+ /* Task search and manipulation must be protected */
4830+ read_lock_irq(&tasklist_lock);
4831+ if (!(target = find_task_by_pid(pid))) {
4832+ retval = -ESRCH;
4833+ goto out_unlock;
4834+ }
4835+
4836+ if (is_realtime(target)) {
4837+ /* The task is already a real-time task.
4838+ * We cannot not allow parameter changes at this point.
4839+ */
4840+ retval = -EBUSY;
4841+ goto out_unlock;
4842+ }
4843+
4844+ if (tp.exec_cost <= 0)
4845+ goto out_unlock;
4846+ if (tp.period <= 0)
4847+ goto out_unlock;
4848+ if (!cpu_online(tp.cpu))
4849+ goto out_unlock;
4850+ if (tp.period < tp.exec_cost)
4851+ {
4852+ printk(KERN_INFO "litmus: real-time task %d rejected "
4853+ "because wcet > period\n", pid);
4854+ goto out_unlock;
4855+ }
4856+
4857+ target->rt_param.task_params = tp;
4858+
4859+ retval = 0;
4860+ out_unlock:
4861+ read_unlock_irq(&tasklist_lock);
4862+ out:
4863+ return retval;
4864+}
4865+
4866+/* Getter of task's RT params
4867+ * returns EINVAL if param or pid is NULL
4868+ * returns ESRCH if pid does not correspond to a valid task
4869+ * returns EFAULT if copying of parameters has failed.
4870+ */
4871+asmlinkage long sys_get_rt_task_param(pid_t pid, struct rt_task __user * param)
4872+{
4873+ int retval = -EINVAL;
4874+ struct task_struct *source;
4875+ struct rt_task lp;
4876+ if (param == 0 || pid < 0)
4877+ goto out;
4878+ read_lock(&tasklist_lock);
4879+ if (!(source = find_task_by_pid(pid))) {
4880+ retval = -ESRCH;
4881+ goto out_unlock;
4882+ }
4883+ lp = source->rt_param.task_params;
4884+ read_unlock(&tasklist_lock);
4885+ /* Do copying outside the lock */
4886+ retval =
4887+ copy_to_user(param, &lp, sizeof(lp)) ? -EFAULT : 0;
4888+ return retval;
4889+ out_unlock:
4890+ read_unlock(&tasklist_lock);
4891+ out:
4892+ return retval;
4893+
4894+}
4895+
4896+/*
4897+ * This is the crucial function for periodic task implementation,
4898+ * It checks if a task is periodic, checks if such kind of sleep
4899+ * is permitted and calls plugin-specific sleep, which puts the
4900+ * task into a wait array.
4901+ * returns 0 on successful wakeup
4902+ * returns EPERM if current conditions do not permit such sleep
4903+ * returns EINVAL if current task is not able to go to sleep
4904+ */
4905+asmlinkage long sys_complete_job(void)
4906+{
4907+ int retval = -EPERM;
4908+ if (!is_realtime(current)) {
4909+ retval = -EINVAL;
4910+ goto out;
4911+ }
4912+ /* Task with negative or zero period cannot sleep */
4913+ if (get_rt_period(current) <= 0) {
4914+ retval = -EINVAL;
4915+ goto out;
4916+ }
4917+ /* The plugin has to put the task into an
4918+ * appropriate queue and call schedule
4919+ */
4920+ retval = litmus->complete_job();
4921+ out:
4922+ return retval;
4923+}
4924+
4925+/* This is an "improved" version of sys_complete_job that
4926+ * addresses the problem of unintentionally missing a job after
4927+ * an overrun.
4928+ *
4929+ * returns 0 on successful wakeup
4930+ * returns EPERM if current conditions do not permit such sleep
4931+ * returns EINVAL if current task is not able to go to sleep
4932+ */
4933+asmlinkage long sys_wait_for_job_release(unsigned int job)
4934+{
4935+ int retval = -EPERM;
4936+ if (!is_realtime(current)) {
4937+ retval = -EINVAL;
4938+ goto out;
4939+ }
4940+
4941+ /* Task with negative or zero period cannot sleep */
4942+ if (get_rt_period(current) <= 0) {
4943+ retval = -EINVAL;
4944+ goto out;
4945+ }
4946+
4947+ retval = 0;
4948+
4949+ /* first wait until we have "reached" the desired job
4950+ *
4951+ * This implementation has at least two problems:
4952+ *
4953+ * 1) It doesn't gracefully handle the wrap around of
4954+ * job_no. Since LITMUS is a prototype, this is not much
4955+ * of a problem right now.
4956+ *
4957+ * 2) It is theoretically racy if a job release occurs
4958+ * between checking job_no and calling sleep_next_period().
4959+ * A proper solution would requiring adding another callback
4960+ * in the plugin structure and testing the condition with
4961+ * interrupts disabled.
4962+ *
4963+ * FIXME: At least problem 2 should be taken care of eventually.
4964+ */
4965+ while (!retval && job > current->rt_param.job_params.job_no)
4966+ /* If the last job overran then job <= job_no and we
4967+ * don't send the task to sleep.
4968+ */
4969+ retval = litmus->complete_job();
4970+ out:
4971+ return retval;
4972+}
4973+
4974+/* This is a helper syscall to query the current job sequence number.
4975+ *
4976+ * returns 0 on successful query
4977+ * returns EPERM if task is not a real-time task.
4978+ * returns EFAULT if &job is not a valid pointer.
4979+ */
4980+asmlinkage long sys_query_job_no(unsigned int __user *job)
4981+{
4982+ int retval = -EPERM;
4983+ if (is_realtime(current))
4984+ retval = put_user(current->rt_param.job_params.job_no, job);
4985+
4986+ return retval;
4987+}
4988+
4989+struct sched_sig {
4990+ struct list_head list;
4991+ struct task_struct* task;
4992+ unsigned int signal:31;
4993+ int force:1;
4994+};
4995+
4996+static void __scheduler_signal(struct task_struct *t, unsigned int signo,
4997+ int force)
4998+{
4999+ struct sched_sig* sig;
5000+
5001+ sig = kmalloc(GFP_ATOMIC, sizeof(*sig));
5002+ if (!sig) {
5003+ TRACE_TASK(t, "dropping signal: %u\n", t);
5004+ return;
5005+ }
5006+
5007+ spin_lock(&sched_sig_list_lock);
5008+
5009+ sig->signal = signo;
5010+ sig->force = force;
5011+ sig->task = t;
5012+ get_task_struct(t);
5013+ list_add(&sig->list, &sched_sig_list);
5014+
5015+ spin_unlock(&sched_sig_list_lock);
5016+}
5017+
5018+void scheduler_signal(struct task_struct *t, unsigned int signo)
5019+{
5020+ __scheduler_signal(t, signo, 0);
5021+}
5022+
5023+void force_scheduler_signal(struct task_struct *t, unsigned int signo)
5024+{
5025+ __scheduler_signal(t, signo, 1);
5026+}
5027+
5028+/* FIXME: get rid of the locking and do this on a per-processor basis */
5029+void send_scheduler_signals(void)
5030+{
5031+ unsigned long flags;
5032+ struct list_head *p, *extra;
5033+ struct siginfo info;
5034+ struct sched_sig* sig;
5035+ struct task_struct* t;
5036+ struct list_head claimed;
5037+
5038+ if (spin_trylock_irqsave(&sched_sig_list_lock, flags)) {
5039+ if (list_empty(&sched_sig_list))
5040+ p = NULL;
5041+ else {
5042+ p = sched_sig_list.next;
5043+ list_del(&sched_sig_list);
5044+ INIT_LIST_HEAD(&sched_sig_list);
5045+ }
5046+ spin_unlock_irqrestore(&sched_sig_list_lock, flags);
5047+
5048+ /* abort if there are no signals */
5049+ if (!p)
5050+ return;
5051+
5052+ /* take signal list we just obtained */
5053+ list_add(&claimed, p);
5054+
5055+ list_for_each_safe(p, extra, &claimed) {
5056+ list_del(p);
5057+ sig = list_entry(p, struct sched_sig, list);
5058+ t = sig->task;
5059+ info.si_signo = sig->signal;
5060+ info.si_errno = 0;
5061+ info.si_code = SI_KERNEL;
5062+ info.si_pid = 1;
5063+ info.si_uid = 0;
5064+ TRACE("sending signal %d to %d\n", info.si_signo,
5065+ t->pid);
5066+ if (sig->force)
5067+ force_sig_info(sig->signal, &info, t);
5068+ else
5069+ send_sig_info(sig->signal, &info, t);
5070+ put_task_struct(t);
5071+ kfree(sig);
5072+ }
5073+ }
5074+
5075+}
5076+
5077+#ifdef CONFIG_NP_SECTION
5078+
5079+static inline void np_mem_error(struct task_struct* t, const char* reason)
5080+{
5081+ if (t->state != TASK_DEAD && !(t->flags & PF_EXITING)) {
5082+ TRACE("np section: %s => %s/%d killed\n",
5083+ reason, t->comm, t->pid);
5084+ force_scheduler_signal(t, SIGKILL);
5085+ }
5086+}
5087+
5088+/* sys_register_np_flag() allows real-time tasks to register an
5089+ * np section indicator.
5090+ * returns 0 if the flag was successfully registered
5091+ * returns EINVAL if current task is not a real-time task
5092+ * returns EFAULT if *flag couldn't be written
5093+ */
5094+asmlinkage long sys_register_np_flag(short __user *flag)
5095+{
5096+ int retval = -EINVAL;
5097+ short test_val = RT_PREEMPTIVE;
5098+
5099+ /* avoid races with the scheduler */
5100+ preempt_disable();
5101+ TRACE("reg_np_flag(%p) for %s/%d\n", flag,
5102+ current->comm, current->pid);
5103+
5104+ /* Let's first try to write to the address.
5105+ * That way it is initialized and any bugs
5106+ * involving dangling pointers will caught
5107+ * early.
5108+ * NULL indicates disabling np section support
5109+ * and should not be tested.
5110+ */
5111+ if (flag)
5112+ retval = poke_kernel_address(test_val, flag);
5113+ else
5114+ retval = 0;
5115+ TRACE("reg_np_flag: retval=%d\n", retval);
5116+ if (unlikely(0 != retval))
5117+ np_mem_error(current, "np flag: not writable");
5118+ else
5119+ /* the pointer is ok */
5120+ current->rt_param.np_flag = flag;
5121+
5122+ preempt_enable();
5123+ return retval;
5124+}
5125+
5126+
5127+void request_exit_np(struct task_struct *t)
5128+{
5129+ int ret;
5130+ short flag;
5131+
5132+ /* We can only do this if t is actually currently scheduled on this CPU
5133+ * because otherwise we are in the wrong address space. Thus make sure
5134+ * to check.
5135+ */
5136+ BUG_ON(t != current);
5137+
5138+ if (unlikely(!is_realtime(t) || !t->rt_param.np_flag)) {
5139+ TRACE_TASK(t, "request_exit_np(): BAD TASK!\n");
5140+ return;
5141+ }
5142+
5143+ flag = RT_EXIT_NP_REQUESTED;
5144+ ret = poke_kernel_address(flag, t->rt_param.np_flag + 1);
5145+ TRACE("request_exit_np(%s/%d)\n", t->comm, t->pid);
5146+ if (unlikely(0 != ret))
5147+ np_mem_error(current, "request_exit_np(): flag not writable");
5148+
5149+}
5150+
5151+
5152+int is_np(struct task_struct* t)
5153+{
5154+ int ret;
5155+ unsigned short flag = 0x5858; /* = XX, looks nicer in debug*/
5156+
5157+ BUG_ON(t != current);
5158+
5159+ if (unlikely(t->rt_param.kernel_np))
5160+ return 1;
5161+ else if (unlikely(t->rt_param.np_flag == NULL) ||
5162+ t->flags & PF_EXITING ||
5163+ t->state == TASK_DEAD)
5164+ return 0;
5165+ else {
5166+ /* This is the tricky part. The process has registered a
5167+ * non-preemptive section marker. We now need to check whether
5168+ * it is set to to NON_PREEMPTIVE. Along the way we could
5169+ * discover that the pointer points to an unmapped region (=>
5170+ * kill the task) or that the location contains some garbage
5171+ * value (=> also kill the task). Killing the task in any case
5172+ * forces userspace to play nicely. Any bugs will be discovered
5173+ * immediately.
5174+ */
5175+ ret = probe_kernel_address(t->rt_param.np_flag, flag);
5176+ if (0 == ret && (flag == RT_NON_PREEMPTIVE ||
5177+ flag == RT_PREEMPTIVE))
5178+ return flag != RT_PREEMPTIVE;
5179+ else {
5180+ /* either we could not read from the address or
5181+ * it contained garbage => kill the process
5182+ * FIXME: Should we cause a SEGFAULT instead?
5183+ */
5184+ TRACE("is_np: ret=%d flag=%c%c (%x)\n", ret,
5185+ flag & 0xff, (flag >> 8) & 0xff, flag);
5186+ np_mem_error(t, "is_np() could not read");
5187+ return 0;
5188+ }
5189+ }
5190+}
5191+
5192+/*
5193+ * sys_exit_np() allows real-time tasks to signal that it left a
5194+ * non-preemptable section. It will be called after the kernel requested a
5195+ * callback in the preemption indicator flag.
5196+ * returns 0 if the signal was valid and processed.
5197+ * returns EINVAL if current task is not a real-time task
5198+ */
5199+asmlinkage long sys_exit_np(void)
5200+{
5201+ int retval = -EINVAL;
5202+
5203+ TS_EXIT_NP_START;
5204+
5205+ if (!is_realtime(current))
5206+ goto out;
5207+
5208+ TRACE("sys_exit_np(%s/%d)\n", current->comm, current->pid);
5209+ /* force rescheduling so that we can be preempted */
5210+ set_tsk_need_resched(current);
5211+ retval = 0;
5212+ out:
5213+
5214+ TS_EXIT_NP_END;
5215+ return retval;
5216+}
5217+
5218+#else /* !CONFIG_NP_SECTION */
5219+
5220+asmlinkage long sys_register_np_flag(short __user *flag)
5221+{
5222+ return -ENOSYS;
5223+}
5224+
5225+asmlinkage long sys_exit_np(void)
5226+{
5227+ return -ENOSYS;
5228+}
5229+
5230+#endif /* CONFIG_NP_SECTION */
5231+
5232+
5233+/* sys_null_call() is only used for determining raw system call
5234+ * overheads (kernel entry, kernel exit). It has no useful side effects.
5235+ * If ts is non-NULL, then the current Feather-Trace time is recorded.
5236+ */
5237+asmlinkage long sys_null_call(cycles_t __user *ts)
5238+{
5239+ long ret = 0;
5240+ cycles_t now;
5241+
5242+ if (ts) {
5243+ now = get_cycles();
5244+ ret = put_user(now, ts);
5245+ }
5246+
5247+ return ret;
5248+}
5249+
5250+/* p is a real-time task. Re-init its state as a best-effort task. */
5251+static void reinit_litmus_state(struct task_struct* p, int restore)
5252+{
5253+ struct rt_task user_config = {};
5254+ __user short *np_flag = NULL;
5255+
5256+ if (restore) {
5257+ /* Safe user-space provided configuration data. */
5258+ user_config = p->rt_param.task_params;
5259+ np_flag = p->rt_param.np_flag;
5260+ }
5261+
5262+ /* We probably should not be inheriting any task's priority
5263+ * at this point in time.
5264+ */
5265+ WARN_ON(p->rt_param.inh_task);
5266+
5267+ /* We need to restore the priority of the task. */
5268+// __setscheduler(p, p->rt_param.old_policy, p->rt_param.old_prio);
5269+
5270+ /* Cleanup everything else. */
5271+ memset(&p->rt_param, 0, sizeof(user_config));
5272+
5273+ /* Restore preserved fields. */
5274+ if (restore) {
5275+ p->rt_param.task_params = user_config;
5276+ p->rt_param.np_flag = np_flag;
5277+ }
5278+}
5279+
5280+long litmus_admit_task(struct task_struct* tsk)
5281+{
5282+ long retval = 0;
5283+ long flags;
5284+
5285+ BUG_ON(is_realtime(tsk));
5286+
5287+ if (get_rt_period(tsk) == 0 ||
5288+ get_exec_cost(tsk) > get_rt_period(tsk)) {
5289+ TRACE_TASK(tsk, "litmus admit: invalid task parameters "
5290+ "(%lu, %lu)\n",
5291+ get_exec_cost(tsk), get_rt_period(tsk));
5292+ return -EINVAL;
5293+ }
5294+
5295+ if (!cpu_online(get_partition(tsk)))
5296+ {
5297+ TRACE_TASK(tsk, "litmus admit: cpu %d is not online\n",
5298+ get_partition(tsk));
5299+ return -EINVAL;
5300+ }
5301+
5302+ INIT_LIST_HEAD(&tsk_rt(tsk)->list);
5303+
5304+ /* avoid scheduler plugin changing underneath us */
5305+ spin_lock_irqsave(&task_transition_lock, flags);
5306+
5307+ /* allocate heap node for this task */
5308+ tsk_rt(tsk)->heap_node = heap_node_alloc(GFP_ATOMIC);
5309+ tsk_rt(tsk)->rel_heap = release_heap_alloc(GFP_ATOMIC);
5310+ if (!tsk_rt(tsk)->heap_node ||
5311+ !tsk_rt(tsk)->rel_heap) {
5312+ printk(KERN_WARNING "litmus: no more heap node memory!?\n");
5313+ retval = -ENOMEM;
5314+ heap_node_free(tsk_rt(tsk)->heap_node);
5315+ release_heap_free(tsk_rt(tsk)->rel_heap);
5316+ } else
5317+ heap_node_init(&tsk_rt(tsk)->heap_node, tsk);
5318+
5319+ if (!retval)
5320+ retval = litmus->admit_task(tsk);
5321+
5322+ if (!retval) {
5323+ sched_trace_task_name(tsk);
5324+ sched_trace_task_param(tsk);
5325+ atomic_inc(&rt_task_count);
5326+ }
5327+
5328+ spin_unlock_irqrestore(&task_transition_lock, flags);
5329+
5330+ return retval;
5331+}
5332+
5333+void litmus_exit_task(struct task_struct* tsk)
5334+{
5335+ if (is_realtime(tsk)) {
5336+ sched_trace_task_completion(tsk, 1);
5337+ litmus->task_exit(tsk);
5338+ BUG_ON(heap_node_in_heap(tsk_rt(tsk)->heap_node));
5339+ heap_node_free(tsk_rt(tsk)->heap_node);
5340+ release_heap_free(tsk_rt(tsk)->rel_heap);
5341+ atomic_dec(&rt_task_count);
5342+ reinit_litmus_state(tsk, 1);
5343+ }
5344+}
5345+
5346+/* Switching a plugin in use is tricky.
5347+ * We must watch out that no real-time tasks exists
5348+ * (and that none is created in parallel) and that the plugin is not
5349+ * currently in use on any processor (in theory).
5350+ *
5351+ * For now, we don't enforce the second part since it is unlikely to cause
5352+ * any trouble by itself as long as we don't unload modules.
5353+ */
5354+int switch_sched_plugin(struct sched_plugin* plugin)
5355+{
5356+ long flags;
5357+ int ret = 0;
5358+
5359+ BUG_ON(!plugin);
5360+
5361+ /* stop task transitions */
5362+ spin_lock_irqsave(&task_transition_lock, flags);
5363+
5364+ /* don't switch if there are active real-time tasks */
5365+ if (atomic_read(&rt_task_count) == 0) {
5366+ ret = litmus->deactivate_plugin();
5367+ if (0 != ret)
5368+ goto out;
5369+ ret = plugin->activate_plugin();
5370+ if (0 != ret) {
5371+ printk(KERN_INFO "Can't activate %s (%d).\n",
5372+ plugin->plugin_name, ret);
5373+ plugin = &linux_sched_plugin;
5374+ }
5375+ printk(KERN_INFO "Switching to LITMUS^RT plugin %s.\n", plugin->plugin_name);
5376+ litmus = plugin;
5377+ } else
5378+ ret = -EBUSY;
5379+out:
5380+ spin_unlock_irqrestore(&task_transition_lock, flags);
5381+ return ret;
5382+}
5383+
5384+/* Called upon fork.
5385+ * p is the newly forked task.
5386+ */
5387+void litmus_fork(struct task_struct* p)
5388+{
5389+ if (is_realtime(p))
5390+ /* clean out any litmus related state, don't preserve anything*/
5391+ reinit_litmus_state(p, 0);
5392+}
5393+
5394+/* Called upon execve().
5395+ * current is doing the exec.
5396+ * Don't let address space specific stuff leak.
5397+ */
5398+void litmus_exec(void)
5399+{
5400+ struct task_struct* p = current;
5401+
5402+ if (is_realtime(p)) {
5403+ WARN_ON(p->rt_param.inh_task);
5404+ p->rt_param.np_flag = NULL;
5405+ }
5406+}
5407+
5408+void exit_litmus(struct task_struct *dead_tsk)
5409+{
5410+ if (is_realtime(dead_tsk))
5411+ litmus_exit_task(dead_tsk);
5412+}
5413+
5414+
5415+#ifdef CONFIG_MAGIC_SYSRQ
5416+int sys_kill(int pid, int sig);
5417+
5418+static void sysrq_handle_kill_rt_tasks(int key, struct tty_struct *tty)
5419+{
5420+ struct task_struct *t;
5421+ read_lock(&tasklist_lock);
5422+ for_each_process(t) {
5423+ if (is_realtime(t)) {
5424+ sys_kill(t->pid, SIGKILL);
5425+ }
5426+ }
5427+ read_unlock(&tasklist_lock);
5428+}
5429+
5430+static struct sysrq_key_op sysrq_kill_rt_tasks_op = {
5431+ .handler = sysrq_handle_kill_rt_tasks,
5432+ .help_msg = "quit-rt-tasks(X)",
5433+ .action_msg = "sent SIGKILL to all LITMUS^RT real-time tasks",
5434+};
5435+
5436+
5437+#endif
5438+
5439+/* in sync.c */
5440+int count_tasks_waiting_for_release(void);
5441+
5442+static int proc_read_stats(char *page, char **start,
5443+ off_t off, int count,
5444+ int *eof, void *data)
5445+{
5446+ int len;
5447+
5448+ len = snprintf(page, PAGE_SIZE,
5449+ "real-time tasks = %d\n"
5450+ "ready for release = %d\n",
5451+ atomic_read(&rt_task_count),
5452+ count_tasks_waiting_for_release());
5453+ return len;
5454+}
5455+
5456+static int proc_read_plugins(char *page, char **start,
5457+ off_t off, int count,
5458+ int *eof, void *data)
5459+{
5460+ int len;
5461+
5462+ len = print_sched_plugins(page, PAGE_SIZE);
5463+ return len;
5464+}
5465+
5466+static int proc_read_curr(char *page, char **start,
5467+ off_t off, int count,
5468+ int *eof, void *data)
5469+{
5470+ int len;
5471+
5472+ len = snprintf(page, PAGE_SIZE, "%s\n", litmus->plugin_name);
5473+ return len;
5474+}
5475+
5476+static int proc_write_curr(struct file *file,
5477+ const char *buffer,
5478+ unsigned long count,
5479+ void *data)
5480+{
5481+ int len, ret;
5482+ char name[65];
5483+ struct sched_plugin* found;
5484+
5485+ if(count > 64)
5486+ len = 64;
5487+ else
5488+ len = count;
5489+
5490+ if(copy_from_user(name, buffer, len))
5491+ return -EFAULT;
5492+
5493+ name[len] = '\0';
5494+ /* chomp name */
5495+ if (len > 1 && name[len - 1] == '\n')
5496+ name[len - 1] = '\0';
5497+
5498+ found = find_sched_plugin(name);
5499+
5500+ if (found) {
5501+ ret = switch_sched_plugin(found);
5502+ if (ret != 0)
5503+ printk(KERN_INFO "Could not switch plugin: %d\n", ret);
5504+ } else
5505+ printk(KERN_INFO "Plugin '%s' is unknown.\n", name);
5506+
5507+ return len;
5508+}
5509+
5510+
5511+static int proc_read_release_master(char *page, char **start,
5512+ off_t off, int count,
5513+ int *eof, void *data)
5514+{
5515+ int len, master;
5516+ master = atomic_read(&release_master_cpu);
5517+ if (master == NO_CPU)
5518+ len = snprintf(page, PAGE_SIZE, "NO_CPU\n");
5519+ else
5520+ len = snprintf(page, PAGE_SIZE, "%d\n", master);
5521+ return len;
5522+}
5523+
5524+static int proc_write_release_master(struct file *file,
5525+ const char *buffer,
5526+ unsigned long count,
5527+ void *data)
5528+{
5529+ int cpu, err, online = 0;
5530+ char msg[64];
5531+
5532+ if (count > 63)
5533+ return -EINVAL;
5534+
5535+ if (copy_from_user(msg, buffer, count))
5536+ return -EFAULT;
5537+
5538+ /* terminate */
5539+ msg[count] = '\0';
5540+ /* chomp */
5541+ if (count > 1 && msg[count - 1] == '\n')
5542+ msg[count - 1] = '\0';
5543+
5544+ if (strcmp(msg, "NO_CPU") == 0) {
5545+ atomic_set(&release_master_cpu, NO_CPU);
5546+ return count;
5547+ } else {
5548+ err = sscanf(msg, "%d", &cpu);
5549+ if (err == 1 && cpu >= 0 && (online = cpu_online(cpu))) {
5550+ atomic_set(&release_master_cpu, cpu);
5551+ return count;
5552+ } else {
5553+ TRACE("invalid release master: '%s' "
5554+ "(err:%d cpu:%d online:%d)\n",
5555+ msg, err, cpu, online);
5556+ return -EINVAL;
5557+ }
5558+ }
5559+}
5560+
5561+static struct proc_dir_entry *litmus_dir = NULL,
5562+ *curr_file = NULL,
5563+ *stat_file = NULL,
5564+ *plugs_file = NULL,
5565+ *release_master_file = NULL;
5566+
5567+static int __init init_litmus_proc(void)
5568+{
5569+ litmus_dir = proc_mkdir("litmus", NULL);
5570+ if (!litmus_dir) {
5571+ printk(KERN_ERR "Could not allocate LITMUS^RT procfs entry.\n");
5572+ return -ENOMEM;
5573+ }
5574+ litmus_dir->owner = THIS_MODULE;
5575+
5576+ curr_file = create_proc_entry("active_plugin",
5577+ 0644, litmus_dir);
5578+ if (!curr_file) {
5579+ printk(KERN_ERR "Could not allocate active_plugin "
5580+ "procfs entry.\n");
5581+ return -ENOMEM;
5582+ }
5583+ curr_file->owner = THIS_MODULE;
5584+ curr_file->read_proc = proc_read_curr;
5585+ curr_file->write_proc = proc_write_curr;
5586+
5587+ release_master_file = create_proc_entry("release_master",
5588+ 0644, litmus_dir);
5589+ if (!release_master_file) {
5590+ printk(KERN_ERR "Could not allocate release_master "
5591+ "procfs entry.\n");
5592+ return -ENOMEM;
5593+ }
5594+ release_master_file->owner = THIS_MODULE;
5595+ release_master_file->read_proc = proc_read_release_master;
5596+ release_master_file->write_proc = proc_write_release_master;
5597+
5598+ stat_file = create_proc_read_entry("stats", 0444, litmus_dir,
5599+ proc_read_stats, NULL);
5600+
5601+ plugs_file = create_proc_read_entry("plugins", 0444, litmus_dir,
5602+ proc_read_plugins, NULL);
5603+
5604+ return 0;
5605+}
5606+
5607+static void exit_litmus_proc(void)
5608+{
5609+ if (plugs_file)
5610+ remove_proc_entry("plugins", litmus_dir);
5611+ if (stat_file)
5612+ remove_proc_entry("stats", litmus_dir);
5613+ if (curr_file)
5614+ remove_proc_entry("active_plugin", litmus_dir);
5615+ if (litmus_dir)
5616+ remove_proc_entry("litmus", NULL);
5617+}
5618+
5619+extern struct sched_plugin linux_sched_plugin;
5620+
5621+static int __init _init_litmus(void)
5622+{
5623+ /* Common initializers,
5624+ * mode change lock is used to enforce single mode change
5625+ * operation.
5626+ */
5627+ printk("Starting LITMUS^RT kernel\n");
5628+
5629+ register_sched_plugin(&linux_sched_plugin);
5630+
5631+ heap_node_cache = KMEM_CACHE(heap_node, SLAB_PANIC);
5632+ release_heap_cache = KMEM_CACHE(release_heap, SLAB_PANIC);
5633+
5634+#ifdef CONFIG_MAGIC_SYSRQ
5635+ /* offer some debugging help */
5636+ if (!register_sysrq_key('x', &sysrq_kill_rt_tasks_op))
5637+ printk("Registered kill rt tasks magic sysrq.\n");
5638+ else
5639+ printk("Could not register kill rt tasks magic sysrq.\n");
5640+#endif
5641+
5642+ init_litmus_proc();
5643+
5644+ return 0;
5645+}
5646+
5647+static void _exit_litmus(void)
5648+{
5649+ exit_litmus_proc();
5650+ kmem_cache_destroy(heap_node_cache);
5651+ kmem_cache_destroy(release_heap_cache);
5652+}
5653+
5654+module_init(_init_litmus);
5655+module_exit(_exit_litmus);
5656diff --git a/litmus/norqlock.c b/litmus/norqlock.c
5657new file mode 100644
5658index 0000000..1a17d6c
5659--- /dev/null
5660+++ b/litmus/norqlock.c
5661@@ -0,0 +1,76 @@
5662+#include <linux/list.h>
5663+#include <linux/bitops.h>
5664+#include <linux/percpu.h>
5665+#include <linux/module.h>
5666+#include <linux/smp.h>
5667+
5668+#include <litmus/norqlock.h>
5669+
5670+struct worklist {
5671+ struct no_rqlock_work* next;
5672+ int hrtimer_hack;
5673+};
5674+
5675+static DEFINE_PER_CPU(struct worklist, norq_worklist) = {NULL, 0};
5676+
5677+void init_no_rqlock_work(struct no_rqlock_work* w, work_t work,
5678+ unsigned long arg)
5679+{
5680+ w->active = 0;
5681+ w->work = work;
5682+ w->arg = arg;
5683+ w->next = NULL;
5684+}
5685+
5686+void __do_without_rqlock(struct no_rqlock_work *work)
5687+{
5688+ long flags;
5689+ struct worklist* wl;
5690+
5691+ local_irq_save(flags);
5692+ wl = &__get_cpu_var(norq_worklist);
5693+ work->next = wl->next;
5694+ wl->next = work;
5695+ local_irq_restore(flags);
5696+}
5697+
5698+void hrtimer_wakeup_hack(int onoff)
5699+{
5700+ preempt_disable();
5701+ __get_cpu_var(norq_worklist).hrtimer_hack = onoff;
5702+ preempt_enable();
5703+}
5704+
5705+void tick_no_rqlock(void)
5706+{
5707+ long flags;
5708+ struct no_rqlock_work *todo, *next;
5709+ struct worklist* wl;
5710+
5711+
5712+ local_irq_save(flags);
5713+
5714+ wl = &__get_cpu_var(norq_worklist);
5715+
5716+ if (wl->hrtimer_hack) {
5717+ /* bail out! */
5718+ local_irq_restore(flags);
5719+ return;
5720+ }
5721+
5722+ next = wl->next;
5723+ wl->next = NULL;
5724+
5725+ local_irq_restore(flags);
5726+
5727+ while (next) {
5728+ todo = next;
5729+ next = next->next;
5730+ todo->next = NULL;
5731+ smp_mb__before_clear_bit();
5732+ clear_bit(0, (void*) &todo->active);
5733+ todo->work(todo->arg);
5734+ }
5735+
5736+
5737+}
5738diff --git a/litmus/rt_domain.c b/litmus/rt_domain.c
5739new file mode 100644
5740index 0000000..2d0920c
5741--- /dev/null
5742+++ b/litmus/rt_domain.c
5743@@ -0,0 +1,302 @@
5744+
5745+/*
5746+ * kernel/rt_domain.c
5747+ *
5748+ * LITMUS real-time infrastructure. This file contains the
5749+ * functions that manipulate RT domains. RT domains are an abstraction
5750+ * of a ready queue and a release queue.
5751+ */
5752+
5753+#include <linux/percpu.h>
5754+#include <linux/sched.h>
5755+#include <linux/list.h>
5756+#include <linux/slab.h>
5757+
5758+#include <litmus/litmus.h>
5759+#include <litmus/sched_plugin.h>
5760+#include <litmus/sched_trace.h>
5761+
5762+#include <litmus/rt_domain.h>
5763+
5764+#include <litmus/trace.h>
5765+
5766+#include <litmus/heap.h>
5767+
5768+static int dummy_resched(rt_domain_t *rt)
5769+{
5770+ return 0;
5771+}
5772+
5773+static int dummy_order(struct heap_node* a, struct heap_node* b)
5774+{
5775+ return 0;
5776+}
5777+
5778+/* default implementation: use default lock */
5779+static void default_release_jobs(rt_domain_t* rt, struct heap* tasks)
5780+{
5781+ merge_ready(rt, tasks);
5782+}
5783+
5784+static unsigned int time2slot(lt_t time)
5785+{
5786+ return (unsigned int) time2quanta(time, FLOOR) % RELEASE_QUEUE_SLOTS;
5787+}
5788+
5789+static enum hrtimer_restart on_release_timer(struct hrtimer *timer)
5790+{
5791+ long flags;
5792+ struct release_heap* rh;
5793+
5794+ TRACE("on_release_timer(0x%p) starts.\n", timer);
5795+
5796+ TS_RELEASE_START;
5797+
5798+ rh = container_of(timer, struct release_heap, timer);
5799+
5800+ spin_lock_irqsave(&rh->dom->release_lock, flags);
5801+ TRACE("CB has the release_lock 0x%p\n", &rh->dom->release_lock);
5802+ /* remove from release queue */
5803+ list_del(&rh->list);
5804+ spin_unlock_irqrestore(&rh->dom->release_lock, flags);
5805+ TRACE("CB returned release_lock 0x%p\n", &rh->dom->release_lock);
5806+
5807+ /* call release callback */
5808+ rh->dom->release_jobs(rh->dom, &rh->heap);
5809+ /* WARNING: rh can be referenced from other CPUs from now on. */
5810+
5811+ TS_RELEASE_END;
5812+
5813+ TRACE("on_release_timer(0x%p) ends.\n", timer);
5814+
5815+ return HRTIMER_NORESTART;
5816+}
5817+
5818+/* allocated in litmus.c */
5819+struct kmem_cache * release_heap_cache;
5820+
5821+struct release_heap* release_heap_alloc(int gfp_flags)
5822+{
5823+ struct release_heap* rh;
5824+ rh= kmem_cache_alloc(release_heap_cache, gfp_flags);
5825+ if (rh) {
5826+ /* FIXME: could be a ctor */
5827+ /* initialize timer */
5828+ hrtimer_init(&rh->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
5829+ rh->timer.function = on_release_timer;
5830+#ifdef CONFIG_HIGH_RES_TIMERS
5831+ rh->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART;
5832+#endif
5833+ }
5834+ return rh;
5835+}
5836+
5837+void release_heap_free(struct release_heap* rh)
5838+{
5839+ /* make sure timer is no longer in use */
5840+ hrtimer_cancel(&rh->timer);
5841+ kmem_cache_free(release_heap_cache, rh);
5842+}
5843+
5844+/* Caller most hold release lock.
5845+ * Will return heap for given time. If no such heap exists prior to the invocation
5846+ * it will be created.
5847+ */
5848+static struct release_heap* get_release_heap(rt_domain_t *rt,
5849+ struct task_struct* t,
5850+ int use_task_heap)
5851+{
5852+ struct list_head* pos;
5853+ struct release_heap* heap = NULL;
5854+ struct release_heap* rh;
5855+ lt_t release_time = get_release(t);
5856+ unsigned int slot = time2slot(release_time);
5857+
5858+ /* initialize pos for the case that the list is empty */
5859+ pos = rt->release_queue.slot[slot].next;
5860+ list_for_each(pos, &rt->release_queue.slot[slot]) {
5861+ rh = list_entry(pos, struct release_heap, list);
5862+ if (release_time == rh->release_time) {
5863+ /* perfect match -- this happens on hyperperiod
5864+ * boundaries
5865+ */
5866+ heap = rh;
5867+ break;
5868+ } else if (lt_before(release_time, rh->release_time)) {
5869+ /* we need to insert a new node since rh is
5870+ * already in the future
5871+ */
5872+ break;
5873+ }
5874+ }
5875+ if (!heap && use_task_heap) {
5876+ /* use pre-allocated release heap */
5877+ rh = tsk_rt(t)->rel_heap;
5878+
5879+ rh->dom = rt;
5880+ rh->release_time = release_time;
5881+
5882+ /* add to release queue */
5883+ list_add(&rh->list, pos->prev);
5884+ heap = rh;
5885+ }
5886+ return heap;
5887+}
5888+
5889+static void reinit_release_heap(struct task_struct* t)
5890+{
5891+ struct release_heap* rh;
5892+
5893+ /* use pre-allocated release heap */
5894+ rh = tsk_rt(t)->rel_heap;
5895+
5896+ /* Make sure it is safe to use. The timer callback could still
5897+ * be executing on another CPU; hrtimer_cancel() will wait
5898+ * until the timer callback has completed. However, under no
5899+ * circumstances should the timer be active (= yet to be
5900+ * triggered).
5901+ *
5902+ * WARNING: If the CPU still holds the release_lock at this point,
5903+ * deadlock may occur!
5904+ */
5905+ BUG_ON(hrtimer_cancel(&rh->timer));
5906+
5907+ /* initialize */
5908+ heap_init(&rh->heap);
5909+
5910+ atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE);
5911+}
5912+
5913+static void arm_release_timer(unsigned long _rt)
5914+{
5915+ rt_domain_t *rt = (rt_domain_t*) _rt;
5916+ unsigned long flags;
5917+ struct list_head list;
5918+ struct list_head *pos, *safe;
5919+ struct task_struct* t;
5920+ struct release_heap* rh;
5921+
5922+ /* We only have to defend against the ISR since norq callbacks
5923+ * are serialized.
5924+ */
5925+ TRACE("arm_release_timer() at %llu\n", litmus_clock());
5926+ spin_lock_irqsave(&rt->tobe_lock, flags);
5927+ list_replace_init(&rt->tobe_released, &list);
5928+ spin_unlock_irqrestore(&rt->tobe_lock, flags);
5929+
5930+ list_for_each_safe(pos, safe, &list) {
5931+ /* pick task of work list */
5932+ t = list_entry(pos, struct task_struct, rt_param.list);
5933+ sched_trace_task_release(t);
5934+ list_del(pos);
5935+
5936+ /* put into release heap while holding release_lock */
5937+ spin_lock_irqsave(&rt->release_lock, flags);
5938+ TRACE_TASK(t, "I have the release_lock 0x%p\n", &rt->release_lock);
5939+ rh = get_release_heap(rt, t, 0);
5940+ if (!rh) {
5941+ /* need to use our own, but drop lock first */
5942+ spin_unlock(&rt->release_lock);
5943+ TRACE_TASK(t, "Dropped release_lock 0x%p\n",
5944+ &rt->release_lock);
5945+ reinit_release_heap(t);
5946+ TRACE_TASK(t, "release_heap ready\n");
5947+ spin_lock(&rt->release_lock);
5948+ TRACE_TASK(t, "Re-acquired release_lock 0x%p\n",
5949+ &rt->release_lock);
5950+ rh = get_release_heap(rt, t, 1);
5951+ }
5952+ heap_insert(rt->order, &rh->heap, tsk_rt(t)->heap_node);
5953+ TRACE_TASK(t, "arm_release_timer(): added to release heap\n");
5954+ spin_unlock_irqrestore(&rt->release_lock, flags);
5955+ TRACE_TASK(t, "Returned the release_lock 0x%p\n", &rt->release_lock);
5956+
5957+ /* To avoid arming the timer multiple times, we only let the
5958+ * owner do the arming (which is the "first" task to reference
5959+ * this release_heap anyway).
5960+ */
5961+ if (rh == tsk_rt(t)->rel_heap) {
5962+ TRACE_TASK(t, "arming timer 0x%p\n", &rh->timer);
5963+ if (rt->release_master == NO_CPU)
5964+ hrtimer_start(&rh->timer,
5965+ ns_to_ktime(rh->release_time),
5966+ HRTIMER_MODE_ABS);
5967+ else
5968+ hrtimer_start_on(rt->release_master,
5969+ &rh->info,
5970+ &rh->timer,
5971+ ns_to_ktime(rh->release_time),
5972+ HRTIMER_MODE_ABS);
5973+ } else
5974+ TRACE_TASK(t, "0x%p is not my timer\n", &rh->timer);
5975+ }
5976+}
5977+
5978+void rt_domain_init(rt_domain_t *rt,
5979+ heap_prio_t order,
5980+ check_resched_needed_t check,
5981+ release_jobs_t release
5982+ )
5983+{
5984+ int i;
5985+
5986+ BUG_ON(!rt);
5987+ if (!check)
5988+ check = dummy_resched;
5989+ if (!release)
5990+ release = default_release_jobs;
5991+ if (!order)
5992+ order = dummy_order;
5993+
5994+ rt->release_master = NO_CPU;
5995+
5996+ heap_init(&rt->ready_queue);
5997+ INIT_LIST_HEAD(&rt->tobe_released);
5998+ for (i = 0; i < RELEASE_QUEUE_SLOTS; i++)
5999+ INIT_LIST_HEAD(&rt->release_queue.slot[i]);
6000+
6001+ spin_lock_init(&rt->ready_lock);
6002+ spin_lock_init(&rt->release_lock);
6003+ spin_lock_init(&rt->tobe_lock);
6004+
6005+ rt->check_resched = check;
6006+ rt->release_jobs = release;
6007+ rt->order = order;
6008+ init_no_rqlock_work(&rt->arm_timer, arm_release_timer, (unsigned long) rt);
6009+}
6010+
6011+/* add_ready - add a real-time task to the rt ready queue. It must be runnable.
6012+ * @new: the newly released task
6013+ */
6014+void __add_ready(rt_domain_t* rt, struct task_struct *new)
6015+{
6016+ TRACE("rt: adding %s/%d (%llu, %llu) rel=%llu to ready queue at %llu\n",
6017+ new->comm, new->pid, get_exec_cost(new), get_rt_period(new),
6018+ get_release(new), litmus_clock());
6019+
6020+ BUG_ON(heap_node_in_heap(tsk_rt(new)->heap_node));
6021+
6022+ heap_insert(rt->order, &rt->ready_queue, tsk_rt(new)->heap_node);
6023+ rt->check_resched(rt);
6024+}
6025+
6026+/* merge_ready - Add a sorted set of tasks to the rt ready queue. They must be runnable.
6027+ * @tasks - the newly released tasks
6028+ */
6029+void __merge_ready(rt_domain_t* rt, struct heap* tasks)
6030+{
6031+ heap_union(rt->order, &rt->ready_queue, tasks);
6032+ rt->check_resched(rt);
6033+}
6034+
6035+/* add_release - add a real-time task to the rt release queue.
6036+ * @task: the sleeping task
6037+ */
6038+void __add_release(rt_domain_t* rt, struct task_struct *task)
6039+{
6040+ TRACE_TASK(task, "add_release(), rel=%llu\n", get_release(task));
6041+ list_add(&tsk_rt(task)->list, &rt->tobe_released);
6042+ task->rt_param.domain = rt;
6043+ do_without_rqlock(&rt->arm_timer);
6044+}
6045+
6046diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c
6047new file mode 100644
6048index 0000000..96e145a
6049--- /dev/null
6050+++ b/litmus/sched_cedf.c
6051@@ -0,0 +1,703 @@
6052+/*
6053+ * kernel/sched_cedf.c
6054+ *
6055+ * Implementation of the Clustered EDF (C-EDF) scheduling algorithm.
6056+ * Linking is included so that support for synchronization (e.g., through
6057+ * the implementation of a "CSN-EDF" algorithm) can be added later if desired.
6058+ *
6059+ * This version uses the simple approach and serializes all scheduling
6060+ * decisions by the use of a queue lock. This is probably not the
6061+ * best way to do it, but it should suffice for now.
6062+ */
6063+
6064+#include <linux/spinlock.h>
6065+#include <linux/percpu.h>
6066+#include <linux/sched.h>
6067+#include <linux/list.h>
6068+
6069+#include <litmus/litmus.h>
6070+#include <litmus/jobs.h>
6071+#include <litmus/sched_plugin.h>
6072+#include <litmus/edf_common.h>
6073+#include <litmus/sched_trace.h>
6074+
6075+#include <linux/module.h>
6076+
6077+/* Overview of C-EDF operations.
6078+ *
6079+ * link_task_to_cpu(T, cpu) - Low-level operation to update the linkage
6080+ * structure (NOT the actually scheduled
6081+ * task). If there is another linked task To
6082+ * already it will set To->linked_on = NO_CPU
6083+ * (thereby removing its association with this
6084+ * CPU). However, it will not requeue the
6085+ * previously linked task (if any). It will set
6086+ * T's state to RT_F_RUNNING and check whether
6087+ * it is already running somewhere else. If T
6088+ * is scheduled somewhere else it will link
6089+ * it to that CPU instead (and pull the linked
6090+ * task to cpu). T may be NULL.
6091+ *
6092+ * unlink(T) - Unlink removes T from all scheduler data
6093+ * structures. If it is linked to some CPU it
6094+ * will link NULL to that CPU. If it is
6095+ * currently queued in the cedf queue for
6096+ * a partition, it will be removed from
6097+ * the rt_domain. It is safe to call
6098+ * unlink(T) if T is not linked. T may not
6099+ * be NULL.
6100+ *
6101+ * requeue(T) - Requeue will insert T into the appropriate
6102+ * queue. If the system is in real-time mode and
6103+ * the T is released already, it will go into the
6104+ * ready queue. If the system is not in
6105+ * real-time mode is T, then T will go into the
6106+ * release queue. If T's release time is in the
6107+ * future, it will go into the release
6108+ * queue. That means that T's release time/job
6109+ * no/etc. has to be updated before requeue(T) is
6110+ * called. It is not safe to call requeue(T)
6111+ * when T is already queued. T may not be NULL.
6112+ *
6113+ * cedf_job_arrival(T) - This is the catch-all function when T enters
6114+ * the system after either a suspension or at a
6115+ * job release. It will queue T (which means it
6116+ * is not safe to call cedf_job_arrival(T) if
6117+ * T is already queued) and then check whether a
6118+ * preemption is necessary. If a preemption is
6119+ * necessary it will update the linkage
6120+ * accordingly and cause scheduled to be called
6121+ * (either with an IPI or need_resched). It is
6122+ * safe to call cedf_job_arrival(T) if T's
6123+ * next job has not been actually released yet
6124+ * (release time in the future). T will be put
6125+ * on the release queue in that case.
6126+ *
6127+ * job_completion(T) - Take care of everything that needs to be done
6128+ * to prepare T for its next release and place
6129+ * it in the right queue with
6130+ * cedf_job_arrival().
6131+ *
6132+ *
6133+ * When we now that T is linked to CPU then link_task_to_cpu(NULL, CPU) is
6134+ * equivalent to unlink(T). Note that if you unlink a task from a CPU none of
6135+ * the functions will automatically propagate pending task from the ready queue
6136+ * to a linked task. This is the job of the calling function ( by means of
6137+ * __take_ready).
6138+ */
6139+
6140+/* cpu_entry_t - maintain the linked and scheduled state
6141+ */
6142+typedef struct {
6143+ int cpu;
6144+ struct task_struct* linked; /* only RT tasks */
6145+ struct task_struct* scheduled; /* only RT tasks */
6146+ struct list_head list;
6147+ atomic_t will_schedule; /* prevent unneeded IPIs */
6148+} cpu_entry_t;
6149+DEFINE_PER_CPU(cpu_entry_t, cedf_cpu_entries);
6150+
6151+cpu_entry_t* cedf_cpu_entries_array[NR_CPUS];
6152+
6153+#define set_will_schedule() \
6154+ (atomic_set(&__get_cpu_var(cedf_cpu_entries).will_schedule, 1))
6155+#define clear_will_schedule() \
6156+ (atomic_set(&__get_cpu_var(cedf_cpu_entries).will_schedule, 0))
6157+#define test_will_schedule(cpu) \
6158+ (atomic_read(&per_cpu(cedf_cpu_entries, cpu).will_schedule))
6159+
6160+/* Cluster size -- currently four. This is a variable to allow for
6161+ * the possibility of changing the cluster size online in the future.
6162+ */
6163+int cluster_size = 4;
6164+
6165+typedef struct {
6166+ rt_domain_t domain;
6167+ int first_cpu;
6168+ int last_cpu;
6169+
6170+ /* the cpus queue themselves according to priority in here */
6171+ struct list_head cedf_cpu_queue;
6172+
6173+ /* per-partition spinlock: protects the domain and
6174+ * serializes scheduling decisions
6175+ */
6176+#define slock domain.ready_lock
6177+} cedf_domain_t;
6178+
6179+DEFINE_PER_CPU(cedf_domain_t*, cedf_domains) = NULL;
6180+
6181+cedf_domain_t* cedf_domains_array[NR_CPUS];
6182+
6183+
6184+/* These are defined similarly to partitioning, except that a
6185+ * tasks partition is any cpu of the cluster to which it
6186+ * is assigned, typically the lowest-numbered cpu.
6187+ */
6188+#define local_edf (&__get_cpu_var(cedf_domains)->domain)
6189+#define local_cedf __get_cpu_var(cedf_domains)
6190+#define remote_edf(cpu) (&per_cpu(cedf_domains, cpu)->domain)
6191+#define remote_cedf(cpu) per_cpu(cedf_domains, cpu)
6192+#define task_edf(task) remote_edf(get_partition(task))
6193+#define task_cedf(task) remote_cedf(get_partition(task))
6194+
6195+/* update_cpu_position - Move the cpu entry to the correct place to maintain
6196+ * order in the cpu queue. Caller must hold cedf lock.
6197+ *
6198+ * This really should be a heap.
6199+ */
6200+static void update_cpu_position(cpu_entry_t *entry)
6201+{
6202+ cpu_entry_t *other;
6203+ struct list_head *cedf_cpu_queue =
6204+ &(remote_cedf(entry->cpu))->cedf_cpu_queue;
6205+ struct list_head *pos;
6206+
6207+ BUG_ON(!cedf_cpu_queue);
6208+
6209+ if (likely(in_list(&entry->list)))
6210+ list_del(&entry->list);
6211+ /* if we do not execute real-time jobs we just move
6212+ * to the end of the queue
6213+ */
6214+ if (entry->linked) {
6215+ list_for_each(pos, cedf_cpu_queue) {
6216+ other = list_entry(pos, cpu_entry_t, list);
6217+ if (edf_higher_prio(entry->linked, other->linked)) {
6218+ __list_add(&entry->list, pos->prev, pos);
6219+ return;
6220+ }
6221+ }
6222+ }
6223+ /* if we get this far we have the lowest priority job */
6224+ list_add_tail(&entry->list, cedf_cpu_queue);
6225+}
6226+
6227+/* link_task_to_cpu - Update the link of a CPU.
6228+ * Handles the case where the to-be-linked task is already
6229+ * scheduled on a different CPU.
6230+ */
6231+static noinline void link_task_to_cpu(struct task_struct* linked,
6232+ cpu_entry_t *entry)
6233+{
6234+ cpu_entry_t *sched;
6235+ struct task_struct* tmp;
6236+ int on_cpu;
6237+
6238+ BUG_ON(linked && !is_realtime(linked));
6239+
6240+ /* Cannot link task to a CPU that doesn't belong to its partition... */
6241+ BUG_ON(linked && remote_cedf(entry->cpu) != task_cedf(linked));
6242+
6243+ /* Currently linked task is set to be unlinked. */
6244+ if (entry->linked) {
6245+ entry->linked->rt_param.linked_on = NO_CPU;
6246+ }
6247+
6248+ /* Link new task to CPU. */
6249+ if (linked) {
6250+ set_rt_flags(linked, RT_F_RUNNING);
6251+ /* handle task is already scheduled somewhere! */
6252+ on_cpu = linked->rt_param.scheduled_on;
6253+ if (on_cpu != NO_CPU) {
6254+ sched = &per_cpu(cedf_cpu_entries, on_cpu);
6255+ /* this should only happen if not linked already */
6256+ BUG_ON(sched->linked == linked);
6257+
6258+ /* If we are already scheduled on the CPU to which we
6259+ * wanted to link, we don't need to do the swap --
6260+ * we just link ourselves to the CPU and depend on
6261+ * the caller to get things right.
6262+ */
6263+ if (entry != sched) {
6264+ tmp = sched->linked;
6265+ linked->rt_param.linked_on = sched->cpu;
6266+ sched->linked = linked;
6267+ update_cpu_position(sched);
6268+ linked = tmp;
6269+ }
6270+ }
6271+ if (linked) /* might be NULL due to swap */
6272+ linked->rt_param.linked_on = entry->cpu;
6273+ }
6274+ entry->linked = linked;
6275+
6276+ if (entry->linked)
6277+ TRACE_TASK(entry->linked, "linked to CPU %d, state:%d\n",
6278+ entry->cpu, entry->linked->state);
6279+ else
6280+ TRACE("NULL linked to CPU %d\n", entry->cpu);
6281+
6282+ update_cpu_position(entry);
6283+}
6284+
6285+/* unlink - Make sure a task is not linked any longer to an entry
6286+ * where it was linked before. Must hold cedf_lock.
6287+ */
6288+static noinline void unlink(struct task_struct* t)
6289+{
6290+ cpu_entry_t *entry;
6291+
6292+ if (unlikely(!t)) {
6293+ TRACE_BUG_ON(!t);
6294+ return;
6295+ }
6296+
6297+ if (t->rt_param.linked_on != NO_CPU) {
6298+ /* unlink */
6299+ entry = &per_cpu(cedf_cpu_entries, t->rt_param.linked_on);
6300+ t->rt_param.linked_on = NO_CPU;
6301+ link_task_to_cpu(NULL, entry);
6302+ } else if (is_queued(t)) {
6303+ /* This is an interesting situation: t is scheduled,
6304+ * but was just recently unlinked. It cannot be
6305+ * linked anywhere else (because then it would have
6306+ * been relinked to this CPU), thus it must be in some
6307+ * queue. We must remove it from the list in this
6308+ * case.
6309+ */
6310+ remove(task_edf(t), t);
6311+ }
6312+}
6313+
6314+
6315+/* preempt - force a CPU to reschedule
6316+ */
6317+static noinline void preempt(cpu_entry_t *entry)
6318+{
6319+ /* We cannot make the is_np() decision here if it is a remote CPU
6320+ * because requesting exit_np() requires that we currently use the
6321+ * address space of the task. Thus, in the remote case we just send
6322+ * the IPI and let schedule() handle the problem.
6323+ */
6324+
6325+ if (smp_processor_id() == entry->cpu) {
6326+ if (entry->scheduled && is_np(entry->scheduled))
6327+ request_exit_np(entry->scheduled);
6328+ else
6329+ set_tsk_need_resched(current);
6330+ } else
6331+ /* in case that it is a remote CPU we have to defer the
6332+ * the decision to the remote CPU
6333+ * FIXME: We could save a few IPI's here if we leave the flag
6334+ * set when we are waiting for a np_exit().
6335+ */
6336+ if (!test_will_schedule(entry->cpu))
6337+ smp_send_reschedule(entry->cpu);
6338+}
6339+
6340+/* requeue - Put an unlinked task into c-edf domain.
6341+ * Caller must hold cedf_lock.
6342+ */
6343+static noinline void requeue(struct task_struct* task)
6344+{
6345+ cedf_domain_t* cedf;
6346+ rt_domain_t* edf;
6347+
6348+ BUG_ON(!task);
6349+ /* sanity check rt_list before insertion */
6350+ BUG_ON(is_queued(task));
6351+
6352+ /* Get correct real-time domain. */
6353+ cedf = task_cedf(task);
6354+ edf = &cedf->domain;
6355+
6356+ if (is_released(task, litmus_clock()))
6357+ __add_ready(edf, task);
6358+ else {
6359+ /* it has got to wait */
6360+ add_release(edf, task);
6361+ }
6362+}
6363+
6364+static void check_for_preemptions(cedf_domain_t* cedf)
6365+{
6366+ cpu_entry_t *last;
6367+ struct task_struct *task;
6368+ struct list_head *cedf_cpu_queue;
6369+ cedf_cpu_queue = &cedf->cedf_cpu_queue;
6370+
6371+ for(last = list_entry(cedf_cpu_queue->prev, cpu_entry_t, list);
6372+ edf_preemption_needed(&cedf->domain, last->linked);
6373+ last = list_entry(cedf_cpu_queue->prev, cpu_entry_t, list)) {
6374+ /* preemption necessary */
6375+ task = __take_ready(&cedf->domain);
6376+ TRACE("check_for_preemptions: task %d linked to %d, state:%d\n",
6377+ task->pid, last->cpu, task->state);
6378+ if (last->linked)
6379+ requeue(last->linked);
6380+ link_task_to_cpu(task, last);
6381+ preempt(last);
6382+ }
6383+
6384+}
6385+
6386+/* cedf_job_arrival: task is either resumed or released */
6387+static noinline void cedf_job_arrival(struct task_struct* task)
6388+{
6389+ cedf_domain_t* cedf;
6390+ rt_domain_t* edf;
6391+
6392+ BUG_ON(!task);
6393+
6394+ /* Get correct real-time domain. */
6395+ cedf = task_cedf(task);
6396+ edf = &cedf->domain;
6397+
6398+ /* first queue arriving job */
6399+ requeue(task);
6400+
6401+ /* then check for any necessary preemptions */
6402+ check_for_preemptions(cedf);
6403+}
6404+
6405+/* check for current job releases */
6406+static void cedf_release_jobs(rt_domain_t* rt, struct heap* tasks)
6407+{
6408+ cedf_domain_t* cedf = container_of(rt, cedf_domain_t, domain);
6409+ unsigned long flags;
6410+
6411+ spin_lock_irqsave(&cedf->slock, flags);
6412+
6413+ __merge_ready(&cedf->domain, tasks);
6414+ check_for_preemptions(cedf);
6415+ spin_unlock_irqrestore(&cedf->slock, flags);
6416+}
6417+
6418+/* cedf_tick - this function is called for every local timer
6419+ * interrupt.
6420+ *
6421+ * checks whether the current task has expired and checks
6422+ * whether we need to preempt it if it has not expired
6423+ */
6424+static void cedf_tick(struct task_struct* t)
6425+{
6426+ BUG_ON(!t);
6427+
6428+ if (is_realtime(t) && budget_exhausted(t)) {
6429+ if (!is_np(t)) {
6430+ /* np tasks will be preempted when they become
6431+ * preemptable again
6432+ */
6433+ set_tsk_need_resched(t);
6434+ set_will_schedule();
6435+ TRACE("cedf_scheduler_tick: "
6436+ "%d is preemptable (state:%d) "
6437+ " => FORCE_RESCHED\n", t->pid, t->state);
6438+ } else {
6439+ TRACE("cedf_scheduler_tick: "
6440+ "%d is non-preemptable (state:%d), "
6441+ "preemption delayed.\n", t->pid, t->state);
6442+ request_exit_np(t);
6443+ }
6444+ }
6445+}
6446+
6447+/* caller holds cedf_lock */
6448+static noinline void job_completion(struct task_struct *t, int forced)
6449+{
6450+ BUG_ON(!t);
6451+
6452+ sched_trace_task_completion(t, forced);
6453+
6454+ TRACE_TASK(t, "job_completion(). [state:%d]\n", t->state);
6455+
6456+ /* set flags */
6457+ set_rt_flags(t, RT_F_SLEEP);
6458+ /* prepare for next period */
6459+ prepare_for_next_period(t);
6460+ /* unlink */
6461+ unlink(t);
6462+ /* requeue
6463+ * But don't requeue a blocking task. */
6464+ if (is_running(t))
6465+ cedf_job_arrival(t);
6466+}
6467+
6468+/* Getting schedule() right is a bit tricky. schedule() may not make any
6469+ * assumptions on the state of the current task since it may be called for a
6470+ * number of reasons. The reasons include a scheduler_tick() determined that it
6471+ * was necessary, because sys_exit_np() was called, because some Linux
6472+ * subsystem determined so, or even (in the worst case) because there is a bug
6473+ * hidden somewhere. Thus, we must take extreme care to determine what the
6474+ * current state is.
6475+ *
6476+ * The CPU could currently be scheduling a task (or not), be linked (or not).
6477+ *
6478+ * The following assertions for the scheduled task could hold:
6479+ *
6480+ * - !is_running(scheduled) // the job blocks
6481+ * - scheduled->timeslice == 0 // the job completed (forcefully)
6482+ * - get_rt_flag() == RT_F_SLEEP // the job completed (by syscall)
6483+ * - linked != scheduled // we need to reschedule (for any reason)
6484+ * - is_np(scheduled) // rescheduling must be delayed,
6485+ * sys_exit_np must be requested
6486+ *
6487+ * Any of these can occur together.
6488+ */
6489+static struct task_struct* cedf_schedule(struct task_struct * prev)
6490+{
6491+ cedf_domain_t* cedf = local_cedf;
6492+ rt_domain_t* edf = &cedf->domain;
6493+ cpu_entry_t* entry = &__get_cpu_var(cedf_cpu_entries);
6494+ int out_of_time, sleep, preempt, np,
6495+ exists, blocks;
6496+ struct task_struct* next = NULL;
6497+
6498+ BUG_ON(!prev);
6499+ BUG_ON(!cedf);
6500+ BUG_ON(!edf);
6501+ BUG_ON(!entry);
6502+ BUG_ON(cedf != remote_cedf(entry->cpu));
6503+ BUG_ON(is_realtime(prev) && cedf != task_cedf(prev));
6504+
6505+ /* Will be released in finish_switch. */
6506+ spin_lock(&cedf->slock);
6507+ clear_will_schedule();
6508+
6509+ /* sanity checking */
6510+ BUG_ON(entry->scheduled && entry->scheduled != prev);
6511+ BUG_ON(entry->scheduled && !is_realtime(prev));
6512+ BUG_ON(is_realtime(prev) && !entry->scheduled);
6513+
6514+ /* (0) Determine state */
6515+ exists = entry->scheduled != NULL;
6516+ blocks = exists && !is_running(entry->scheduled);
6517+ out_of_time = exists && budget_exhausted(entry->scheduled);
6518+ np = exists && is_np(entry->scheduled);
6519+ sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP;
6520+ preempt = entry->scheduled != entry->linked;
6521+
6522+ /* If a task blocks we have no choice but to reschedule.
6523+ */
6524+ if (blocks)
6525+ unlink(entry->scheduled);
6526+
6527+ /* Request a sys_exit_np() call if we would like to preempt but cannot.
6528+ * We need to make sure to update the link structure anyway in case
6529+ * that we are still linked. Multiple calls to request_exit_np() don't
6530+ * hurt.
6531+ */
6532+ if (np && (out_of_time || preempt || sleep)) {
6533+ unlink(entry->scheduled);
6534+ request_exit_np(entry->scheduled);
6535+ }
6536+
6537+ /* Any task that is preemptable and either exhausts its execution
6538+ * budget or wants to sleep completes. We may have to reschedule after
6539+ * this. Don't do a job completion if blocks (can't have timers
6540+ * running for blocked jobs). Preemption go first for the same reason.
6541+ */
6542+ if (!np && (out_of_time || sleep) && !blocks && !preempt)
6543+ job_completion(entry->scheduled, !sleep);
6544+
6545+ /* Link pending task if we became unlinked.
6546+ */
6547+ if (!entry->linked)
6548+ link_task_to_cpu(__take_ready(edf), entry);
6549+
6550+ /* The final scheduling decision. Do we need to switch for some reason?
6551+ * If linked different from scheduled select linked as next.
6552+ */
6553+ if ((!np || blocks) &&
6554+ entry->linked != entry->scheduled) {
6555+ /* Schedule a linked job? */
6556+ if (entry->linked) {
6557+ entry->linked->rt_param.scheduled_on = entry->cpu;
6558+ next = entry->linked;
6559+ }
6560+ if (entry->scheduled) {
6561+ /* not gonna be scheduled soon */
6562+ entry->scheduled->rt_param.scheduled_on = NO_CPU;
6563+ TRACE_TASK(entry->scheduled, "scheduled_on = NO_CPU\n");
6564+ }
6565+ } else
6566+ /* Only override Linux scheduler if we have real-time task
6567+ * scheduled that needs to continue.
6568+ */
6569+ if (exists)
6570+ next = prev;
6571+
6572+ spin_unlock(&cedf->slock);
6573+
6574+ return next;
6575+}
6576+
6577+/* _finish_switch - we just finished the switch away from prev
6578+ */
6579+static void cedf_finish_switch(struct task_struct *prev)
6580+{
6581+ cpu_entry_t* entry = &__get_cpu_var(cedf_cpu_entries);
6582+
6583+ BUG_ON(!prev);
6584+ BUG_ON(!entry);
6585+
6586+ entry->scheduled = is_realtime(current) ? current : NULL;
6587+}
6588+
6589+/* Prepare a task for running in RT mode
6590+ */
6591+static void cedf_task_new(struct task_struct *t, int on_rq, int running)
6592+{
6593+ unsigned long flags;
6594+ cedf_domain_t* cedf = task_cedf(t);
6595+ cpu_entry_t* entry;
6596+
6597+ BUG_ON(!cedf);
6598+
6599+ spin_lock_irqsave(&cedf->slock, flags);
6600+ if (running) {
6601+ entry = &per_cpu(cedf_cpu_entries, task_cpu(t));
6602+ BUG_ON(!entry);
6603+ BUG_ON(entry->scheduled);
6604+ entry->scheduled = t;
6605+ t->rt_param.scheduled_on = task_cpu(t);
6606+ } else
6607+ t->rt_param.scheduled_on = NO_CPU;
6608+ t->rt_param.linked_on = NO_CPU;
6609+
6610+ /* setup job params */
6611+ release_at(t, litmus_clock());
6612+
6613+ cedf_job_arrival(t);
6614+ spin_unlock_irqrestore(&cedf->slock, flags);
6615+}
6616+
6617+
6618+static void cedf_task_wake_up(struct task_struct *task)
6619+{
6620+ unsigned long flags;
6621+ cedf_domain_t* cedf;
6622+ lt_t now;
6623+
6624+ BUG_ON(!task);
6625+
6626+ cedf = task_cedf(task);
6627+ BUG_ON(!cedf);
6628+
6629+ spin_lock_irqsave(&cedf->slock, flags);
6630+ /* We need to take suspensions because of semaphores into
6631+ * account! If a job resumes after being suspended due to acquiring
6632+ * a semaphore, it should never be treated as a new job release.
6633+ */
6634+ if (get_rt_flags(task) == RT_F_EXIT_SEM) {
6635+ set_rt_flags(task, RT_F_RUNNING);
6636+ } else {
6637+ now = litmus_clock();
6638+ if (is_tardy(task, now)) {
6639+ /* new sporadic release */
6640+ release_at(task, now);
6641+ sched_trace_task_release(task);
6642+ }
6643+ else if (task->time_slice)
6644+ /* came back in time before deadline
6645+ */
6646+ set_rt_flags(task, RT_F_RUNNING);
6647+ }
6648+ cedf_job_arrival(task);
6649+ spin_unlock_irqrestore(&cedf->slock, flags);
6650+}
6651+
6652+
6653+static void cedf_task_block(struct task_struct *t)
6654+{
6655+ unsigned long flags;
6656+
6657+ BUG_ON(!t);
6658+
6659+ /* unlink if necessary */
6660+ spin_lock_irqsave(&task_cedf(t)->slock, flags);
6661+ unlink(t);
6662+ spin_unlock_irqrestore(&task_cedf(t)->slock, flags);
6663+
6664+ BUG_ON(!is_realtime(t));
6665+}
6666+
6667+static void cedf_task_exit(struct task_struct * t)
6668+{
6669+ unsigned long flags;
6670+
6671+ BUG_ON(!t);
6672+
6673+ /* unlink if necessary */
6674+ spin_lock_irqsave(&task_cedf(t)->slock, flags);
6675+ unlink(t);
6676+ if (tsk_rt(t)->scheduled_on != NO_CPU) {
6677+ cedf_cpu_entries_array[tsk_rt(t)->scheduled_on]->
6678+ scheduled = NULL;
6679+ tsk_rt(t)->scheduled_on = NO_CPU;
6680+ }
6681+ spin_unlock_irqrestore(&task_cedf(t)->slock, flags);
6682+
6683+ BUG_ON(!is_realtime(t));
6684+ TRACE_TASK(t, "RIP\n");
6685+}
6686+
6687+static long cedf_admit_task(struct task_struct* tsk)
6688+{
6689+ return (task_cpu(tsk) >= task_cedf(tsk)->first_cpu &&
6690+ task_cpu(tsk) <= task_cedf(tsk)->last_cpu) ? 0 : -EINVAL;
6691+}
6692+
6693+
6694+/* Plugin object */
6695+static struct sched_plugin cedf_plugin __cacheline_aligned_in_smp = {
6696+ .plugin_name = "C-EDF",
6697+ .finish_switch = cedf_finish_switch,
6698+ .tick = cedf_tick,
6699+ .task_new = cedf_task_new,
6700+ .complete_job = complete_job,
6701+ .task_exit = cedf_task_exit,
6702+ .schedule = cedf_schedule,
6703+ .task_wake_up = cedf_task_wake_up,
6704+ .task_block = cedf_task_block,
6705+ .admit_task = cedf_admit_task
6706+};
6707+
6708+static void cedf_domain_init(int first_cpu, int last_cpu)
6709+{
6710+ int cpu;
6711+
6712+ /* Create new domain for this cluster. */
6713+ cedf_domain_t *new_cedf_domain = kmalloc(sizeof(*new_cedf_domain),
6714+ GFP_KERNEL);
6715+
6716+ /* Initialize cluster domain. */
6717+ edf_domain_init(&new_cedf_domain->domain, NULL,
6718+ cedf_release_jobs);
6719+ new_cedf_domain->first_cpu = first_cpu;
6720+ new_cedf_domain->last_cpu = last_cpu;
6721+ INIT_LIST_HEAD(&new_cedf_domain->cedf_cpu_queue);
6722+
6723+ /* Assign all cpus in cluster to point to this domain. */
6724+ for (cpu = first_cpu; cpu <= last_cpu; cpu++) {
6725+ remote_cedf(cpu) = new_cedf_domain;
6726+ cedf_domains_array[cpu] = new_cedf_domain;
6727+ }
6728+}
6729+
6730+static int __init init_cedf(void)
6731+{
6732+ int cpu;
6733+ cpu_entry_t *entry;
6734+
6735+ /* initialize CPU state */
6736+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
6737+ entry = &per_cpu(cedf_cpu_entries, cpu);
6738+ cedf_cpu_entries_array[cpu] = entry;
6739+ atomic_set(&entry->will_schedule, 0);
6740+ entry->linked = NULL;
6741+ entry->scheduled = NULL;
6742+ entry->cpu = cpu;
6743+ INIT_LIST_HEAD(&entry->list);
6744+ }
6745+
6746+ /* initialize all cluster domains */
6747+ for (cpu = 0; cpu < NR_CPUS; cpu += cluster_size)
6748+ cedf_domain_init(cpu, cpu+cluster_size-1);
6749+
6750+ return register_sched_plugin(&cedf_plugin);
6751+}
6752+
6753+module_init(init_cedf);
6754+
6755diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c
6756new file mode 100644
6757index 0000000..cbde657
6758--- /dev/null
6759+++ b/litmus/sched_gsn_edf.c
6760@@ -0,0 +1,760 @@
6761+/*
6762+ * kernel/sched_gsn_edf.c
6763+ *
6764+ * Implementation of the GSN-EDF scheduling algorithm.
6765+ *
6766+ * This version uses the simple approach and serializes all scheduling
6767+ * decisions by the use of a queue lock. This is probably not the
6768+ * best way to do it, but it should suffice for now.
6769+ */
6770+
6771+#include <linux/spinlock.h>
6772+#include <linux/percpu.h>
6773+#include <linux/sched.h>
6774+
6775+#include <litmus/litmus.h>
6776+#include <litmus/jobs.h>
6777+#include <litmus/sched_plugin.h>
6778+#include <litmus/edf_common.h>
6779+#include <litmus/sched_trace.h>
6780+
6781+#include <litmus/heap.h>
6782+
6783+#include <linux/module.h>
6784+
6785+/* Overview of GSN-EDF operations.
6786+ *
6787+ * For a detailed explanation of GSN-EDF have a look at the FMLP paper. This
6788+ * description only covers how the individual operations are implemented in
6789+ * LITMUS.
6790+ *
6791+ * link_task_to_cpu(T, cpu) - Low-level operation to update the linkage
6792+ * structure (NOT the actually scheduled
6793+ * task). If there is another linked task To
6794+ * already it will set To->linked_on = NO_CPU
6795+ * (thereby removing its association with this
6796+ * CPU). However, it will not requeue the
6797+ * previously linked task (if any). It will set
6798+ * T's state to RT_F_RUNNING and check whether
6799+ * it is already running somewhere else. If T
6800+ * is scheduled somewhere else it will link
6801+ * it to that CPU instead (and pull the linked
6802+ * task to cpu). T may be NULL.
6803+ *
6804+ * unlink(T) - Unlink removes T from all scheduler data
6805+ * structures. If it is linked to some CPU it
6806+ * will link NULL to that CPU. If it is
6807+ * currently queued in the gsnedf queue it will
6808+ * be removed from the rt_domain. It is safe to
6809+ * call unlink(T) if T is not linked. T may not
6810+ * be NULL.
6811+ *
6812+ * requeue(T) - Requeue will insert T into the appropriate
6813+ * queue. If the system is in real-time mode and
6814+ * the T is released already, it will go into the
6815+ * ready queue. If the system is not in
6816+ * real-time mode is T, then T will go into the
6817+ * release queue. If T's release time is in the
6818+ * future, it will go into the release
6819+ * queue. That means that T's release time/job
6820+ * no/etc. has to be updated before requeu(T) is
6821+ * called. It is not safe to call requeue(T)
6822+ * when T is already queued. T may not be NULL.
6823+ *
6824+ * gsnedf_job_arrival(T) - This is the catch all function when T enters
6825+ * the system after either a suspension or at a
6826+ * job release. It will queue T (which means it
6827+ * is not safe to call gsnedf_job_arrival(T) if
6828+ * T is already queued) and then check whether a
6829+ * preemption is necessary. If a preemption is
6830+ * necessary it will update the linkage
6831+ * accordingly and cause scheduled to be called
6832+ * (either with an IPI or need_resched). It is
6833+ * safe to call gsnedf_job_arrival(T) if T's
6834+ * next job has not been actually released yet
6835+ * (releast time in the future). T will be put
6836+ * on the release queue in that case.
6837+ *
6838+ * job_completion(T) - Take care of everything that needs to be done
6839+ * to prepare T for its next release and place
6840+ * it in the right queue with
6841+ * gsnedf_job_arrival().
6842+ *
6843+ *
6844+ * When we now that T is linked to CPU then link_task_to_cpu(NULL, CPU) is
6845+ * equivalent to unlink(T). Note that if you unlink a task from a CPU none of
6846+ * the functions will automatically propagate pending task from the ready queue
6847+ * to a linked task. This is the job of the calling function ( by means of
6848+ * __take_ready).
6849+ */
6850+
6851+
6852+/* cpu_entry_t - maintain the linked and scheduled state
6853+ */
6854+typedef struct {
6855+ int cpu;
6856+ struct task_struct* linked; /* only RT tasks */
6857+ struct task_struct* scheduled; /* only RT tasks */
6858+ atomic_t will_schedule; /* prevent unneeded IPIs */
6859+ struct heap_node* hn;
6860+} cpu_entry_t;
6861+DEFINE_PER_CPU(cpu_entry_t, gsnedf_cpu_entries);
6862+
6863+cpu_entry_t* gsnedf_cpus[NR_CPUS];
6864+
6865+#define set_will_schedule() \
6866+ (atomic_set(&__get_cpu_var(gsnedf_cpu_entries).will_schedule, 1))
6867+#define clear_will_schedule() \
6868+ (atomic_set(&__get_cpu_var(gsnedf_cpu_entries).will_schedule, 0))
6869+#define test_will_schedule(cpu) \
6870+ (atomic_read(&per_cpu(gsnedf_cpu_entries, cpu).will_schedule))
6871+
6872+
6873+/* the cpus queue themselves according to priority in here */
6874+static struct heap_node gsnedf_heap_node[NR_CPUS];
6875+static struct heap gsnedf_cpu_heap;
6876+
6877+static rt_domain_t gsnedf;
6878+#define gsnedf_lock (gsnedf.ready_lock)
6879+
6880+
6881+static int cpu_lower_prio(struct heap_node *_a, struct heap_node *_b)
6882+{
6883+ cpu_entry_t *a, *b;
6884+ a = _a->value;
6885+ b = _b->value;
6886+ /* Note that a and b are inverted: we want the lowest-priority CPU at
6887+ * the top of the heap.
6888+ */
6889+ return edf_higher_prio(b->linked, a->linked);
6890+}
6891+
6892+/* update_cpu_position - Move the cpu entry to the correct place to maintain
6893+ * order in the cpu queue. Caller must hold gsnedf lock.
6894+ */
6895+static void update_cpu_position(cpu_entry_t *entry)
6896+{
6897+ if (likely(heap_node_in_heap(entry->hn)))
6898+ heap_delete(cpu_lower_prio, &gsnedf_cpu_heap, entry->hn);
6899+ heap_insert(cpu_lower_prio, &gsnedf_cpu_heap, entry->hn);
6900+}
6901+
6902+/* caller must hold gsnedf lock */
6903+static cpu_entry_t* lowest_prio_cpu(void)
6904+{
6905+ struct heap_node* hn;
6906+ hn = heap_peek(cpu_lower_prio, &gsnedf_cpu_heap);
6907+ return hn->value;
6908+}
6909+
6910+
6911+/* link_task_to_cpu - Update the link of a CPU.
6912+ * Handles the case where the to-be-linked task is already
6913+ * scheduled on a different CPU.
6914+ */
6915+static noinline void link_task_to_cpu(struct task_struct* linked,
6916+ cpu_entry_t *entry)
6917+{
6918+ cpu_entry_t *sched;
6919+ struct task_struct* tmp;
6920+ int on_cpu;
6921+
6922+ BUG_ON(linked && !is_realtime(linked));
6923+
6924+ /* Currently linked task is set to be unlinked. */
6925+ if (entry->linked) {
6926+ entry->linked->rt_param.linked_on = NO_CPU;
6927+ }
6928+
6929+ /* Link new task to CPU. */
6930+ if (linked) {
6931+ set_rt_flags(linked, RT_F_RUNNING);
6932+ /* handle task is already scheduled somewhere! */
6933+ on_cpu = linked->rt_param.scheduled_on;
6934+ if (on_cpu != NO_CPU) {
6935+ sched = &per_cpu(gsnedf_cpu_entries, on_cpu);
6936+ /* this should only happen if not linked already */
6937+ BUG_ON(sched->linked == linked);
6938+
6939+ /* If we are already scheduled on the CPU to which we
6940+ * wanted to link, we don't need to do the swap --
6941+ * we just link ourselves to the CPU and depend on
6942+ * the caller to get things right.
6943+ */
6944+ if (entry != sched) {
6945+ TRACE_TASK(linked,
6946+ "already scheduled on %d, updating link.\n",
6947+ sched->cpu);
6948+ tmp = sched->linked;
6949+ linked->rt_param.linked_on = sched->cpu;
6950+ sched->linked = linked;
6951+ update_cpu_position(sched);
6952+ linked = tmp;
6953+ }
6954+ }
6955+ if (linked) /* might be NULL due to swap */
6956+ linked->rt_param.linked_on = entry->cpu;
6957+ }
6958+ entry->linked = linked;
6959+ if (linked)
6960+ TRACE_TASK(linked, "linked to %d.\n", entry->cpu);
6961+ else
6962+ TRACE("NULL linked to %d.\n", entry->cpu);
6963+ update_cpu_position(entry);
6964+}
6965+
6966+/* unlink - Make sure a task is not linked any longer to an entry
6967+ * where it was linked before. Must hold gsnedf_lock.
6968+ */
6969+static noinline void unlink(struct task_struct* t)
6970+{
6971+ cpu_entry_t *entry;
6972+
6973+ if (unlikely(!t)) {
6974+ TRACE_BUG_ON(!t);
6975+ return;
6976+ }
6977+
6978+ if (t->rt_param.linked_on != NO_CPU) {
6979+ /* unlink */
6980+ entry = &per_cpu(gsnedf_cpu_entries, t->rt_param.linked_on);
6981+ t->rt_param.linked_on = NO_CPU;
6982+ link_task_to_cpu(NULL, entry);
6983+ } else if (is_queued(t)) {
6984+ /* This is an interesting situation: t is scheduled,
6985+ * but was just recently unlinked. It cannot be
6986+ * linked anywhere else (because then it would have
6987+ * been relinked to this CPU), thus it must be in some
6988+ * queue. We must remove it from the list in this
6989+ * case.
6990+ */
6991+ remove(&gsnedf, t);
6992+ }
6993+}
6994+
6995+
6996+/* preempt - force a CPU to reschedule
6997+ */
6998+static noinline void preempt(cpu_entry_t *entry)
6999+{
7000+ /* We cannot make the is_np() decision here if it is a remote CPU
7001+ * because requesting exit_np() requires that we currently use the
7002+ * address space of the task. Thus, in the remote case we just send
7003+ * the IPI and let schedule() handle the problem.
7004+ */
7005+
7006+ if (smp_processor_id() == entry->cpu) {
7007+ if (entry->scheduled && is_np(entry->scheduled))
7008+ request_exit_np(entry->scheduled);
7009+ else
7010+ set_tsk_need_resched(current);
7011+ } else
7012+ /* in case that it is a remote CPU we have to defer the
7013+ * the decision to the remote CPU
7014+ * FIXME: We could save a few IPI's here if we leave the flag
7015+ * set when we are waiting for a np_exit().
7016+ */
7017+ if (!test_will_schedule(entry->cpu))
7018+ smp_send_reschedule(entry->cpu);
7019+}
7020+
7021+/* requeue - Put an unlinked task into gsn-edf domain.
7022+ * Caller must hold gsnedf_lock.
7023+ */
7024+static noinline void requeue(struct task_struct* task)
7025+{
7026+ BUG_ON(!task);
7027+ /* sanity check before insertion */
7028+ BUG_ON(is_queued(task));
7029+
7030+ if (is_released(task, litmus_clock()))
7031+ __add_ready(&gsnedf, task);
7032+ else {
7033+ /* it has got to wait */
7034+ add_release(&gsnedf, task);
7035+ }
7036+}
7037+
7038+/* check for any necessary preemptions */
7039+static void check_for_preemptions(void)
7040+{
7041+ struct task_struct *task;
7042+ cpu_entry_t* last;
7043+
7044+ for(last = lowest_prio_cpu();
7045+ edf_preemption_needed(&gsnedf, last->linked);
7046+ last = lowest_prio_cpu()) {
7047+ /* preemption necessary */
7048+ task = __take_ready(&gsnedf);
7049+ TRACE("check_for_preemptions: attempting to link task %d to %d\n",
7050+ task->pid, last->cpu);
7051+ if (last->linked)
7052+ requeue(last->linked);
7053+ link_task_to_cpu(task, last);
7054+ preempt(last);
7055+ }
7056+}
7057+
7058+/* gsnedf_job_arrival: task is either resumed or released */
7059+static noinline void gsnedf_job_arrival(struct task_struct* task)
7060+{
7061+ BUG_ON(!task);
7062+
7063+ requeue(task);
7064+ check_for_preemptions();
7065+}
7066+
7067+static void gsnedf_release_jobs(rt_domain_t* rt, struct heap* tasks)
7068+{
7069+ unsigned long flags;
7070+
7071+ spin_lock_irqsave(&gsnedf_lock, flags);
7072+
7073+ __merge_ready(rt, tasks);
7074+ check_for_preemptions();
7075+
7076+ spin_unlock_irqrestore(&gsnedf_lock, flags);
7077+}
7078+
7079+/* caller holds gsnedf_lock */
7080+static noinline void job_completion(struct task_struct *t, int forced)
7081+{
7082+ BUG_ON(!t);
7083+
7084+ sched_trace_task_completion(t, forced);
7085+
7086+ TRACE_TASK(t, "job_completion().\n");
7087+
7088+ /* set flags */
7089+ set_rt_flags(t, RT_F_SLEEP);
7090+ /* prepare for next period */
7091+ prepare_for_next_period(t);
7092+ if (is_released(t, litmus_clock()))
7093+ sched_trace_task_release(t);
7094+ /* unlink */
7095+ unlink(t);
7096+ /* requeue
7097+ * But don't requeue a blocking task. */
7098+ if (is_running(t))
7099+ gsnedf_job_arrival(t);
7100+}
7101+
7102+/* gsnedf_tick - this function is called for every local timer
7103+ * interrupt.
7104+ *
7105+ * checks whether the current task has expired and checks
7106+ * whether we need to preempt it if it has not expired
7107+ */
7108+static void gsnedf_tick(struct task_struct* t)
7109+{
7110+ if (is_realtime(t) && budget_exhausted(t)) {
7111+ if (!is_np(t)) {
7112+ /* np tasks will be preempted when they become
7113+ * preemptable again
7114+ */
7115+ set_tsk_need_resched(t);
7116+ set_will_schedule();
7117+ TRACE("gsnedf_scheduler_tick: "
7118+ "%d is preemptable "
7119+ " => FORCE_RESCHED\n", t->pid);
7120+ } else {
7121+ TRACE("gsnedf_scheduler_tick: "
7122+ "%d is non-preemptable, "
7123+ "preemption delayed.\n", t->pid);
7124+ request_exit_np(t);
7125+ }
7126+ }
7127+}
7128+
7129+/* Getting schedule() right is a bit tricky. schedule() may not make any
7130+ * assumptions on the state of the current task since it may be called for a
7131+ * number of reasons. The reasons include a scheduler_tick() determined that it
7132+ * was necessary, because sys_exit_np() was called, because some Linux
7133+ * subsystem determined so, or even (in the worst case) because there is a bug
7134+ * hidden somewhere. Thus, we must take extreme care to determine what the
7135+ * current state is.
7136+ *
7137+ * The CPU could currently be scheduling a task (or not), be linked (or not).
7138+ *
7139+ * The following assertions for the scheduled task could hold:
7140+ *
7141+ * - !is_running(scheduled) // the job blocks
7142+ * - scheduled->timeslice == 0 // the job completed (forcefully)
7143+ * - get_rt_flag() == RT_F_SLEEP // the job completed (by syscall)
7144+ * - linked != scheduled // we need to reschedule (for any reason)
7145+ * - is_np(scheduled) // rescheduling must be delayed,
7146+ * sys_exit_np must be requested
7147+ *
7148+ * Any of these can occur together.
7149+ */
7150+static struct task_struct* gsnedf_schedule(struct task_struct * prev)
7151+{
7152+ cpu_entry_t* entry = &__get_cpu_var(gsnedf_cpu_entries);
7153+ int out_of_time, sleep, preempt, np, exists, blocks;
7154+ struct task_struct* next = NULL;
7155+
7156+ /* Bail out early if we are the release master.
7157+ * The release master never schedules any real-time tasks.
7158+ */
7159+ if (gsnedf.release_master == entry->cpu)
7160+ return NULL;
7161+
7162+ spin_lock(&gsnedf_lock);
7163+ clear_will_schedule();
7164+
7165+ /* sanity checking */
7166+ BUG_ON(entry->scheduled && entry->scheduled != prev);
7167+ BUG_ON(entry->scheduled && !is_realtime(prev));
7168+ BUG_ON(is_realtime(prev) && !entry->scheduled);
7169+
7170+ /* (0) Determine state */
7171+ exists = entry->scheduled != NULL;
7172+ blocks = exists && !is_running(entry->scheduled);
7173+ out_of_time = exists && budget_exhausted(entry->scheduled);
7174+ np = exists && is_np(entry->scheduled);
7175+ sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP;
7176+ preempt = entry->scheduled != entry->linked;
7177+
7178+ TRACE_TASK(prev, "invoked gsnedf_schedule.\n");
7179+
7180+ if (exists)
7181+ TRACE_TASK(prev,
7182+ "blocks:%d out_of_time:%d np:%d sleep:%d preempt:%d "
7183+ "state:%d sig:%d\n",
7184+ blocks, out_of_time, np, sleep, preempt,
7185+ prev->state, signal_pending(prev));
7186+ if (entry->linked && preempt)
7187+ TRACE_TASK(prev, "will be preempted by %s/%d\n",
7188+ entry->linked->comm, entry->linked->pid);
7189+
7190+
7191+ /* If a task blocks we have no choice but to reschedule.
7192+ */
7193+ if (blocks)
7194+ unlink(entry->scheduled);
7195+
7196+ /* Request a sys_exit_np() call if we would like to preempt but cannot.
7197+ * We need to make sure to update the link structure anyway in case
7198+ * that we are still linked. Multiple calls to request_exit_np() don't
7199+ * hurt.
7200+ */
7201+ if (np && (out_of_time || preempt || sleep)) {
7202+ unlink(entry->scheduled);
7203+ request_exit_np(entry->scheduled);
7204+ }
7205+
7206+ /* Any task that is preemptable and either exhausts its execution
7207+ * budget or wants to sleep completes. We may have to reschedule after
7208+ * this. Don't do a job completion if we block (can't have timers running
7209+ * for blocked jobs). Preemption go first for the same reason.
7210+ */
7211+ if (!np && (out_of_time || sleep) && !blocks && !preempt)
7212+ job_completion(entry->scheduled, !sleep);
7213+
7214+ /* Link pending task if we became unlinked.
7215+ */
7216+ if (!entry->linked)
7217+ link_task_to_cpu(__take_ready(&gsnedf), entry);
7218+
7219+ /* The final scheduling decision. Do we need to switch for some reason?
7220+ * If linked is different from scheduled, then select linked as next.
7221+ */
7222+ if ((!np || blocks) &&
7223+ entry->linked != entry->scheduled) {
7224+ /* Schedule a linked job? */
7225+ if (entry->linked) {
7226+ entry->linked->rt_param.scheduled_on = entry->cpu;
7227+ next = entry->linked;
7228+ }
7229+ if (entry->scheduled) {
7230+ /* not gonna be scheduled soon */
7231+ entry->scheduled->rt_param.scheduled_on = NO_CPU;
7232+ TRACE_TASK(entry->scheduled, "scheduled_on = NO_CPU\n");
7233+ }
7234+ } else
7235+ /* Only override Linux scheduler if we have a real-time task
7236+ * scheduled that needs to continue.
7237+ */
7238+ if (exists)
7239+ next = prev;
7240+
7241+ spin_unlock(&gsnedf_lock);
7242+
7243+ TRACE("gsnedf_lock released, next=0x%p\n", next);
7244+
7245+
7246+ if (next)
7247+ TRACE_TASK(next, "scheduled at %llu\n", litmus_clock());
7248+ else if (exists && !next)
7249+ TRACE("becomes idle at %llu.\n", litmus_clock());
7250+
7251+
7252+ return next;
7253+}
7254+
7255+
7256+/* _finish_switch - we just finished the switch away from prev
7257+ */
7258+static void gsnedf_finish_switch(struct task_struct *prev)
7259+{
7260+ cpu_entry_t* entry = &__get_cpu_var(gsnedf_cpu_entries);
7261+
7262+ entry->scheduled = is_realtime(current) ? current : NULL;
7263+ TRACE_TASK(prev, "switched away from\n");
7264+}
7265+
7266+
7267+/* Prepare a task for running in RT mode
7268+ */
7269+static void gsnedf_task_new(struct task_struct * t, int on_rq, int running)
7270+{
7271+ unsigned long flags;
7272+ cpu_entry_t* entry;
7273+
7274+ TRACE("gsn edf: task new %d\n", t->pid);
7275+
7276+ spin_lock_irqsave(&gsnedf_lock, flags);
7277+
7278+ /* setup job params */
7279+ release_at(t, litmus_clock());
7280+
7281+ if (running) {
7282+ entry = &per_cpu(gsnedf_cpu_entries, task_cpu(t));
7283+ BUG_ON(entry->scheduled);
7284+ if (entry->cpu != gsnedf.release_master) {
7285+ entry->scheduled = t;
7286+ tsk_rt(t)->scheduled_on = task_cpu(t);
7287+ } else {
7288+ preempt(entry); /* force resched */
7289+ tsk_rt(t)->scheduled_on = NO_CPU;
7290+ }
7291+ } else {
7292+ t->rt_param.scheduled_on = NO_CPU;
7293+ }
7294+ t->rt_param.linked_on = NO_CPU;
7295+
7296+ gsnedf_job_arrival(t);
7297+ spin_unlock_irqrestore(&gsnedf_lock, flags);
7298+}
7299+
7300+static void gsnedf_task_wake_up(struct task_struct *task)
7301+{
7302+ unsigned long flags;
7303+ lt_t now;
7304+
7305+ TRACE_TASK(task, "wake_up at %llu\n", litmus_clock());
7306+
7307+ spin_lock_irqsave(&gsnedf_lock, flags);
7308+ /* We need to take suspensions because of semaphores into
7309+ * account! If a job resumes after being suspended due to acquiring
7310+ * a semaphore, it should never be treated as a new job release.
7311+ */
7312+ if (get_rt_flags(task) == RT_F_EXIT_SEM) {
7313+ set_rt_flags(task, RT_F_RUNNING);
7314+ } else {
7315+ now = litmus_clock();
7316+ if (is_tardy(task, now)) {
7317+ /* new sporadic release */
7318+ release_at(task, now);
7319+ sched_trace_task_release(task);
7320+ }
7321+ else if (task->time_slice)
7322+ /* came back in time before deadline
7323+ */
7324+ set_rt_flags(task, RT_F_RUNNING);
7325+ }
7326+ gsnedf_job_arrival(task);
7327+ spin_unlock_irqrestore(&gsnedf_lock, flags);
7328+}
7329+
7330+static void gsnedf_task_block(struct task_struct *t)
7331+{
7332+ unsigned long flags;
7333+
7334+ TRACE_TASK(t, "block at %llu\n", litmus_clock());
7335+
7336+ /* unlink if necessary */
7337+ spin_lock_irqsave(&gsnedf_lock, flags);
7338+ unlink(t);
7339+ spin_unlock_irqrestore(&gsnedf_lock, flags);
7340+
7341+ BUG_ON(!is_realtime(t));
7342+}
7343+
7344+
7345+static void gsnedf_task_exit(struct task_struct * t)
7346+{
7347+ unsigned long flags;
7348+
7349+ /* unlink if necessary */
7350+ spin_lock_irqsave(&gsnedf_lock, flags);
7351+ unlink(t);
7352+ if (tsk_rt(t)->scheduled_on != NO_CPU) {
7353+ gsnedf_cpus[tsk_rt(t)->scheduled_on]->scheduled = NULL;
7354+ tsk_rt(t)->scheduled_on = NO_CPU;
7355+ }
7356+ spin_unlock_irqrestore(&gsnedf_lock, flags);
7357+
7358+ BUG_ON(!is_realtime(t));
7359+ TRACE_TASK(t, "RIP\n");
7360+}
7361+
7362+#ifdef CONFIG_FMLP
7363+static long gsnedf_pi_block(struct pi_semaphore *sem,
7364+ struct task_struct *new_waiter)
7365+{
7366+ /* This callback has to handle the situation where a new waiter is
7367+ * added to the wait queue of the semaphore.
7368+ *
7369+ * We must check if has a higher priority than the currently
7370+ * highest-priority task, and then potentially reschedule.
7371+ */
7372+
7373+ BUG_ON(!new_waiter);
7374+
7375+ if (edf_higher_prio(new_waiter, sem->hp.task)) {
7376+ TRACE_TASK(new_waiter, " boosts priority\n");
7377+ /* called with IRQs disabled */
7378+ spin_lock(&gsnedf_lock);
7379+ /* store new highest-priority task */
7380+ sem->hp.task = new_waiter;
7381+ if (sem->holder) {
7382+ /* let holder inherit */
7383+ sem->holder->rt_param.inh_task = new_waiter;
7384+ unlink(sem->holder);
7385+ gsnedf_job_arrival(sem->holder);
7386+ }
7387+ spin_unlock(&gsnedf_lock);
7388+ }
7389+
7390+ return 0;
7391+}
7392+
7393+static long gsnedf_inherit_priority(struct pi_semaphore *sem,
7394+ struct task_struct *new_owner)
7395+{
7396+ /* We don't need to acquire the gsnedf_lock since at the time of this
7397+ * call new_owner isn't actually scheduled yet (it's still sleeping)
7398+ * and since the calling function already holds sem->wait.lock, which
7399+ * prevents concurrent sem->hp.task changes.
7400+ */
7401+
7402+ if (sem->hp.task && sem->hp.task != new_owner) {
7403+ new_owner->rt_param.inh_task = sem->hp.task;
7404+ TRACE_TASK(new_owner, "inherited priority from %s/%d\n",
7405+ sem->hp.task->comm, sem->hp.task->pid);
7406+ } else
7407+ TRACE_TASK(new_owner,
7408+ "cannot inherit priority, "
7409+ "no higher priority job waits.\n");
7410+ return 0;
7411+}
7412+
7413+/* This function is called on a semaphore release, and assumes that
7414+ * the current task is also the semaphore holder.
7415+ */
7416+static long gsnedf_return_priority(struct pi_semaphore *sem)
7417+{
7418+ struct task_struct* t = current;
7419+ int ret = 0;
7420+
7421+ /* Find new highest-priority semaphore task
7422+ * if holder task is the current hp.task.
7423+ *
7424+ * Calling function holds sem->wait.lock.
7425+ */
7426+ if (t == sem->hp.task)
7427+ edf_set_hp_task(sem);
7428+
7429+ TRACE_CUR("gsnedf_return_priority for lock %p\n", sem);
7430+
7431+ if (t->rt_param.inh_task) {
7432+ /* interrupts already disabled by PI code */
7433+ spin_lock(&gsnedf_lock);
7434+
7435+ /* Reset inh_task to NULL. */
7436+ t->rt_param.inh_task = NULL;
7437+
7438+ /* Check if rescheduling is necessary */
7439+ unlink(t);
7440+ gsnedf_job_arrival(t);
7441+ spin_unlock(&gsnedf_lock);
7442+ }
7443+
7444+ return ret;
7445+}
7446+
7447+#endif
7448+
7449+static long gsnedf_admit_task(struct task_struct* tsk)
7450+{
7451+ return 0;
7452+}
7453+
7454+static long gsnedf_activate_plugin(void)
7455+{
7456+ int cpu;
7457+ cpu_entry_t *entry;
7458+
7459+ heap_init(&gsnedf_cpu_heap);
7460+ gsnedf.release_master = atomic_read(&release_master_cpu);
7461+
7462+ for_each_online_cpu(cpu) {
7463+ entry = &per_cpu(gsnedf_cpu_entries, cpu);
7464+ heap_node_init(&entry->hn, entry);
7465+ atomic_set(&entry->will_schedule, 0);
7466+ entry->linked = NULL;
7467+ entry->scheduled = NULL;
7468+ if (cpu != gsnedf.release_master) {
7469+ TRACE("GSN-EDF: Initializing CPU #%d.\n", cpu);
7470+ update_cpu_position(entry);
7471+ } else {
7472+ TRACE("GSN-EDF: CPU %d is release master.\n", cpu);
7473+ }
7474+ }
7475+ return 0;
7476+}
7477+
7478+/* Plugin object */
7479+static struct sched_plugin gsn_edf_plugin __cacheline_aligned_in_smp = {
7480+ .plugin_name = "GSN-EDF",
7481+ .finish_switch = gsnedf_finish_switch,
7482+ .tick = gsnedf_tick,
7483+ .task_new = gsnedf_task_new,
7484+ .complete_job = complete_job,
7485+ .task_exit = gsnedf_task_exit,
7486+ .schedule = gsnedf_schedule,
7487+ .task_wake_up = gsnedf_task_wake_up,
7488+ .task_block = gsnedf_task_block,
7489+#ifdef CONFIG_FMLP
7490+ .fmlp_active = 1,
7491+ .pi_block = gsnedf_pi_block,
7492+ .inherit_priority = gsnedf_inherit_priority,
7493+ .return_priority = gsnedf_return_priority,
7494+#endif
7495+ .admit_task = gsnedf_admit_task,
7496+ .activate_plugin = gsnedf_activate_plugin,
7497+};
7498+
7499+
7500+static int __init init_gsn_edf(void)
7501+{
7502+ int cpu;
7503+ cpu_entry_t *entry;
7504+
7505+ heap_init(&gsnedf_cpu_heap);
7506+ /* initialize CPU state */
7507+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
7508+ entry = &per_cpu(gsnedf_cpu_entries, cpu);
7509+ gsnedf_cpus[cpu] = entry;
7510+ atomic_set(&entry->will_schedule, 0);
7511+ entry->cpu = cpu;
7512+ entry->hn = &gsnedf_heap_node[cpu];
7513+ heap_node_init(&entry->hn, entry);
7514+ }
7515+ edf_domain_init(&gsnedf, NULL, gsnedf_release_jobs);
7516+ return register_sched_plugin(&gsn_edf_plugin);
7517+}
7518+
7519+
7520+module_init(init_gsn_edf);
7521diff --git a/litmus/sched_litmus.c b/litmus/sched_litmus.c
7522new file mode 100644
7523index 0000000..3ebec1d
7524--- /dev/null
7525+++ b/litmus/sched_litmus.c
7526@@ -0,0 +1,245 @@
7527+/* This file is included from kernel/sched.c */
7528+
7529+#include <litmus/litmus.h>
7530+#include <litmus/sched_plugin.h>
7531+
7532+static void update_time_litmus(struct rq *rq, struct task_struct *p)
7533+{
7534+ u64 delta = rq->clock - p->se.exec_start;
7535+ if (unlikely((s64)delta < 0))
7536+ delta = 0;
7537+ /* per job counter */
7538+ p->rt_param.job_params.exec_time += delta;
7539+ /* task counter */
7540+ p->se.sum_exec_runtime += delta;
7541+ /* sched_clock() */
7542+ p->se.exec_start = rq->clock;
7543+ cpuacct_charge(p, delta);
7544+}
7545+
7546+static void double_rq_lock(struct rq *rq1, struct rq *rq2);
7547+static void double_rq_unlock(struct rq *rq1, struct rq *rq2);
7548+
7549+static void litmus_tick(struct rq *rq, struct task_struct *p)
7550+{
7551+ if (is_realtime(p))
7552+ update_time_litmus(rq, p);
7553+ litmus->tick(p);
7554+}
7555+
7556+static void litmus_schedule(struct rq *rq, struct task_struct *prev)
7557+{
7558+ struct rq* other_rq;
7559+ long was_running;
7560+ lt_t _maybe_deadlock = 0;
7561+ /* WARNING: rq is _not_ locked! */
7562+ if (is_realtime(prev)) {
7563+ update_time_litmus(rq, prev);
7564+ if (!is_running(prev))
7565+ tsk_rt(prev)->present = 0;
7566+ }
7567+
7568+ /* let the plugin schedule */
7569+ rq->litmus_next = litmus->schedule(prev);
7570+
7571+ /* check if a global plugin pulled a task from a different RQ */
7572+ if (rq->litmus_next && task_rq(rq->litmus_next) != rq) {
7573+ /* we need to migrate the task */
7574+ other_rq = task_rq(rq->litmus_next);
7575+ TRACE_TASK(rq->litmus_next, "migrate from %d\n", other_rq->cpu);
7576+
7577+ /* while we drop the lock, the prev task could change its
7578+ * state
7579+ */
7580+ was_running = is_running(prev);
7581+ mb();
7582+ spin_unlock(&rq->lock);
7583+
7584+ /* Don't race with a concurrent switch. This could deadlock in
7585+ * the case of cross or circular migrations. It's the job of
7586+ * the plugin to make sure that doesn't happen.
7587+ */
7588+ TRACE_TASK(rq->litmus_next, "stack_in_use=%d\n",
7589+ rq->litmus_next->rt_param.stack_in_use);
7590+ if (rq->litmus_next->rt_param.stack_in_use != NO_CPU) {
7591+ TRACE_TASK(rq->litmus_next, "waiting to deschedule\n");
7592+ _maybe_deadlock = litmus_clock();
7593+ }
7594+ while (rq->litmus_next->rt_param.stack_in_use != NO_CPU) {
7595+ cpu_relax();
7596+ mb();
7597+ if (rq->litmus_next->rt_param.stack_in_use == NO_CPU)
7598+ TRACE_TASK(rq->litmus_next,
7599+ "descheduled. Proceeding.\n");
7600+ if (lt_before(_maybe_deadlock + 10000000,
7601+ litmus_clock())) {
7602+ /* We've been spinning for 10ms.
7603+ * Something can't be right!
7604+ * Let's abandon the task and bail out; at least
7605+ * we will have debug info instead of a hard
7606+ * deadlock.
7607+ */
7608+ TRACE_TASK(rq->litmus_next,
7609+ "stack too long in use. "
7610+ "Deadlock?\n");
7611+ rq->litmus_next = NULL;
7612+
7613+ /* bail out */
7614+ spin_lock(&rq->lock);
7615+ return;
7616+ }
7617+ }
7618+#ifdef __ARCH_WANT_UNLOCKED_CTXSW
7619+ if (rq->litmus_next->oncpu)
7620+ TRACE_TASK(rq->litmus_next, "waiting for !oncpu");
7621+ while (rq->litmus_next->oncpu) {
7622+ cpu_relax();
7623+ mb();
7624+ }
7625+#endif
7626+ double_rq_lock(rq, other_rq);
7627+ mb();
7628+ if (is_realtime(prev) && is_running(prev) != was_running) {
7629+ TRACE_TASK(prev,
7630+ "state changed while we dropped"
7631+ " the lock: is_running=%d, was_running=%d\n",
7632+ is_running(prev), was_running);
7633+ if (is_running(prev) && !was_running) {
7634+ /* prev task became unblocked
7635+ * we need to simulate normal sequence of events
7636+ * to scheduler plugins.
7637+ */
7638+ litmus->task_block(prev);
7639+ litmus->task_wake_up(prev);
7640+ }
7641+ }
7642+
7643+ set_task_cpu(rq->litmus_next, smp_processor_id());
7644+
7645+ /* DEBUG: now that we have the lock we need to make sure a
7646+ * couple of things still hold:
7647+ * - it is still a real-time task
7648+ * - it is still runnable (could have been stopped)
7649+ * If either is violated, then the active plugin is
7650+ * doing something wrong.
7651+ */
7652+ if (!is_realtime(rq->litmus_next) ||
7653+ !is_running(rq->litmus_next)) {
7654+ /* BAD BAD BAD */
7655+ TRACE_TASK(rq->litmus_next,
7656+ "BAD: migration invariant FAILED: "
7657+ "rt=%d running=%d\n",
7658+ is_realtime(rq->litmus_next),
7659+ is_running(rq->litmus_next));
7660+ /* drop the task */
7661+ rq->litmus_next = NULL;
7662+ }
7663+ /* release the other CPU's runqueue, but keep ours */
7664+ spin_unlock(&other_rq->lock);
7665+ }
7666+ if (rq->litmus_next)
7667+ rq->litmus_next->rt_param.stack_in_use = rq->cpu;
7668+}
7669+
7670+static void enqueue_task_litmus(struct rq *rq, struct task_struct *p,
7671+ int wakeup)
7672+{
7673+ if (wakeup) {
7674+ sched_trace_task_resume(p);
7675+ tsk_rt(p)->present = 1;
7676+ litmus->task_wake_up(p);
7677+ } else
7678+ TRACE_TASK(p, "ignoring an enqueue, not a wake up.\n");
7679+}
7680+
7681+static void dequeue_task_litmus(struct rq *rq, struct task_struct *p, int sleep)
7682+{
7683+ if (sleep) {
7684+ litmus->task_block(p);
7685+ tsk_rt(p)->present = 0;
7686+ sched_trace_task_block(p);
7687+ } else
7688+ TRACE_TASK(p, "ignoring a dequeue, not going to sleep.\n");
7689+}
7690+
7691+static void yield_task_litmus(struct rq *rq)
7692+{
7693+ BUG_ON(rq->curr != current);
7694+ litmus->complete_job();
7695+}
7696+
7697+/* Plugins are responsible for this.
7698+ */
7699+static void check_preempt_curr_litmus(struct rq *rq, struct task_struct *p)
7700+{
7701+}
7702+
7703+/* has already been taken care of */
7704+static void put_prev_task_litmus(struct rq *rq, struct task_struct *p)
7705+{
7706+}
7707+
7708+static struct task_struct *pick_next_task_litmus(struct rq *rq)
7709+{
7710+ struct task_struct* picked = rq->litmus_next;
7711+ rq->litmus_next = NULL;
7712+ if (picked)
7713+ picked->se.exec_start = rq->clock;
7714+ return picked;
7715+}
7716+
7717+static void task_tick_litmus(struct rq *rq, struct task_struct *p)
7718+{
7719+}
7720+
7721+/* This is called when a task became a real-time task, either due to a SCHED_*
7722+ * class transition or due to PI mutex inheritance. We don't handle Linux PI
7723+ * mutex inheritance yet (and probably never will). Use LITMUS provided
7724+ * synchronization primitives instead.
7725+ */
7726+static void set_curr_task_litmus(struct rq *rq)
7727+{
7728+ rq->curr->se.exec_start = rq->clock;
7729+}
7730+
7731+
7732+#ifdef CONFIG_SMP
7733+
7734+/* we don't repartition at runtime */
7735+
7736+static unsigned long
7737+load_balance_litmus(struct rq *this_rq, int this_cpu, struct rq *busiest,
7738+ unsigned long max_load_move,
7739+ struct sched_domain *sd, enum cpu_idle_type idle,
7740+ int *all_pinned, int *this_best_prio)
7741+{
7742+ return 0;
7743+}
7744+
7745+static int
7746+move_one_task_litmus(struct rq *this_rq, int this_cpu, struct rq *busiest,
7747+ struct sched_domain *sd, enum cpu_idle_type idle)
7748+{
7749+ return 0;
7750+}
7751+#endif
7752+
7753+const struct sched_class litmus_sched_class = {
7754+ .next = &rt_sched_class,
7755+ .enqueue_task = enqueue_task_litmus,
7756+ .dequeue_task = dequeue_task_litmus,
7757+ .yield_task = yield_task_litmus,
7758+
7759+ .check_preempt_curr = check_preempt_curr_litmus,
7760+
7761+ .pick_next_task = pick_next_task_litmus,
7762+ .put_prev_task = put_prev_task_litmus,
7763+
7764+#ifdef CONFIG_SMP
7765+ .load_balance = load_balance_litmus,
7766+ .move_one_task = move_one_task_litmus,
7767+#endif
7768+
7769+ .set_curr_task = set_curr_task_litmus,
7770+ .task_tick = task_tick_litmus,
7771+};
7772diff --git a/litmus/sched_pfair.c b/litmus/sched_pfair.c
7773new file mode 100644
7774index 0000000..f623e0e
7775--- /dev/null
7776+++ b/litmus/sched_pfair.c
7777@@ -0,0 +1,882 @@
7778+/*
7779+ * kernel/sched_pfair.c
7780+ *
7781+ * Implementation of the (global) Pfair scheduling algorithm.
7782+ *
7783+ */
7784+
7785+#include <asm/div64.h>
7786+#include <linux/delay.h>
7787+#include <linux/module.h>
7788+#include <linux/spinlock.h>
7789+#include <linux/percpu.h>
7790+#include <linux/sched.h>
7791+#include <linux/list.h>
7792+
7793+#include <litmus/litmus.h>
7794+#include <litmus/jobs.h>
7795+#include <litmus/rt_domain.h>
7796+#include <litmus/sched_plugin.h>
7797+#include <litmus/sched_trace.h>
7798+
7799+#include <litmus/heap.h>
7800+
7801+struct subtask {
7802+ /* measured in quanta relative to job release */
7803+ quanta_t release;
7804+ quanta_t deadline;
7805+ quanta_t overlap; /* called "b bit" by PD^2 */
7806+ quanta_t group_deadline;
7807+};
7808+
7809+struct pfair_param {
7810+ quanta_t quanta; /* number of subtasks */
7811+ quanta_t cur; /* index of current subtask */
7812+
7813+ quanta_t release; /* in quanta */
7814+ quanta_t period; /* in quanta */
7815+
7816+ quanta_t last_quantum; /* when scheduled last */
7817+ int last_cpu; /* where scheduled last */
7818+
7819+ unsigned int sporadic_release; /* On wakeup, new sporadic release? */
7820+
7821+ struct subtask subtasks[0]; /* allocate together with pfair_param */
7822+};
7823+
7824+#define tsk_pfair(tsk) ((tsk)->rt_param.pfair)
7825+
7826+struct pfair_state {
7827+ int cpu;
7828+ volatile quanta_t cur_tick; /* updated by the CPU that is advancing
7829+ * the time */
7830+ volatile quanta_t local_tick; /* What tick is the local CPU currently
7831+ * executing? Updated only by the local
7832+ * CPU. In QEMU, this may lag behind the
7833+ * current tick. In a real system, with
7834+ * proper timers and aligned quanta,
7835+ * that should only be the
7836+ * case for a very short time after the
7837+ * time advanced. With staggered quanta,
7838+ * it will lag for the duration of the
7839+ * offset.
7840+ */
7841+
7842+ struct task_struct* linked; /* the task that should be executing */
7843+ struct task_struct* local; /* the local copy of linked */
7844+ struct task_struct* scheduled; /* what is actually scheduled */
7845+
7846+ unsigned long missed_quanta;
7847+ lt_t offset; /* stagger offset */
7848+};
7849+
7850+/* Currently, we limit the maximum period of any task to 2000 quanta.
7851+ * The reason is that it makes the implementation easier since we do not
7852+ * need to reallocate the release wheel on task arrivals.
7853+ * In the future
7854+ */
7855+#define PFAIR_MAX_PERIOD 2000
7856+
7857+/* This is the release queue wheel. It is indexed by pfair_time %
7858+ * PFAIR_MAX_PERIOD. Each heap is ordered by PFAIR priority, so that it can be
7859+ * merged with the ready queue.
7860+ */
7861+static struct heap release_queue[PFAIR_MAX_PERIOD];
7862+
7863+DEFINE_PER_CPU(struct pfair_state, pfair_state);
7864+struct pfair_state* pstate[NR_CPUS]; /* short cut */
7865+
7866+static quanta_t pfair_time = 0; /* the "official" PFAIR clock */
7867+static quanta_t merge_time = 0; /* Updated after the release queue has been
7868+ * merged. Used by drop_all_references().
7869+ */
7870+
7871+static rt_domain_t pfair;
7872+
7873+/* The pfair_lock is used to serialize all scheduling events.
7874+ */
7875+#define pfair_lock pfair.ready_lock
7876+
7877+/* Enable for lots of trace info.
7878+ * #define PFAIR_DEBUG
7879+ */
7880+
7881+#ifdef PFAIR_DEBUG
7882+#define PTRACE_TASK(t, f, args...) TRACE_TASK(t, f, ## args)
7883+#define PTRACE(f, args...) TRACE(f, ## args)
7884+#else
7885+#define PTRACE_TASK(t, f, args...)
7886+#define PTRACE(f, args...)
7887+#endif
7888+
7889+/* gcc will inline all of these accessor functions... */
7890+static struct subtask* cur_subtask(struct task_struct* t)
7891+{
7892+ return tsk_pfair(t)->subtasks + tsk_pfair(t)->cur;
7893+}
7894+
7895+static quanta_t cur_deadline(struct task_struct* t)
7896+{
7897+ return cur_subtask(t)->deadline + tsk_pfair(t)->release;
7898+}
7899+
7900+
7901+static quanta_t cur_sub_release(struct task_struct* t)
7902+{
7903+ return cur_subtask(t)->release + tsk_pfair(t)->release;
7904+}
7905+
7906+static quanta_t cur_release(struct task_struct* t)
7907+{
7908+#ifdef EARLY_RELEASE
7909+ /* only the release of the first subtask counts when we early
7910+ * release */
7911+ return tsk_pfair(t)->release;
7912+#else
7913+ return cur_sub_release(t);
7914+#endif
7915+}
7916+
7917+static quanta_t cur_overlap(struct task_struct* t)
7918+{
7919+ return cur_subtask(t)->overlap;
7920+}
7921+
7922+static quanta_t cur_group_deadline(struct task_struct* t)
7923+{
7924+ quanta_t gdl = cur_subtask(t)->group_deadline;
7925+ if (gdl)
7926+ return gdl + tsk_pfair(t)->release;
7927+ else
7928+ return gdl;
7929+}
7930+
7931+
7932+static int pfair_higher_prio(struct task_struct* first,
7933+ struct task_struct* second)
7934+{
7935+ return /* first task must exist */
7936+ first && (
7937+ /* Does the second task exist and is it a real-time task? If
7938+ * not, the first task (which is a RT task) has higher
7939+ * priority.
7940+ */
7941+ !second || !is_realtime(second) ||
7942+
7943+ /* Is the (subtask) deadline of the first task earlier?
7944+ * Then it has higher priority.
7945+ */
7946+ time_before(cur_deadline(first), cur_deadline(second)) ||
7947+
7948+ /* Do we have a deadline tie?
7949+ * Then break by B-bit.
7950+ */
7951+ (cur_deadline(first) == cur_deadline(second) &&
7952+ (cur_overlap(first) > cur_overlap(second) ||
7953+
7954+ /* Do we have a B-bit tie?
7955+ * Then break by group deadline.
7956+ */
7957+ (cur_overlap(first) == cur_overlap(second) &&
7958+ (time_after(cur_group_deadline(first),
7959+ cur_group_deadline(second)) ||
7960+
7961+ /* Do we have a group deadline tie?
7962+ * Then break by PID, which are unique.
7963+ */
7964+ (cur_group_deadline(first) ==
7965+ cur_group_deadline(second) &&
7966+ first->pid < second->pid))))));
7967+}
7968+
7969+int pfair_ready_order(struct heap_node* a, struct heap_node* b)
7970+{
7971+ return pfair_higher_prio(heap2task(a), heap2task(b));
7972+}
7973+
7974+/* return the proper release queue for time t */
7975+static struct heap* relq(quanta_t t)
7976+{
7977+ struct heap* rq = &release_queue[t % PFAIR_MAX_PERIOD];
7978+ return rq;
7979+}
7980+
7981+static void prepare_release(struct task_struct* t, quanta_t at)
7982+{
7983+ tsk_pfair(t)->release = at;
7984+ tsk_pfair(t)->cur = 0;
7985+}
7986+
7987+static void __pfair_add_release(struct task_struct* t, struct heap* queue)
7988+{
7989+ heap_insert(pfair_ready_order, queue,
7990+ tsk_rt(t)->heap_node);
7991+}
7992+
7993+static void pfair_add_release(struct task_struct* t)
7994+{
7995+ BUG_ON(heap_node_in_heap(tsk_rt(t)->heap_node));
7996+ __pfair_add_release(t, relq(cur_release(t)));
7997+}
7998+
7999+/* pull released tasks from the release queue */
8000+static void poll_releases(quanta_t time)
8001+{
8002+ __merge_ready(&pfair, relq(time));
8003+ merge_time = time;
8004+}
8005+
8006+static void check_preempt(struct task_struct* t)
8007+{
8008+ int cpu = NO_CPU;
8009+ if (tsk_rt(t)->linked_on != tsk_rt(t)->scheduled_on &&
8010+ tsk_rt(t)->present) {
8011+ /* the task can be scheduled and
8012+ * is not scheduled where it ought to be scheduled
8013+ */
8014+ cpu = tsk_rt(t)->linked_on != NO_CPU ?
8015+ tsk_rt(t)->linked_on :
8016+ tsk_rt(t)->scheduled_on;
8017+ PTRACE_TASK(t, "linked_on:%d, scheduled_on:%d\n",
8018+ tsk_rt(t)->linked_on, tsk_rt(t)->scheduled_on);
8019+ /* preempt */
8020+ if (cpu == smp_processor_id())
8021+ set_tsk_need_resched(current);
8022+ else {
8023+ smp_send_reschedule(cpu);
8024+ }
8025+ }
8026+}
8027+
8028+/* caller must hold pfair_lock */
8029+static void drop_all_references(struct task_struct *t)
8030+{
8031+ int cpu;
8032+ struct pfair_state* s;
8033+ struct heap* q;
8034+ if (heap_node_in_heap(tsk_rt(t)->heap_node)) {
8035+ /* figure out what queue the node is in */
8036+ if (time_before_eq(cur_release(t), merge_time))
8037+ q = &pfair.ready_queue;
8038+ else
8039+ q = relq(cur_release(t));
8040+ heap_delete(pfair_ready_order, q,
8041+ tsk_rt(t)->heap_node);
8042+ }
8043+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
8044+ s = &per_cpu(pfair_state, cpu);
8045+ if (s->linked == t)
8046+ s->linked = NULL;
8047+ if (s->local == t)
8048+ s->local = NULL;
8049+ if (s->scheduled == t)
8050+ s->scheduled = NULL;
8051+ }
8052+}
8053+
8054+/* returns 1 if the task needs to go the release queue */
8055+static int advance_subtask(quanta_t time, struct task_struct* t, int cpu)
8056+{
8057+ struct pfair_param* p = tsk_pfair(t);
8058+ int to_relq;
8059+ p->cur = (p->cur + 1) % p->quanta;
8060+ if (!p->cur) {
8061+ sched_trace_task_completion(t, 1);
8062+ if (tsk_rt(t)->present) {
8063+ /* we start a new job */
8064+ prepare_for_next_period(t);
8065+ sched_trace_task_release(t);
8066+ get_rt_flags(t) = RT_F_RUNNING;
8067+ p->release += p->period;
8068+ } else {
8069+ /* remove task from system until it wakes */
8070+ drop_all_references(t);
8071+ tsk_pfair(t)->sporadic_release = 1;
8072+ TRACE_TASK(t, "on %d advanced to subtask %lu (not present)\n",
8073+ cpu, p->cur);
8074+ return 0;
8075+ }
8076+ }
8077+ to_relq = time_after(cur_release(t), time);
8078+ TRACE_TASK(t, "on %d advanced to subtask %lu -> to_relq=%d\n",
8079+ cpu, p->cur, to_relq);
8080+ return to_relq;
8081+}
8082+
8083+static void advance_subtasks(quanta_t time)
8084+{
8085+ int cpu, missed;
8086+ struct task_struct* l;
8087+ struct pfair_param* p;
8088+
8089+ for_each_online_cpu(cpu) {
8090+ l = pstate[cpu]->linked;
8091+ missed = pstate[cpu]->linked != pstate[cpu]->local;
8092+ if (l) {
8093+ p = tsk_pfair(l);
8094+ p->last_quantum = time;
8095+ p->last_cpu = cpu;
8096+ if (advance_subtask(time, l, cpu)) {
8097+ pstate[cpu]->linked = NULL;
8098+ pfair_add_release(l);
8099+ }
8100+ }
8101+ }
8102+}
8103+
8104+static int target_cpu(quanta_t time, struct task_struct* t, int default_cpu)
8105+{
8106+ int cpu;
8107+ if (tsk_rt(t)->scheduled_on != NO_CPU) {
8108+ /* always observe scheduled_on linkage */
8109+ default_cpu = tsk_rt(t)->scheduled_on;
8110+ } else if (tsk_pfair(t)->last_quantum == time - 1) {
8111+ /* back2back quanta */
8112+ /* Only observe last_quantum if no scheduled_on is in the way.
8113+ * This should only kick in if a CPU missed quanta, and that
8114+ * *should* only happen in QEMU.
8115+ */
8116+ cpu = tsk_pfair(t)->last_cpu;
8117+ if (!pstate[cpu]->linked ||
8118+ tsk_rt(pstate[cpu]->linked)->scheduled_on != cpu) {
8119+ default_cpu = cpu;
8120+ }
8121+ }
8122+ return default_cpu;
8123+}
8124+
8125+/* returns one if linking was redirected */
8126+static int pfair_link(quanta_t time, int cpu,
8127+ struct task_struct* t)
8128+{
8129+ int target = target_cpu(time, t, cpu);
8130+ struct task_struct* prev = pstate[cpu]->linked;
8131+ struct task_struct* other;
8132+
8133+ if (target != cpu) {
8134+ other = pstate[target]->linked;
8135+ pstate[target]->linked = t;
8136+ tsk_rt(t)->linked_on = target;
8137+ if (!other)
8138+ /* linked ok, but reschedule this CPU */
8139+ return 1;
8140+ if (target < cpu) {
8141+ /* link other to cpu instead */
8142+ tsk_rt(other)->linked_on = cpu;
8143+ pstate[cpu]->linked = other;
8144+ if (prev) {
8145+ /* prev got pushed back into the ready queue */
8146+ tsk_rt(prev)->linked_on = NO_CPU;
8147+ __add_ready(&pfair, prev);
8148+ }
8149+ /* we are done with this cpu */
8150+ return 0;
8151+ } else {
8152+ /* re-add other, it's original CPU was not considered yet */
8153+ tsk_rt(other)->linked_on = NO_CPU;
8154+ __add_ready(&pfair, other);
8155+ /* reschedule this CPU */
8156+ return 1;
8157+ }
8158+ } else {
8159+ pstate[cpu]->linked = t;
8160+ tsk_rt(t)->linked_on = cpu;
8161+ if (prev) {
8162+ /* prev got pushed back into the ready queue */
8163+ tsk_rt(prev)->linked_on = NO_CPU;
8164+ __add_ready(&pfair, prev);
8165+ }
8166+ /* we are done with this CPU */
8167+ return 0;
8168+ }
8169+}
8170+
8171+static void schedule_subtasks(quanta_t time)
8172+{
8173+ int cpu, retry;
8174+
8175+ for_each_online_cpu(cpu) {
8176+ retry = 1;
8177+ while (retry) {
8178+ if (pfair_higher_prio(__peek_ready(&pfair),
8179+ pstate[cpu]->linked))
8180+ retry = pfair_link(time, cpu,
8181+ __take_ready(&pfair));
8182+ else
8183+ retry = 0;
8184+ }
8185+ }
8186+}
8187+
8188+static void schedule_next_quantum(quanta_t time)
8189+{
8190+ int cpu;
8191+
8192+ /* called with interrupts disabled */
8193+ PTRACE("--- Q %lu at %llu PRE-SPIN\n",
8194+ time, litmus_clock());
8195+ spin_lock(&pfair_lock);
8196+ PTRACE("<<< Q %lu at %llu\n",
8197+ time, litmus_clock());
8198+
8199+ sched_trace_quantum_boundary();
8200+
8201+ advance_subtasks(time);
8202+ poll_releases(time);
8203+ schedule_subtasks(time);
8204+
8205+ for (cpu = 0; cpu < NR_CPUS; cpu++)
8206+ if (pstate[cpu]->linked)
8207+ PTRACE_TASK(pstate[cpu]->linked,
8208+ " linked on %d.\n", cpu);
8209+ else
8210+ PTRACE("(null) linked on %d.\n", cpu);
8211+
8212+ /* We are done. Advance time. */
8213+ mb();
8214+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
8215+ if (pstate[cpu]->local_tick != pstate[cpu]->cur_tick) {
8216+ TRACE("BAD Quantum not acked on %d "
8217+ "(l:%lu c:%lu p:%lu)\n",
8218+ cpu,
8219+ pstate[cpu]->local_tick,
8220+ pstate[cpu]->cur_tick,
8221+ pfair_time);
8222+ pstate[cpu]->missed_quanta++;
8223+ }
8224+ pstate[cpu]->cur_tick = time;
8225+ }
8226+ PTRACE(">>> Q %lu at %llu\n",
8227+ time, litmus_clock());
8228+ spin_unlock(&pfair_lock);
8229+}
8230+
8231+static noinline void wait_for_quantum(quanta_t q, struct pfair_state* state)
8232+{
8233+ quanta_t loc;
8234+
8235+ goto first; /* skip mb() on first iteration */
8236+ do {
8237+ cpu_relax();
8238+ mb();
8239+ first: loc = state->cur_tick;
8240+ /* FIXME: what if loc > cur? */
8241+ } while (time_before(loc, q));
8242+ PTRACE("observed cur_tick:%lu >= q:%lu\n",
8243+ loc, q);
8244+}
8245+
8246+static quanta_t current_quantum(struct pfair_state* state)
8247+{
8248+ lt_t t = litmus_clock() - state->offset;
8249+ return time2quanta(t, FLOOR);
8250+}
8251+
8252+static void catchup_quanta(quanta_t from, quanta_t target,
8253+ struct pfair_state* state)
8254+{
8255+ quanta_t cur = from, time;
8256+ TRACE("+++< BAD catching up quanta from %lu to %lu\n",
8257+ from, target);
8258+ while (time_before(cur, target)) {
8259+ wait_for_quantum(cur, state);
8260+ cur++;
8261+ time = cmpxchg(&pfair_time,
8262+ cur - 1, /* expected */
8263+ cur /* next */
8264+ );
8265+ if (time == cur - 1)
8266+ schedule_next_quantum(cur);
8267+ }
8268+ TRACE("+++> catching up done\n");
8269+}
8270+
8271+/* pfair_tick - this function is called for every local timer
8272+ * interrupt.
8273+ */
8274+static void pfair_tick(struct task_struct* t)
8275+{
8276+ struct pfair_state* state = &__get_cpu_var(pfair_state);
8277+ quanta_t time, cur;
8278+ int retry = 10;
8279+
8280+ do {
8281+ cur = current_quantum(state);
8282+ PTRACE("q %lu at %llu\n", cur, litmus_clock());
8283+
8284+ /* Attempt to advance time. First CPU to get here
8285+ * will prepare the next quantum.
8286+ */
8287+ time = cmpxchg(&pfair_time,
8288+ cur - 1, /* expected */
8289+ cur /* next */
8290+ );
8291+ if (time == cur - 1) {
8292+ /* exchange succeeded */
8293+ wait_for_quantum(cur - 1, state);
8294+ schedule_next_quantum(cur);
8295+ retry = 0;
8296+ } else if (time_before(time, cur - 1)) {
8297+ /* the whole system missed a tick !? */
8298+ catchup_quanta(time, cur, state);
8299+ retry--;
8300+ } else if (time_after(time, cur)) {
8301+ /* our timer lagging behind!? */
8302+ TRACE("BAD pfair_time:%lu > cur:%lu\n", time, cur);
8303+ retry--;
8304+ } else {
8305+ /* Some other CPU already started scheduling
8306+ * this quantum. Let it do its job and then update.
8307+ */
8308+ retry = 0;
8309+ }
8310+ } while (retry);
8311+
8312+ /* Spin locally until time advances. */
8313+ wait_for_quantum(cur, state);
8314+
8315+ /* copy assignment */
8316+ /* FIXME: what if we race with a future update? Corrupted state? */
8317+ state->local = state->linked;
8318+ /* signal that we are done */
8319+ mb();
8320+ state->local_tick = state->cur_tick;
8321+
8322+ if (state->local != current
8323+ && (is_realtime(current) || is_present(state->local)))
8324+ set_tsk_need_resched(current);
8325+}
8326+
8327+static int safe_to_schedule(struct task_struct* t, int cpu)
8328+{
8329+ int where = tsk_rt(t)->scheduled_on;
8330+ if (where != NO_CPU && where != cpu) {
8331+ TRACE_TASK(t, "BAD: can't be scheduled on %d, "
8332+ "scheduled already on %d.\n", cpu, where);
8333+ return 0;
8334+ } else
8335+ return tsk_rt(t)->present && get_rt_flags(t) == RT_F_RUNNING;
8336+}
8337+
8338+static struct task_struct* pfair_schedule(struct task_struct * prev)
8339+{
8340+ struct pfair_state* state = &__get_cpu_var(pfair_state);
8341+ int blocks;
8342+ struct task_struct* next = NULL;
8343+
8344+ spin_lock(&pfair_lock);
8345+
8346+ blocks = is_realtime(prev) && !is_running(prev);
8347+
8348+ if (state->local && safe_to_schedule(state->local, state->cpu))
8349+ next = state->local;
8350+
8351+ if (prev != next) {
8352+ tsk_rt(prev)->scheduled_on = NO_CPU;
8353+ if (next)
8354+ tsk_rt(next)->scheduled_on = state->cpu;
8355+ }
8356+
8357+ spin_unlock(&pfair_lock);
8358+
8359+ if (next)
8360+ TRACE_TASK(next, "scheduled rel=%lu at %lu (%llu)\n",
8361+ tsk_pfair(next)->release, pfair_time, litmus_clock());
8362+ else if (is_realtime(prev))
8363+ TRACE("Becomes idle at %lu (%llu)\n", pfair_time, litmus_clock());
8364+
8365+ return next;
8366+}
8367+
8368+static void pfair_task_new(struct task_struct * t, int on_rq, int running)
8369+{
8370+ unsigned long flags;
8371+
8372+ TRACE("pfair: task new %d state:%d\n", t->pid, t->state);
8373+
8374+ spin_lock_irqsave(&pfair_lock, flags);
8375+ if (running)
8376+ t->rt_param.scheduled_on = task_cpu(t);
8377+ else
8378+ t->rt_param.scheduled_on = NO_CPU;
8379+
8380+ prepare_release(t, pfair_time + 1);
8381+ tsk_pfair(t)->sporadic_release = 0;
8382+ pfair_add_release(t);
8383+ check_preempt(t);
8384+
8385+ spin_unlock_irqrestore(&pfair_lock, flags);
8386+}
8387+
8388+static void pfair_task_wake_up(struct task_struct *t)
8389+{
8390+ unsigned long flags;
8391+ lt_t now;
8392+
8393+ TRACE_TASK(t, "wakes at %llu, release=%lu, pfair_time:%lu\n",
8394+ litmus_clock(), cur_release(t), pfair_time);
8395+
8396+ spin_lock_irqsave(&pfair_lock, flags);
8397+
8398+ /* It is a little unclear how to deal with Pfair
8399+ * tasks that block for a while and then wake. For now,
8400+ * if a task blocks and wakes before its next job release,
8401+ * then it may resume if it is currently linked somewhere
8402+ * (as if it never blocked at all). Otherwise, we have a
8403+ * new sporadic job release.
8404+ */
8405+ if (tsk_pfair(t)->sporadic_release) {
8406+ now = litmus_clock();
8407+ release_at(t, now);
8408+ prepare_release(t, time2quanta(now, CEIL));
8409+ sched_trace_task_release(t);
8410+ /* FIXME: race with pfair_time advancing */
8411+ pfair_add_release(t);
8412+ tsk_pfair(t)->sporadic_release = 0;
8413+ }
8414+
8415+ check_preempt(t);
8416+
8417+ spin_unlock_irqrestore(&pfair_lock, flags);
8418+ TRACE_TASK(t, "wake up done at %llu\n", litmus_clock());
8419+}
8420+
8421+static void pfair_task_block(struct task_struct *t)
8422+{
8423+ BUG_ON(!is_realtime(t));
8424+ TRACE_TASK(t, "blocks at %llu, state:%d\n",
8425+ litmus_clock(), t->state);
8426+}
8427+
8428+static void pfair_task_exit(struct task_struct * t)
8429+{
8430+ unsigned long flags;
8431+
8432+ BUG_ON(!is_realtime(t));
8433+
8434+ /* Remote task from release or ready queue, and ensure
8435+ * that it is not the scheduled task for ANY CPU. We
8436+ * do this blanket check because occassionally when
8437+ * tasks exit while blocked, the task_cpu of the task
8438+ * might not be the same as the CPU that the PFAIR scheduler
8439+ * has chosen for it.
8440+ */
8441+ spin_lock_irqsave(&pfair_lock, flags);
8442+
8443+ TRACE_TASK(t, "RIP, state:%d\n", t->state);
8444+ drop_all_references(t);
8445+
8446+ spin_unlock_irqrestore(&pfair_lock, flags);
8447+
8448+ kfree(t->rt_param.pfair);
8449+ t->rt_param.pfair = NULL;
8450+}
8451+
8452+
8453+static void pfair_release_at(struct task_struct* task, lt_t start)
8454+{
8455+ unsigned long flags;
8456+ quanta_t release;
8457+
8458+ BUG_ON(!is_realtime(task));
8459+
8460+ spin_lock_irqsave(&pfair_lock, flags);
8461+ release_at(task, start);
8462+ release = time2quanta(start, CEIL);
8463+
8464+ if (release - pfair_time >= PFAIR_MAX_PERIOD)
8465+ release = pfair_time + PFAIR_MAX_PERIOD;
8466+
8467+ TRACE_TASK(task, "sys release at %lu\n", release);
8468+
8469+ drop_all_references(task);
8470+ prepare_release(task, release);
8471+ pfair_add_release(task);
8472+
8473+ /* Clear sporadic release flag, since this release subsumes any
8474+ * sporadic release on wake.
8475+ */
8476+ tsk_pfair(task)->sporadic_release = 0;
8477+
8478+ spin_unlock_irqrestore(&pfair_lock, flags);
8479+}
8480+
8481+static void init_subtask(struct subtask* sub, unsigned long i,
8482+ lt_t quanta, lt_t period)
8483+{
8484+ /* since i is zero-based, the formulas are shifted by one */
8485+ lt_t tmp;
8486+
8487+ /* release */
8488+ tmp = period * i;
8489+ do_div(tmp, quanta); /* floor */
8490+ sub->release = (quanta_t) tmp;
8491+
8492+ /* deadline */
8493+ tmp = period * (i + 1);
8494+ if (do_div(tmp, quanta)) /* ceil */
8495+ tmp++;
8496+ sub->deadline = (quanta_t) tmp;
8497+
8498+ /* next release */
8499+ tmp = period * (i + 1);
8500+ do_div(tmp, quanta); /* floor */
8501+ sub->overlap = sub->deadline - (quanta_t) tmp;
8502+
8503+ /* Group deadline.
8504+ * Based on the formula given in Uma's thesis.
8505+ */
8506+ if (2 * quanta >= period) {
8507+ /* heavy */
8508+ tmp = (sub->deadline - (i + 1)) * period;
8509+ if (period > quanta &&
8510+ do_div(tmp, (period - quanta))) /* ceil */
8511+ tmp++;
8512+ sub->group_deadline = (quanta_t) tmp;
8513+ } else
8514+ sub->group_deadline = 0;
8515+}
8516+
8517+static void dump_subtasks(struct task_struct* t)
8518+{
8519+ unsigned long i;
8520+ for (i = 0; i < t->rt_param.pfair->quanta; i++)
8521+ TRACE_TASK(t, "SUBTASK %lu: rel=%lu dl=%lu bbit:%lu gdl:%lu\n",
8522+ i + 1,
8523+ t->rt_param.pfair->subtasks[i].release,
8524+ t->rt_param.pfair->subtasks[i].deadline,
8525+ t->rt_param.pfair->subtasks[i].overlap,
8526+ t->rt_param.pfair->subtasks[i].group_deadline);
8527+}
8528+
8529+static long pfair_admit_task(struct task_struct* t)
8530+{
8531+ lt_t quanta;
8532+ lt_t period;
8533+ s64 quantum_length = ktime_to_ns(tick_period);
8534+ struct pfair_param* param;
8535+ unsigned long i;
8536+
8537+ /* Pfair is a tick-based method, so the time
8538+ * of interest is jiffies. Calculate tick-based
8539+ * times for everything.
8540+ * (Ceiling of exec cost, floor of period.)
8541+ */
8542+
8543+ quanta = get_exec_cost(t);
8544+ period = get_rt_period(t);
8545+
8546+ quanta = time2quanta(get_exec_cost(t), CEIL);
8547+
8548+ if (do_div(period, quantum_length))
8549+ printk(KERN_WARNING
8550+ "The period of %s/%d is not a multiple of %llu.\n",
8551+ t->comm, t->pid, (unsigned long long) quantum_length);
8552+
8553+ if (period >= PFAIR_MAX_PERIOD) {
8554+ printk(KERN_WARNING
8555+ "PFAIR: Rejecting task %s/%d; its period is too long.\n",
8556+ t->comm, t->pid);
8557+ return -EINVAL;
8558+ }
8559+
8560+ if (quanta == period) {
8561+ /* special case: task has weight 1.0 */
8562+ printk(KERN_INFO
8563+ "Admitting weight 1.0 task. (%s/%d, %llu, %llu).\n",
8564+ t->comm, t->pid, quanta, period);
8565+ quanta = 1;
8566+ period = 1;
8567+ }
8568+
8569+ param = kmalloc(sizeof(*param) +
8570+ quanta * sizeof(struct subtask), GFP_ATOMIC);
8571+
8572+ if (!param)
8573+ return -ENOMEM;
8574+
8575+ param->quanta = quanta;
8576+ param->cur = 0;
8577+ param->release = 0;
8578+ param->period = period;
8579+
8580+ for (i = 0; i < quanta; i++)
8581+ init_subtask(param->subtasks + i, i, quanta, period);
8582+
8583+ if (t->rt_param.pfair)
8584+ /* get rid of stale allocation */
8585+ kfree(t->rt_param.pfair);
8586+
8587+ t->rt_param.pfair = param;
8588+
8589+ /* spew out some debug info */
8590+ dump_subtasks(t);
8591+
8592+ return 0;
8593+}
8594+
8595+static long pfair_activate_plugin(void)
8596+{
8597+ int cpu;
8598+ struct pfair_state* state;
8599+
8600+ state = &__get_cpu_var(pfair_state);
8601+ pfair_time = current_quantum(state);
8602+
8603+ TRACE("Activating PFAIR at q=%lu\n", pfair_time);
8604+
8605+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
8606+ state = &per_cpu(pfair_state, cpu);
8607+ state->cur_tick = pfair_time;
8608+ state->local_tick = pfair_time;
8609+ state->missed_quanta = 0;
8610+ state->offset = cpu_stagger_offset(cpu);
8611+ }
8612+
8613+ return 0;
8614+}
8615+
8616+/* Plugin object */
8617+static struct sched_plugin pfair_plugin __cacheline_aligned_in_smp = {
8618+ .plugin_name = "PFAIR",
8619+ .tick = pfair_tick,
8620+ .task_new = pfair_task_new,
8621+ .task_exit = pfair_task_exit,
8622+ .schedule = pfair_schedule,
8623+ .task_wake_up = pfair_task_wake_up,
8624+ .task_block = pfair_task_block,
8625+ .admit_task = pfair_admit_task,
8626+ .release_at = pfair_release_at,
8627+ .complete_job = complete_job,
8628+ .activate_plugin = pfair_activate_plugin,
8629+};
8630+
8631+static int __init init_pfair(void)
8632+{
8633+ int cpu, i;
8634+ struct pfair_state *state;
8635+
8636+ /* initialize release queue */
8637+ for (i = 0; i < PFAIR_MAX_PERIOD; i++)
8638+ heap_init(&release_queue[i]);
8639+
8640+ /* initialize CPU state */
8641+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
8642+ state = &per_cpu(pfair_state, cpu);
8643+ state->cpu = cpu;
8644+ state->cur_tick = 0;
8645+ state->local_tick = 0;
8646+ state->linked = NULL;
8647+ state->local = NULL;
8648+ state->scheduled = NULL;
8649+ state->missed_quanta = 0;
8650+ state->offset = cpu_stagger_offset(cpu);
8651+ pstate[cpu] = state;
8652+ }
8653+
8654+ rt_domain_init(&pfair, pfair_ready_order, NULL, NULL);
8655+ return register_sched_plugin(&pfair_plugin);
8656+}
8657+
8658+module_init(init_pfair);
8659+
8660diff --git a/litmus/sched_plugin.c b/litmus/sched_plugin.c
8661new file mode 100644
8662index 0000000..0be091e
8663--- /dev/null
8664+++ b/litmus/sched_plugin.c
8665@@ -0,0 +1,199 @@
8666+/* sched_plugin.c -- core infrastructure for the scheduler plugin system
8667+ *
8668+ * This file includes the initialization of the plugin system, the no-op Linux
8669+ * scheduler plugin and some dummy functions.
8670+ */
8671+
8672+#include <linux/list.h>
8673+#include <linux/spinlock.h>
8674+
8675+#include <litmus/litmus.h>
8676+#include <litmus/sched_plugin.h>
8677+
8678+#include <litmus/jobs.h>
8679+
8680+/*************************************************************
8681+ * Dummy plugin functions *
8682+ *************************************************************/
8683+
8684+static void litmus_dummy_finish_switch(struct task_struct * prev)
8685+{
8686+}
8687+
8688+static struct task_struct* litmus_dummy_schedule(struct task_struct * prev)
8689+{
8690+ return NULL;
8691+}
8692+
8693+static void litmus_dummy_tick(struct task_struct* tsk)
8694+{
8695+}
8696+
8697+static long litmus_dummy_admit_task(struct task_struct* tsk)
8698+{
8699+ printk(KERN_CRIT "LITMUS^RT: Linux plugin rejects %s/%d.\n",
8700+ tsk->comm, tsk->pid);
8701+ return -EINVAL;
8702+}
8703+
8704+static void litmus_dummy_task_new(struct task_struct *t, int on_rq, int running)
8705+{
8706+}
8707+
8708+static void litmus_dummy_task_wake_up(struct task_struct *task)
8709+{
8710+}
8711+
8712+static void litmus_dummy_task_block(struct task_struct *task)
8713+{
8714+}
8715+
8716+static void litmus_dummy_task_exit(struct task_struct *task)
8717+{
8718+}
8719+
8720+static long litmus_dummy_complete_job(void)
8721+{
8722+ return -ENOSYS;
8723+}
8724+
8725+static long litmus_dummy_activate_plugin(void)
8726+{
8727+ return 0;
8728+}
8729+
8730+static long litmus_dummy_deactivate_plugin(void)
8731+{
8732+ return 0;
8733+}
8734+
8735+#ifdef CONFIG_FMLP
8736+
8737+static long litmus_dummy_inherit_priority(struct pi_semaphore *sem,
8738+ struct task_struct *new_owner)
8739+{
8740+ return -ENOSYS;
8741+}
8742+
8743+static long litmus_dummy_return_priority(struct pi_semaphore *sem)
8744+{
8745+ return -ENOSYS;
8746+}
8747+
8748+static long litmus_dummy_pi_block(struct pi_semaphore *sem,
8749+ struct task_struct *new_waiter)
8750+{
8751+ return -ENOSYS;
8752+}
8753+
8754+#endif
8755+
8756+
8757+/* The default scheduler plugin. It doesn't do anything and lets Linux do its
8758+ * job.
8759+ */
8760+struct sched_plugin linux_sched_plugin = {
8761+ .plugin_name = "Linux",
8762+ .tick = litmus_dummy_tick,
8763+ .task_new = litmus_dummy_task_new,
8764+ .task_exit = litmus_dummy_task_exit,
8765+ .task_wake_up = litmus_dummy_task_wake_up,
8766+ .task_block = litmus_dummy_task_block,
8767+ .complete_job = litmus_dummy_complete_job,
8768+ .schedule = litmus_dummy_schedule,
8769+ .finish_switch = litmus_dummy_finish_switch,
8770+ .activate_plugin = litmus_dummy_activate_plugin,
8771+ .deactivate_plugin = litmus_dummy_deactivate_plugin,
8772+#ifdef CONFIG_FMLP
8773+ .inherit_priority = litmus_dummy_inherit_priority,
8774+ .return_priority = litmus_dummy_return_priority,
8775+ .pi_block = litmus_dummy_pi_block,
8776+#endif
8777+ .admit_task = litmus_dummy_admit_task
8778+};
8779+
8780+/*
8781+ * The reference to current plugin that is used to schedule tasks within
8782+ * the system. It stores references to actual function implementations
8783+ * Should be initialized by calling "init_***_plugin()"
8784+ */
8785+struct sched_plugin *litmus = &linux_sched_plugin;
8786+
8787+/* the list of registered scheduling plugins */
8788+static LIST_HEAD(sched_plugins);
8789+static DEFINE_SPINLOCK(sched_plugins_lock);
8790+
8791+#define CHECK(func) {\
8792+ if (!plugin->func) \
8793+ plugin->func = litmus_dummy_ ## func;}
8794+
8795+/* FIXME: get reference to module */
8796+int register_sched_plugin(struct sched_plugin* plugin)
8797+{
8798+ printk(KERN_INFO "Registering LITMUS^RT plugin %s.\n",
8799+ plugin->plugin_name);
8800+
8801+ /* make sure we don't trip over null pointers later */
8802+ CHECK(finish_switch);
8803+ CHECK(schedule);
8804+ CHECK(tick);
8805+ CHECK(task_wake_up);
8806+ CHECK(task_exit);
8807+ CHECK(task_block);
8808+ CHECK(task_new);
8809+ CHECK(complete_job);
8810+ CHECK(activate_plugin);
8811+ CHECK(deactivate_plugin);
8812+#ifdef CONFIG_FMLP
8813+ CHECK(inherit_priority);
8814+ CHECK(return_priority);
8815+ CHECK(pi_block);
8816+#endif
8817+ CHECK(admit_task);
8818+
8819+ if (!plugin->release_at)
8820+ plugin->release_at = release_at;
8821+
8822+ spin_lock(&sched_plugins_lock);
8823+ list_add(&plugin->list, &sched_plugins);
8824+ spin_unlock(&sched_plugins_lock);
8825+
8826+ return 0;
8827+}
8828+
8829+
8830+/* FIXME: reference counting, etc. */
8831+struct sched_plugin* find_sched_plugin(const char* name)
8832+{
8833+ struct list_head *pos;
8834+ struct sched_plugin *plugin;
8835+
8836+ spin_lock(&sched_plugins_lock);
8837+ list_for_each(pos, &sched_plugins) {
8838+ plugin = list_entry(pos, struct sched_plugin, list);
8839+ if (!strcmp(plugin->plugin_name, name))
8840+ goto out_unlock;
8841+ }
8842+ plugin = NULL;
8843+
8844+out_unlock:
8845+ spin_unlock(&sched_plugins_lock);
8846+ return plugin;
8847+}
8848+
8849+int print_sched_plugins(char* buf, int max)
8850+{
8851+ int count = 0;
8852+ struct list_head *pos;
8853+ struct sched_plugin *plugin;
8854+
8855+ spin_lock(&sched_plugins_lock);
8856+ list_for_each(pos, &sched_plugins) {
8857+ plugin = list_entry(pos, struct sched_plugin, list);
8858+ count += snprintf(buf + count, max - count, "%s\n", plugin->plugin_name);
8859+ if (max - count <= 0)
8860+ break;
8861+ }
8862+ spin_unlock(&sched_plugins_lock);
8863+ return count;
8864+}
8865diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c
8866new file mode 100644
8867index 0000000..9a2bdfc
8868--- /dev/null
8869+++ b/litmus/sched_psn_edf.c
8870@@ -0,0 +1,454 @@
8871+
8872+/*
8873+ * kernel/sched_psn_edf.c
8874+ *
8875+ * Implementation of the PSN-EDF scheduler plugin.
8876+ * Based on kern/sched_part_edf.c and kern/sched_gsn_edf.c.
8877+ *
8878+ * Suspensions and non-preemptable sections are supported.
8879+ * Priority inheritance is not supported.
8880+ */
8881+
8882+#include <linux/percpu.h>
8883+#include <linux/sched.h>
8884+#include <linux/list.h>
8885+#include <linux/spinlock.h>
8886+
8887+#include <linux/module.h>
8888+
8889+#include <litmus/litmus.h>
8890+#include <litmus/jobs.h>
8891+#include <litmus/sched_plugin.h>
8892+#include <litmus/edf_common.h>
8893+
8894+
8895+typedef struct {
8896+ rt_domain_t domain;
8897+ int cpu;
8898+ struct task_struct* scheduled; /* only RT tasks */
8899+
8900+/* scheduling lock
8901+ */
8902+#define slock domain.ready_lock
8903+/* protects the domain and
8904+ * serializes scheduling decisions
8905+ */
8906+} psnedf_domain_t;
8907+
8908+DEFINE_PER_CPU(psnedf_domain_t, psnedf_domains);
8909+
8910+#define local_edf (&__get_cpu_var(psnedf_domains).domain)
8911+#define local_pedf (&__get_cpu_var(psnedf_domains))
8912+#define remote_edf(cpu) (&per_cpu(psnedf_domains, cpu).domain)
8913+#define remote_pedf(cpu) (&per_cpu(psnedf_domains, cpu))
8914+#define task_edf(task) remote_edf(get_partition(task))
8915+#define task_pedf(task) remote_pedf(get_partition(task))
8916+
8917+
8918+static void psnedf_domain_init(psnedf_domain_t* pedf,
8919+ check_resched_needed_t check,
8920+ release_jobs_t release,
8921+ int cpu)
8922+{
8923+ edf_domain_init(&pedf->domain, check, release);
8924+ pedf->cpu = cpu;
8925+ pedf->scheduled = NULL;
8926+}
8927+
8928+static void requeue(struct task_struct* t, rt_domain_t *edf)
8929+{
8930+ if (t->state != TASK_RUNNING)
8931+ TRACE_TASK(t, "requeue: !TASK_RUNNING\n");
8932+
8933+ set_rt_flags(t, RT_F_RUNNING);
8934+ if (is_released(t, litmus_clock()))
8935+ __add_ready(edf, t);
8936+ else
8937+ add_release(edf, t); /* it has got to wait */
8938+}
8939+
8940+/* we assume the lock is being held */
8941+static void preempt(psnedf_domain_t *pedf)
8942+{
8943+ if (smp_processor_id() == pedf->cpu) {
8944+ if (pedf->scheduled && is_np(pedf->scheduled))
8945+ request_exit_np(pedf->scheduled);
8946+ else
8947+ set_tsk_need_resched(current);
8948+ } else
8949+ /* in case that it is a remote CPU we have to defer the
8950+ * the decision to the remote CPU
8951+ */
8952+ smp_send_reschedule(pedf->cpu);
8953+}
8954+
8955+/* This check is trivial in partioned systems as we only have to consider
8956+ * the CPU of the partition.
8957+ */
8958+static int psnedf_check_resched(rt_domain_t *edf)
8959+{
8960+ psnedf_domain_t *pedf = container_of(edf, psnedf_domain_t, domain);
8961+ int ret = 0;
8962+
8963+ /* because this is a callback from rt_domain_t we already hold
8964+ * the necessary lock for the ready queue
8965+ */
8966+ if (edf_preemption_needed(edf, pedf->scheduled)) {
8967+ preempt(pedf);
8968+ ret = 1;
8969+ }
8970+ return ret;
8971+}
8972+
8973+static void psnedf_tick(struct task_struct *t)
8974+{
8975+ psnedf_domain_t *pedf = local_pedf;
8976+
8977+ /* Check for inconsistency. We don't need the lock for this since
8978+ * ->scheduled is only changed in schedule, which obviously is not
8979+ * executing in parallel on this CPU
8980+ */
8981+ BUG_ON(is_realtime(t) && t != pedf->scheduled);
8982+
8983+ if (is_realtime(t) && budget_exhausted(t)) {
8984+ if (!is_np(t))
8985+ set_tsk_need_resched(t);
8986+ else {
8987+ TRACE("psnedf_scheduler_tick: "
8988+ "%d is non-preemptable, "
8989+ "preemption delayed.\n", t->pid);
8990+ request_exit_np(t);
8991+ }
8992+ }
8993+}
8994+
8995+static void job_completion(struct task_struct* t)
8996+{
8997+ TRACE_TASK(t, "job_completion().\n");
8998+ set_rt_flags(t, RT_F_SLEEP);
8999+ prepare_for_next_period(t);
9000+}
9001+
9002+static struct task_struct* psnedf_schedule(struct task_struct * prev)
9003+{
9004+ psnedf_domain_t* pedf = local_pedf;
9005+ rt_domain_t* edf = &pedf->domain;
9006+ struct task_struct* next;
9007+
9008+ int out_of_time, sleep, preempt,
9009+ np, exists, blocks, resched;
9010+
9011+ spin_lock(&pedf->slock);
9012+
9013+ /* sanity checking */
9014+ BUG_ON(pedf->scheduled && pedf->scheduled != prev);
9015+ BUG_ON(pedf->scheduled && !is_realtime(prev));
9016+
9017+ /* (0) Determine state */
9018+ exists = pedf->scheduled != NULL;
9019+ blocks = exists && !is_running(pedf->scheduled);
9020+ out_of_time = exists && budget_exhausted(pedf->scheduled);
9021+ np = exists && is_np(pedf->scheduled);
9022+ sleep = exists && get_rt_flags(pedf->scheduled) == RT_F_SLEEP;
9023+ preempt = edf_preemption_needed(edf, prev);
9024+
9025+ /* If we need to preempt do so.
9026+ * The following checks set resched to 1 in case of special
9027+ * circumstances.
9028+ */
9029+ resched = preempt;
9030+
9031+ /* If a task blocks we have no choice but to reschedule.
9032+ */
9033+ if (blocks)
9034+ resched = 1;
9035+
9036+ /* Request a sys_exit_np() call if we would like to preempt but cannot.
9037+ * Multiple calls to request_exit_np() don't hurt.
9038+ */
9039+ if (np && (out_of_time || preempt || sleep))
9040+ request_exit_np(pedf->scheduled);
9041+
9042+ /* Any task that is preemptable and either exhausts its execution
9043+ * budget or wants to sleep completes. We may have to reschedule after
9044+ * this.
9045+ */
9046+ if (!np && (out_of_time || sleep) && !blocks) {
9047+ job_completion(pedf->scheduled);
9048+ resched = 1;
9049+ }
9050+
9051+ /* The final scheduling decision. Do we need to switch for some reason?
9052+ * Switch if we are in RT mode and have no task or if we need to
9053+ * resched.
9054+ */
9055+ next = NULL;
9056+ if ((!np || blocks) && (resched || !exists)) {
9057+ /* Take care of a previously scheduled
9058+ * job by taking it out of the Linux runqueue.
9059+ */
9060+ if (pedf->scheduled && !blocks)
9061+ requeue(pedf->scheduled, edf);
9062+ next = __take_ready(edf);
9063+ } else
9064+ /* Only override Linux scheduler if we have a real-time task
9065+ * scheduled that needs to continue.
9066+ */
9067+ if (exists)
9068+ next = prev;
9069+
9070+ if (next) {
9071+ TRACE_TASK(next, " == next\n");
9072+ set_rt_flags(next, RT_F_RUNNING);
9073+ } else {
9074+ TRACE("becoming idle.\n");
9075+ }
9076+
9077+ pedf->scheduled = next;
9078+ spin_unlock(&pedf->slock);
9079+
9080+ return next;
9081+}
9082+
9083+
9084+/* Prepare a task for running in RT mode
9085+ */
9086+static void psnedf_task_new(struct task_struct * t, int on_rq, int running)
9087+{
9088+ rt_domain_t* edf = task_edf(t);
9089+ psnedf_domain_t* pedf = task_pedf(t);
9090+ unsigned long flags;
9091+
9092+ TRACE_TASK(t, "new\n");
9093+
9094+ /* setup job parameters */
9095+ release_at(t, litmus_clock());
9096+
9097+ /* The task should be running in the queue, otherwise signal
9098+ * code will try to wake it up with fatal consequences.
9099+ */
9100+ spin_lock_irqsave(&pedf->slock, flags);
9101+ if (running) {
9102+ /* there shouldn't be anything else running at the time */
9103+ BUG_ON(pedf->scheduled);
9104+ pedf->scheduled = t;
9105+ } else {
9106+ requeue(t, edf);
9107+ /* maybe we have to reschedule */
9108+ preempt(pedf);
9109+ }
9110+ spin_unlock_irqrestore(&pedf->slock, flags);
9111+}
9112+
9113+static void psnedf_task_wake_up(struct task_struct *task)
9114+{
9115+ unsigned long flags;
9116+ psnedf_domain_t* pedf = task_pedf(task);
9117+ rt_domain_t* edf = task_edf(task);
9118+ lt_t now;
9119+
9120+ TRACE_TASK(task, "wake up\n");
9121+ spin_lock_irqsave(&pedf->slock, flags);
9122+ BUG_ON(is_queued(task));
9123+ /* We need to take suspensions because of semaphores into
9124+ * account! If a job resumes after being suspended due to acquiring
9125+ * a semaphore, it should never be treated as a new job release.
9126+ *
9127+ * FIXME: This should be done in some more predictable and userspace-controlled way.
9128+ */
9129+ now = litmus_clock();
9130+ if (is_tardy(task, now) &&
9131+ get_rt_flags(task) != RT_F_EXIT_SEM) {
9132+ /* new sporadic release */
9133+ release_at(task, now);
9134+ sched_trace_task_release(task);
9135+ }
9136+ requeue(task, edf);
9137+ spin_unlock_irqrestore(&pedf->slock, flags);
9138+ TRACE_TASK(task, "wake up done\n");
9139+}
9140+
9141+static void psnedf_task_block(struct task_struct *t)
9142+{
9143+ /* only running tasks can block, thus t is in no queue */
9144+ TRACE_TASK(t, "block, state=%d\n", t->state);
9145+ BUG_ON(!is_realtime(t));
9146+ BUG_ON(is_queued(t));
9147+}
9148+
9149+static void psnedf_task_exit(struct task_struct * t)
9150+{
9151+ unsigned long flags;
9152+ psnedf_domain_t* pedf = task_pedf(t);
9153+ rt_domain_t* edf;
9154+
9155+ spin_lock_irqsave(&pedf->slock, flags);
9156+ if (is_queued(t)) {
9157+ /* dequeue */
9158+ edf = task_edf(t);
9159+ remove(edf, t);
9160+ }
9161+ if (pedf->scheduled == t)
9162+ pedf->scheduled = NULL;
9163+ preempt(pedf);
9164+ spin_unlock_irqrestore(&pedf->slock, flags);
9165+}
9166+
9167+#ifdef CONFIG_FMLP
9168+static long psnedf_pi_block(struct pi_semaphore *sem,
9169+ struct task_struct *new_waiter)
9170+{
9171+ psnedf_domain_t* pedf;
9172+ rt_domain_t* edf;
9173+ struct task_struct* t;
9174+ int cpu = get_partition(new_waiter);
9175+
9176+ BUG_ON(!new_waiter);
9177+
9178+ if (edf_higher_prio(new_waiter, sem->hp.cpu_task[cpu])) {
9179+ TRACE_TASK(new_waiter, " boosts priority\n");
9180+ pedf = task_pedf(new_waiter);
9181+ edf = task_edf(new_waiter);
9182+
9183+ /* interrupts already disabled */
9184+ spin_lock(&pedf->slock);
9185+
9186+ /* store new highest-priority task */
9187+ sem->hp.cpu_task[cpu] = new_waiter;
9188+ if (sem->holder &&
9189+ get_partition(sem->holder) == get_partition(new_waiter)) {
9190+ /* let holder inherit */
9191+ sem->holder->rt_param.inh_task = new_waiter;
9192+ t = sem->holder;
9193+ if (is_queued(t)) {
9194+ /* queued in domain*/
9195+ remove(edf, t);
9196+ /* readd to make priority change take place */
9197+ /* FIXME: this looks outdated */
9198+ if (is_released(t, litmus_clock()))
9199+ __add_ready(edf, t);
9200+ else
9201+ add_release(edf, t);
9202+ }
9203+ }
9204+
9205+ /* check if we need to reschedule */
9206+ if (edf_preemption_needed(edf, current))
9207+ preempt(pedf);
9208+
9209+ spin_unlock(&pedf->slock);
9210+ }
9211+
9212+ return 0;
9213+}
9214+
9215+static long psnedf_inherit_priority(struct pi_semaphore *sem,
9216+ struct task_struct *new_owner)
9217+{
9218+ int cpu = get_partition(new_owner);
9219+
9220+ new_owner->rt_param.inh_task = sem->hp.cpu_task[cpu];
9221+ if (sem->hp.cpu_task[cpu] && new_owner != sem->hp.cpu_task[cpu]) {
9222+ TRACE_TASK(new_owner,
9223+ "inherited priority from %s/%d\n",
9224+ sem->hp.cpu_task[cpu]->comm,
9225+ sem->hp.cpu_task[cpu]->pid);
9226+ } else
9227+ TRACE_TASK(new_owner,
9228+ "cannot inherit priority: "
9229+ "no higher priority job waits on this CPU!\n");
9230+ /* make new owner non-preemptable as required by FMLP under
9231+ * PSN-EDF.
9232+ */
9233+ make_np(new_owner);
9234+ return 0;
9235+}
9236+
9237+
9238+/* This function is called on a semaphore release, and assumes that
9239+ * the current task is also the semaphore holder.
9240+ */
9241+static long psnedf_return_priority(struct pi_semaphore *sem)
9242+{
9243+ struct task_struct* t = current;
9244+ psnedf_domain_t* pedf = task_pedf(t);
9245+ rt_domain_t* edf = task_edf(t);
9246+ int ret = 0;
9247+ int cpu = get_partition(current);
9248+
9249+
9250+ /* Find new highest-priority semaphore task
9251+ * if holder task is the current hp.cpu_task[cpu].
9252+ *
9253+ * Calling function holds sem->wait.lock.
9254+ */
9255+ if (t == sem->hp.cpu_task[cpu])
9256+ edf_set_hp_cpu_task(sem, cpu);
9257+
9258+ take_np(t);
9259+ if (current->rt_param.inh_task) {
9260+ TRACE_CUR("return priority of %s/%d\n",
9261+ current->rt_param.inh_task->comm,
9262+ current->rt_param.inh_task->pid);
9263+ spin_lock(&pedf->slock);
9264+
9265+ /* Reset inh_task to NULL. */
9266+ current->rt_param.inh_task = NULL;
9267+
9268+ /* check if we need to reschedule */
9269+ if (edf_preemption_needed(edf, current))
9270+ preempt(pedf);
9271+
9272+ spin_unlock(&pedf->slock);
9273+ } else
9274+ TRACE_CUR(" no priority to return %p\n", sem);
9275+
9276+ return ret;
9277+}
9278+
9279+#endif
9280+
9281+static long psnedf_admit_task(struct task_struct* tsk)
9282+{
9283+ return task_cpu(tsk) == tsk->rt_param.task_params.cpu ? 0 : -EINVAL;
9284+}
9285+
9286+/* Plugin object */
9287+static struct sched_plugin psn_edf_plugin __cacheline_aligned_in_smp = {
9288+ .plugin_name = "PSN-EDF",
9289+#ifdef CONFIG_SRP
9290+ .srp_active = 1,
9291+#endif
9292+ .tick = psnedf_tick,
9293+ .task_new = psnedf_task_new,
9294+ .complete_job = complete_job,
9295+ .task_exit = psnedf_task_exit,
9296+ .schedule = psnedf_schedule,
9297+ .task_wake_up = psnedf_task_wake_up,
9298+ .task_block = psnedf_task_block,
9299+#ifdef CONFIG_FMLP
9300+ .fmlp_active = 1,
9301+ .pi_block = psnedf_pi_block,
9302+ .inherit_priority = psnedf_inherit_priority,
9303+ .return_priority = psnedf_return_priority,
9304+#endif
9305+ .admit_task = psnedf_admit_task
9306+};
9307+
9308+
9309+static int __init init_psn_edf(void)
9310+{
9311+ int i;
9312+
9313+ for (i = 0; i < NR_CPUS; i++)
9314+ {
9315+ psnedf_domain_init(remote_pedf(i),
9316+ psnedf_check_resched,
9317+ NULL, i);
9318+ }
9319+ return register_sched_plugin(&psn_edf_plugin);
9320+}
9321+
9322+
9323+
9324+module_init(init_psn_edf);
9325diff --git a/litmus/sched_task_trace.c b/litmus/sched_task_trace.c
9326new file mode 100644
9327index 0000000..c9dbfb2
9328--- /dev/null
9329+++ b/litmus/sched_task_trace.c
9330@@ -0,0 +1,200 @@
9331+/* sched_task_trace.c -- record scheduling events to a byte stream
9332+ *
9333+ */
9334+
9335+#define NO_TASK_TRACE_DECLS
9336+
9337+#include <linux/module.h>
9338+#include <linux/sched.h>
9339+#include <linux/percpu.h>
9340+
9341+#include <litmus/ftdev.h>
9342+#include <litmus/litmus.h>
9343+
9344+#include <litmus/sched_trace.h>
9345+#include <litmus/feather_trace.h>
9346+#include <litmus/ftdev.h>
9347+
9348+#define FT_TASK_TRACE_MAJOR 253
9349+#define NO_EVENTS 4096 /* this is a buffer of 12 4k pages per CPU */
9350+
9351+#define now() litmus_clock()
9352+
9353+struct local_buffer {
9354+ struct st_event_record record[NO_EVENTS];
9355+ char flag[NO_EVENTS];
9356+ struct ft_buffer ftbuf;
9357+};
9358+
9359+DEFINE_PER_CPU(struct local_buffer, st_event_buffer);
9360+
9361+static struct ftdev st_dev;
9362+
9363+static int st_dev_can_open(struct ftdev *dev, unsigned int cpu)
9364+{
9365+ return cpu_online(cpu) ? 0 : -ENODEV;
9366+}
9367+
9368+static int __init init_sched_task_trace(void)
9369+{
9370+ struct local_buffer* buf;
9371+ int i, ok = 0;
9372+ ftdev_init(&st_dev, THIS_MODULE);
9373+ for (i = 0; i < NR_CPUS; i++) {
9374+ buf = &per_cpu(st_event_buffer, i);
9375+ ok += init_ft_buffer(&buf->ftbuf, NO_EVENTS,
9376+ sizeof(struct st_event_record),
9377+ buf->flag,
9378+ buf->record);
9379+ st_dev.minor[i].buf = &buf->ftbuf;
9380+ }
9381+ if (ok == NR_CPUS) {
9382+ st_dev.minor_cnt = NR_CPUS;
9383+ st_dev.can_open = st_dev_can_open;
9384+ return register_ftdev(&st_dev, "sched_trace", FT_TASK_TRACE_MAJOR);
9385+ } else
9386+ return -EINVAL;
9387+}
9388+
9389+module_init(init_sched_task_trace);
9390+
9391+
9392+static inline struct st_event_record* get_record(u8 type, struct task_struct* t)
9393+{
9394+ struct st_event_record* rec;
9395+ struct local_buffer* buf;
9396+
9397+ buf = &get_cpu_var(st_event_buffer);
9398+ if (ft_buffer_start_write(&buf->ftbuf, (void**) &rec)) {
9399+ rec->hdr.type = type;
9400+ rec->hdr.cpu = smp_processor_id();
9401+ rec->hdr.pid = t ? t->pid : 0;
9402+ rec->hdr.job = t ? t->rt_param.job_params.job_no : 0;
9403+ } else
9404+ put_cpu_var(st_event_buffer);
9405+ /* rec will be NULL if it failed */
9406+ return rec;
9407+}
9408+
9409+static inline void put_record(struct st_event_record* rec)
9410+{
9411+ struct local_buffer* buf;
9412+ buf = &__get_cpu_var(st_event_buffer);
9413+ ft_buffer_finish_write(&buf->ftbuf, rec);
9414+ put_cpu_var(st_event_buffer);
9415+}
9416+
9417+feather_callback void do_sched_trace_task_name(unsigned long id, unsigned long _task)
9418+{
9419+ struct task_struct *t = (struct task_struct*) _task;
9420+ struct st_event_record* rec = get_record(ST_NAME, t);
9421+ int i;
9422+ if (rec) {
9423+ for (i = 0; i < min(TASK_COMM_LEN, ST_NAME_LEN); i++)
9424+ rec->data.name.cmd[i] = t->comm[i];
9425+ put_record(rec);
9426+ }
9427+}
9428+
9429+feather_callback void do_sched_trace_task_param(unsigned long id, unsigned long _task)
9430+{
9431+ struct task_struct *t = (struct task_struct*) _task;
9432+ struct st_event_record* rec = get_record(ST_PARAM, t);
9433+ if (rec) {
9434+ rec->data.param.wcet = get_exec_cost(t);
9435+ rec->data.param.period = get_rt_period(t);
9436+ rec->data.param.phase = get_rt_phase(t);
9437+ rec->data.param.partition = get_partition(t);
9438+ put_record(rec);
9439+ }
9440+}
9441+
9442+feather_callback void do_sched_trace_task_release(unsigned long id, unsigned long _task)
9443+{
9444+ struct task_struct *t = (struct task_struct*) _task;
9445+ struct st_event_record* rec = get_record(ST_RELEASE, t);
9446+ if (rec) {
9447+ rec->data.release.release = get_release(t);
9448+ rec->data.release.deadline = get_deadline(t);
9449+ put_record(rec);
9450+ }
9451+}
9452+
9453+/* skipped: st_assigned_data, we don't use it atm */
9454+
9455+feather_callback void do_sched_trace_task_switch_to(unsigned long id,
9456+ unsigned long _task)
9457+{
9458+ struct task_struct *t = (struct task_struct*) _task;
9459+ struct st_event_record* rec;
9460+ if (is_realtime(t)) {
9461+ rec = get_record(ST_SWITCH_TO, t);
9462+ if (rec) {
9463+ rec->data.switch_to.when = now();
9464+ rec->data.switch_to.exec_time = get_exec_time(t);
9465+ put_record(rec);
9466+ }
9467+ }
9468+}
9469+
9470+feather_callback void do_sched_trace_task_switch_away(unsigned long id,
9471+ unsigned long _task)
9472+{
9473+ struct task_struct *t = (struct task_struct*) _task;
9474+ struct st_event_record* rec;
9475+ if (is_realtime(t)) {
9476+ rec = get_record(ST_SWITCH_AWAY, t);
9477+ if (rec) {
9478+ rec->data.switch_away.when = now();
9479+ rec->data.switch_away.exec_time = get_exec_time(t);
9480+ put_record(rec);
9481+ }
9482+ }
9483+}
9484+
9485+feather_callback void do_sched_trace_task_completion(unsigned long id,
9486+ unsigned long _task,
9487+ unsigned long forced)
9488+{
9489+ struct task_struct *t = (struct task_struct*) _task;
9490+ struct st_event_record* rec = get_record(ST_COMPLETION, t);
9491+ if (rec) {
9492+ rec->data.completion.when = now();
9493+ rec->data.completion.forced = forced;
9494+ put_record(rec);
9495+ }
9496+}
9497+
9498+feather_callback void do_sched_trace_task_block(unsigned long id,
9499+ unsigned long _task)
9500+{
9501+ struct task_struct *t = (struct task_struct*) _task;
9502+ struct st_event_record* rec = get_record(ST_BLOCK, t);
9503+ if (rec) {
9504+ rec->data.block.when = now();
9505+ put_record(rec);
9506+ }
9507+}
9508+
9509+feather_callback void do_sched_trace_task_resume(unsigned long id,
9510+ unsigned long _task)
9511+{
9512+ struct task_struct *t = (struct task_struct*) _task;
9513+ struct st_event_record* rec = get_record(ST_RESUME, t);
9514+ if (rec) {
9515+ rec->data.resume.when = now();
9516+ put_record(rec);
9517+ }
9518+}
9519+
9520+feather_callback void do_sched_trace_sys_release(unsigned long id,
9521+ unsigned long _start)
9522+{
9523+ lt_t *start = (lt_t*) _start;
9524+ struct st_event_record* rec = get_record(ST_SYS_RELEASE, NULL);
9525+ if (rec) {
9526+ rec->data.sys_release.when = now();
9527+ rec->data.sys_release.release = *start;
9528+ put_record(rec);
9529+ }
9530+}
9531diff --git a/litmus/sched_trace.c b/litmus/sched_trace.c
9532new file mode 100644
9533index 0000000..9ee6f02
9534--- /dev/null
9535+++ b/litmus/sched_trace.c
9536@@ -0,0 +1,507 @@
9537+/* sched_trace.c -- record scheduling events to a byte stream.
9538+ *
9539+ * TODO: Move ring buffer to a lockfree implementation.
9540+ */
9541+
9542+#include <linux/spinlock.h>
9543+#include <linux/fs.h>
9544+#include <linux/cdev.h>
9545+#include <asm/semaphore.h>
9546+#include <asm/uaccess.h>
9547+#include <linux/module.h>
9548+#include <linux/sysrq.h>
9549+
9550+#include <litmus/sched_trace.h>
9551+#include <litmus/litmus.h>
9552+
9553+typedef struct {
9554+ /* guard read and write pointers */
9555+ spinlock_t lock;
9556+ /* guard against concurrent freeing of buffer */
9557+ rwlock_t del_lock;
9558+
9559+ /* memory allocated for ring buffer */
9560+ unsigned long order;
9561+ char* buf;
9562+ char* end;
9563+
9564+ /* Read/write pointer. May not cross.
9565+ * They point to the position of next write and
9566+ * last read.
9567+ */
9568+ char* writep;
9569+ char* readp;
9570+
9571+} ring_buffer_t;
9572+
9573+#define EMPTY_RING_BUFFER { \
9574+ .lock = SPIN_LOCK_UNLOCKED, \
9575+ .del_lock = RW_LOCK_UNLOCKED, \
9576+ .buf = NULL, \
9577+ .end = NULL, \
9578+ .writep = NULL, \
9579+ .readp = NULL \
9580+}
9581+
9582+void rb_init(ring_buffer_t* buf)
9583+{
9584+ *buf = (ring_buffer_t) EMPTY_RING_BUFFER;
9585+}
9586+
9587+int rb_alloc_buf(ring_buffer_t* buf, unsigned long order)
9588+{
9589+ unsigned long flags;
9590+ int error = 0;
9591+ char *mem;
9592+
9593+ /* do memory allocation while not atomic */
9594+ mem = (char *) __get_free_pages(GFP_KERNEL, order);
9595+ if (!mem)
9596+ return -ENOMEM;
9597+ write_lock_irqsave(&buf->del_lock, flags);
9598+ BUG_ON(buf->buf);
9599+ buf->buf = mem;
9600+ buf->end = buf->buf + PAGE_SIZE * (1 << order) - 1;
9601+ memset(buf->buf, 0xff, buf->end - buf->buf);
9602+ buf->order = order;
9603+ buf->writep = buf->buf + 1;
9604+ buf->readp = buf->buf;
9605+ write_unlock_irqrestore(&buf->del_lock, flags);
9606+ return error;
9607+}
9608+
9609+int rb_free_buf(ring_buffer_t* buf)
9610+{
9611+ unsigned long flags;
9612+ int error = 0;
9613+ write_lock_irqsave(&buf->del_lock, flags);
9614+ BUG_ON(!buf->buf);
9615+ free_pages((unsigned long) buf->buf, buf->order);
9616+ buf->buf = NULL;
9617+ buf->end = NULL;
9618+ buf->writep = NULL;
9619+ buf->readp = NULL;
9620+ write_unlock_irqrestore(&buf->del_lock, flags);
9621+ return error;
9622+}
9623+
9624+/* Assumption: concurrent writes are serialized externally
9625+ *
9626+ * Will only succeed if there is enough space for all len bytes.
9627+ */
9628+int rb_put(ring_buffer_t* buf, char* mem, size_t len)
9629+{
9630+ unsigned long flags;
9631+ char* r , *w;
9632+ int error = 0;
9633+ read_lock_irqsave(&buf->del_lock, flags);
9634+ if (!buf->buf) {
9635+ error = -ENODEV;
9636+ goto out;
9637+ }
9638+ spin_lock(&buf->lock);
9639+ r = buf->readp;
9640+ w = buf->writep;
9641+ spin_unlock(&buf->lock);
9642+ if (r < w && buf->end - w >= len - 1) {
9643+ /* easy case: there is enough space in the buffer
9644+ * to write it in one continous chunk*/
9645+ memcpy(w, mem, len);
9646+ w += len;
9647+ if (w > buf->end)
9648+ /* special case: fit exactly into buffer
9649+ * w is now buf->end + 1
9650+ */
9651+ w = buf->buf;
9652+ } else if (w < r && r - w >= len) { /* >= len because may not cross */
9653+ /* we are constrained by the read pointer but we there
9654+ * is enough space
9655+ */
9656+ memcpy(w, mem, len);
9657+ w += len;
9658+ } else if (r <= w && buf->end - w < len - 1) {
9659+ /* the wrap around case: there may or may not be space */
9660+ if ((buf->end - w) + (r - buf->buf) >= len - 1) {
9661+ /* copy chunk that fits at the end */
9662+ memcpy(w, mem, buf->end - w + 1);
9663+ mem += buf->end - w + 1;
9664+ len -= (buf->end - w + 1);
9665+ w = buf->buf;
9666+ /* copy the rest */
9667+ memcpy(w, mem, len);
9668+ w += len;
9669+ }
9670+ else
9671+ error = -ENOMEM;
9672+ } else {
9673+ error = -ENOMEM;
9674+ }
9675+ if (!error) {
9676+ spin_lock(&buf->lock);
9677+ buf->writep = w;
9678+ spin_unlock(&buf->lock);
9679+ }
9680+ out:
9681+ read_unlock_irqrestore(&buf->del_lock, flags);
9682+ return error;
9683+}
9684+
9685+/* Assumption: concurrent reads are serialized externally */
9686+int rb_get(ring_buffer_t* buf, char* mem, size_t len)
9687+{
9688+ unsigned long flags;
9689+ char* r , *w;
9690+ int error = 0;
9691+ read_lock_irqsave(&buf->del_lock, flags);
9692+ if (!buf->buf) {
9693+ error = -ENODEV;
9694+ goto out;
9695+ }
9696+ spin_lock(&buf->lock);
9697+ r = buf->readp;
9698+ w = buf->writep;
9699+ spin_unlock(&buf->lock);
9700+
9701+ if (w <= r && buf->end - r >= len) {
9702+ /* easy case: there is enough data in the buffer
9703+ * to get it in one chunk*/
9704+ memcpy(mem, r + 1, len);
9705+ r += len;
9706+ error = len;
9707+
9708+ } else if (r + 1 < w && w - r - 1 >= len) {
9709+ /* we are constrained by the write pointer but
9710+ * there is enough data
9711+ */
9712+ memcpy(mem, r + 1, len);
9713+ r += len;
9714+ error = len;
9715+
9716+ } else if (r + 1 < w && w - r - 1 < len) {
9717+ /* we are constrained by the write pointer and there
9718+ * there is not enough data
9719+ */
9720+ memcpy(mem, r + 1, w - r - 1);
9721+ error = w - r - 1;
9722+ r += w - r - 1;
9723+
9724+ } else if (w <= r && buf->end - r < len) {
9725+ /* the wrap around case: there may or may not be enough data
9726+ * first let's get what is available
9727+ */
9728+ memcpy(mem, r + 1, buf->end - r);
9729+ error += (buf->end - r);
9730+ mem += (buf->end - r);
9731+ len -= (buf->end - r);
9732+ r += (buf->end - r);
9733+
9734+ if (w > buf->buf) {
9735+ /* there is more to get */
9736+ r = buf->buf - 1;
9737+ if (w - r >= len) {
9738+ /* plenty */
9739+ memcpy(mem, r + 1, len);
9740+ error += len;
9741+ r += len;
9742+ } else {
9743+ memcpy(mem, r + 1, w - r - 1);
9744+ error += w - r - 1;
9745+ r += w - r - 1;
9746+ }
9747+ }
9748+ } /* nothing available */
9749+
9750+ if (error > 0) {
9751+ spin_lock(&buf->lock);
9752+ buf->readp = r;
9753+ spin_unlock(&buf->lock);
9754+ }
9755+ out:
9756+ read_unlock_irqrestore(&buf->del_lock, flags);
9757+ return error;
9758+}
9759+
9760+
9761+
9762+/******************************************************************************/
9763+/* DEVICE FILE DRIVER */
9764+/******************************************************************************/
9765+
9766+
9767+
9768+/* Allocate a buffer of about 1 MB per CPU.
9769+ *
9770+ */
9771+#define BUFFER_ORDER 8
9772+
9773+typedef struct {
9774+ ring_buffer_t buf;
9775+ atomic_t reader_cnt;
9776+ struct semaphore reader_mutex;
9777+} trace_buffer_t;
9778+
9779+
9780+/* This does not initialize the semaphore!! */
9781+
9782+#define EMPTY_TRACE_BUFFER \
9783+ { .buf = EMPTY_RING_BUFFER, .reader_cnt = ATOMIC_INIT(0)}
9784+
9785+static spinlock_t log_buffer_lock = SPIN_LOCK_UNLOCKED;
9786+static trace_buffer_t log_buffer = EMPTY_TRACE_BUFFER;
9787+
9788+static void init_log_buffer(void)
9789+{
9790+ /* only initialize the mutex, the rest was initialized as part
9791+ * of the static initialization macro
9792+ */
9793+ init_MUTEX(&log_buffer.reader_mutex);
9794+}
9795+
9796+static ssize_t log_read(struct file *filp, char __user *to, size_t len,
9797+ loff_t *f_pos)
9798+{
9799+ /* we ignore f_pos, this is strictly sequential */
9800+
9801+ ssize_t error = -EINVAL;
9802+ char* mem;
9803+ trace_buffer_t *buf = filp->private_data;
9804+
9805+ if (down_interruptible(&buf->reader_mutex)) {
9806+ error = -ERESTARTSYS;
9807+ goto out;
9808+ }
9809+
9810+ if (len > 64 * 1024)
9811+ len = 64 * 1024;
9812+ mem = kmalloc(len, GFP_KERNEL);
9813+ if (!mem) {
9814+ error = -ENOMEM;
9815+ goto out_unlock;
9816+ }
9817+
9818+ error = rb_get(&buf->buf, mem, len);
9819+ while (!error) {
9820+ set_current_state(TASK_INTERRUPTIBLE);
9821+ schedule_timeout(110);
9822+ if (signal_pending(current))
9823+ error = -ERESTARTSYS;
9824+ else
9825+ error = rb_get(&buf->buf, mem, len);
9826+ }
9827+
9828+ if (error > 0 && copy_to_user(to, mem, error))
9829+ error = -EFAULT;
9830+
9831+ kfree(mem);
9832+ out_unlock:
9833+ up(&buf->reader_mutex);
9834+ out:
9835+ return error;
9836+}
9837+
9838+
9839+
9840+/* in kernel/printk.c */
9841+extern int trace_override;
9842+extern int trace_recurse;
9843+
9844+
9845+/* log_open - open the global log message ring buffer.
9846+ */
9847+static int log_open(struct inode *in, struct file *filp)
9848+{
9849+ int error = -EINVAL;
9850+ trace_buffer_t* buf;
9851+
9852+ buf = &log_buffer;
9853+
9854+ if (down_interruptible(&buf->reader_mutex)) {
9855+ error = -ERESTARTSYS;
9856+ goto out;
9857+ }
9858+
9859+ /* first open must allocate buffers */
9860+ if (atomic_inc_return(&buf->reader_cnt) == 1) {
9861+ if ((error = rb_alloc_buf(&buf->buf, BUFFER_ORDER)))
9862+ {
9863+ atomic_dec(&buf->reader_cnt);
9864+ goto out_unlock;
9865+ }
9866+ }
9867+
9868+ error = 0;
9869+ filp->private_data = buf;
9870+ printk(KERN_DEBUG "sched_trace buf: from 0x%p to 0x%p length: %x\n",
9871+ buf->buf.buf, buf->buf.end,
9872+ (unsigned int) (buf->buf.end - buf->buf.buf));
9873+ trace_override++;
9874+ out_unlock:
9875+ up(&buf->reader_mutex);
9876+ out:
9877+ return error;
9878+}
9879+
9880+static int log_release(struct inode *in, struct file *filp)
9881+{
9882+ int error = -EINVAL;
9883+ trace_buffer_t* buf = filp->private_data;
9884+
9885+ BUG_ON(!filp->private_data);
9886+
9887+ if (down_interruptible(&buf->reader_mutex)) {
9888+ error = -ERESTARTSYS;
9889+ goto out;
9890+ }
9891+
9892+ /* last release must deallocate buffers */
9893+ if (atomic_dec_return(&buf->reader_cnt) == 0) {
9894+ error = rb_free_buf(&buf->buf);
9895+ }
9896+
9897+ trace_override--;
9898+ up(&buf->reader_mutex);
9899+ out:
9900+ return error;
9901+}
9902+
9903+/******************************************************************************/
9904+/* Device Registration */
9905+/******************************************************************************/
9906+
9907+/* the major numbes are from the unassigned/local use block
9908+ *
9909+ * This should be converted to dynamic allocation at some point...
9910+ */
9911+#define LOG_MAJOR 251
9912+
9913+/* log_fops - The file operations for accessing the global LITMUS log message
9914+ * buffer.
9915+ *
9916+ * Except for opening the device file it uses the same operations as trace_fops.
9917+ */
9918+struct file_operations log_fops = {
9919+ .owner = THIS_MODULE,
9920+ .open = log_open,
9921+ .release = log_release,
9922+ .read = log_read,
9923+};
9924+
9925+static int __init register_buffer_dev(const char* name,
9926+ struct file_operations* fops,
9927+ int major, int count)
9928+{
9929+ dev_t trace_dev;
9930+ struct cdev *cdev;
9931+ int error = 0;
9932+
9933+ trace_dev = MKDEV(major, 0);
9934+ error = register_chrdev_region(trace_dev, count, name);
9935+ if (error)
9936+ {
9937+ printk(KERN_WARNING "sched trace: "
9938+ "Could not register major/minor number %d\n", major);
9939+ return error;
9940+ }
9941+ cdev = cdev_alloc();
9942+ if (!cdev) {
9943+ printk(KERN_WARNING "sched trace: "
9944+ "Could not get a cdev for %s.\n", name);
9945+ return -ENOMEM;
9946+ }
9947+ cdev->owner = THIS_MODULE;
9948+ cdev->ops = fops;
9949+ error = cdev_add(cdev, trace_dev, count);
9950+ if (error) {
9951+ printk(KERN_WARNING "sched trace: "
9952+ "add_cdev failed for %s.\n", name);
9953+ return -ENOMEM;
9954+ }
9955+ return error;
9956+
9957+}
9958+
9959+#ifdef CONFIG_MAGIC_SYSRQ
9960+
9961+static void sysrq_dump_trace_buffer(int key, struct tty_struct *tty)
9962+{
9963+ dump_trace_buffer(100);
9964+}
9965+
9966+static struct sysrq_key_op sysrq_dump_trace_buffer_op = {
9967+ .handler = sysrq_dump_trace_buffer,
9968+ .help_msg = "dump-trace-buffer(Y)",
9969+ .action_msg = "writing content of TRACE() buffer",
9970+};
9971+
9972+#endif
9973+
9974+static int __init init_sched_trace(void)
9975+{
9976+ printk("Initializing TRACE() device\n");
9977+ init_log_buffer();
9978+
9979+#ifdef CONFIG_MAGIC_SYSRQ
9980+ /* offer some debugging help */
9981+ if (!register_sysrq_key('y', &sysrq_dump_trace_buffer_op))
9982+ printk("Registered dump-trace-buffer(Y) magic sysrq.\n");
9983+ else
9984+ printk("Could not register dump-trace-buffer(Y) magic sysrq.\n");
9985+#endif
9986+
9987+
9988+ return register_buffer_dev("litmus_log", &log_fops,
9989+ LOG_MAJOR, 1);
9990+}
9991+
9992+module_init(init_sched_trace);
9993+
9994+#define MSG_SIZE 255
9995+static DEFINE_PER_CPU(char[MSG_SIZE], fmt_buffer);
9996+
9997+/* sched_trace_log_message - This is the only function that accesses the the
9998+ * log buffer inside the kernel for writing.
9999+ * Concurrent access to it is serialized via the
10000+ * log_buffer_lock.
10001+ *
10002+ * The maximum length of a formatted message is 255.
10003+ */
10004+void sched_trace_log_message(const char* fmt, ...)
10005+{
10006+ unsigned long flags;
10007+ va_list args;
10008+ size_t len;
10009+ char* buf;
10010+
10011+ va_start(args, fmt);
10012+ local_irq_save(flags);
10013+
10014+ /* format message */
10015+ buf = __get_cpu_var(fmt_buffer);
10016+ len = vscnprintf(buf, MSG_SIZE, fmt, args);
10017+
10018+ spin_lock(&log_buffer_lock);
10019+ /* Don't copy the trailing null byte, we don't want null bytes
10020+ * in a text file.
10021+ */
10022+ rb_put(&log_buffer.buf, buf, len);
10023+ spin_unlock(&log_buffer_lock);
10024+
10025+ local_irq_restore(flags);
10026+ va_end(args);
10027+}
10028+
10029+void dump_trace_buffer(int max)
10030+{
10031+ char line[80];
10032+ int len;
10033+ int count = 0;
10034+
10035+ /* potential but very unlikely race... */
10036+ trace_recurse = 1;
10037+ while ((max == 0 || count++ < max) &&
10038+ (len = rb_get(&log_buffer.buf, line, sizeof(line) - 1)) > 0) {
10039+ line[len] = '\0';
10040+ printk("%s", line);
10041+ }
10042+ trace_recurse = 0;
10043+}
10044diff --git a/litmus/srp.c b/litmus/srp.c
10045new file mode 100644
10046index 0000000..71639b9
10047--- /dev/null
10048+++ b/litmus/srp.c
10049@@ -0,0 +1,318 @@
10050+/* ************************************************************************** */
10051+/* STACK RESOURCE POLICY */
10052+/* ************************************************************************** */
10053+
10054+#include <asm/atomic.h>
10055+#include <linux/wait.h>
10056+#include <litmus/litmus.h>
10057+#include <litmus/sched_plugin.h>
10058+
10059+#include <litmus/fdso.h>
10060+
10061+#include <litmus/trace.h>
10062+
10063+
10064+#ifdef CONFIG_SRP
10065+
10066+struct srp_priority {
10067+ struct list_head list;
10068+ unsigned int period;
10069+ pid_t pid;
10070+};
10071+
10072+#define list2prio(l) list_entry(l, struct srp_priority, list)
10073+
10074+/* SRP task priority comparison function. Smaller periods have highest
10075+ * priority, tie-break is PID. Special case: period == 0 <=> no priority
10076+ */
10077+static int srp_higher_prio(struct srp_priority* first,
10078+ struct srp_priority* second)
10079+{
10080+ if (!first->period)
10081+ return 0;
10082+ else
10083+ return !second->period ||
10084+ first->period < second->period || (
10085+ first->period == second->period &&
10086+ first->pid < second->pid);
10087+}
10088+
10089+struct srp {
10090+ struct list_head ceiling;
10091+ wait_queue_head_t ceiling_blocked;
10092+};
10093+
10094+
10095+atomic_t srp_objects_in_use = ATOMIC_INIT(0);
10096+
10097+DEFINE_PER_CPU(struct srp, srp);
10098+
10099+
10100+/* Initialize SRP semaphores at boot time. */
10101+static int __init srp_init(void)
10102+{
10103+ int i;
10104+
10105+ printk("Initializing SRP per-CPU ceilings...");
10106+ for (i = 0; i < NR_CPUS; i++) {
10107+ init_waitqueue_head(&per_cpu(srp, i).ceiling_blocked);
10108+ INIT_LIST_HEAD(&per_cpu(srp, i).ceiling);
10109+ }
10110+ printk(" done!\n");
10111+
10112+ return 0;
10113+}
10114+module_init(srp_init);
10115+
10116+
10117+#define system_ceiling(srp) list2prio(srp->ceiling.next)
10118+
10119+
10120+#define UNDEF_SEM -2
10121+
10122+
10123+/* struct for uniprocessor SRP "semaphore" */
10124+struct srp_semaphore {
10125+ struct srp_priority ceiling;
10126+ struct task_struct* owner;
10127+ int cpu; /* cpu associated with this "semaphore" and resource */
10128+};
10129+
10130+#define ceiling2sem(c) container_of(c, struct srp_semaphore, ceiling)
10131+
10132+static int srp_exceeds_ceiling(struct task_struct* first,
10133+ struct srp* srp)
10134+{
10135+ return list_empty(&srp->ceiling) ||
10136+ get_rt_period(first) < system_ceiling(srp)->period ||
10137+ (get_rt_period(first) == system_ceiling(srp)->period &&
10138+ first->pid < system_ceiling(srp)->pid) ||
10139+ ceiling2sem(system_ceiling(srp))->owner == first;
10140+}
10141+
10142+static void srp_add_prio(struct srp* srp, struct srp_priority* prio)
10143+{
10144+ struct list_head *pos;
10145+ if (in_list(&prio->list)) {
10146+ printk(KERN_CRIT "WARNING: SRP violation detected, prio is already in "
10147+ "ceiling list! cpu=%d, srp=%p\n", smp_processor_id(), ceiling2sem(prio));
10148+ return;
10149+ }
10150+ list_for_each(pos, &srp->ceiling)
10151+ if (unlikely(srp_higher_prio(prio, list2prio(pos)))) {
10152+ __list_add(&prio->list, pos->prev, pos);
10153+ return;
10154+ }
10155+
10156+ list_add_tail(&prio->list, &srp->ceiling);
10157+}
10158+
10159+
10160+static void* create_srp_semaphore(void)
10161+{
10162+ struct srp_semaphore* sem;
10163+
10164+ sem = kmalloc(sizeof(*sem), GFP_KERNEL);
10165+ if (!sem)
10166+ return NULL;
10167+
10168+ INIT_LIST_HEAD(&sem->ceiling.list);
10169+ sem->ceiling.period = 0;
10170+ sem->cpu = UNDEF_SEM;
10171+ sem->owner = NULL;
10172+ atomic_inc(&srp_objects_in_use);
10173+ return sem;
10174+}
10175+
10176+static noinline int open_srp_semaphore(struct od_table_entry* entry, void* __user arg)
10177+{
10178+ struct srp_semaphore* sem = (struct srp_semaphore*) entry->obj->obj;
10179+ int ret = 0;
10180+ struct task_struct* t = current;
10181+ struct srp_priority t_prio;
10182+
10183+ TRACE("opening SRP semaphore %p, cpu=%d\n", sem, sem->cpu);
10184+ if (!srp_active())
10185+ return -EBUSY;
10186+
10187+ if (sem->cpu == UNDEF_SEM)
10188+ sem->cpu = get_partition(t);
10189+ else if (sem->cpu != get_partition(t))
10190+ ret = -EPERM;
10191+
10192+ if (ret == 0) {
10193+ t_prio.period = get_rt_period(t);
10194+ t_prio.pid = t->pid;
10195+ if (srp_higher_prio(&t_prio, &sem->ceiling)) {
10196+ sem->ceiling.period = t_prio.period;
10197+ sem->ceiling.pid = t_prio.pid;
10198+ }
10199+ }
10200+
10201+ return ret;
10202+}
10203+
10204+static void destroy_srp_semaphore(void* sem)
10205+{
10206+ /* XXX invariants */
10207+ atomic_dec(&srp_objects_in_use);
10208+ kfree(sem);
10209+}
10210+
10211+struct fdso_ops srp_sem_ops = {
10212+ .create = create_srp_semaphore,
10213+ .open = open_srp_semaphore,
10214+ .destroy = destroy_srp_semaphore
10215+};
10216+
10217+
10218+static void do_srp_down(struct srp_semaphore* sem)
10219+{
10220+ /* Update ceiling. */
10221+ srp_add_prio(&__get_cpu_var(srp), &sem->ceiling);
10222+ WARN_ON(sem->owner != NULL);
10223+ sem->owner = current;
10224+ TRACE_CUR("acquired srp 0x%p\n", sem);
10225+}
10226+
10227+static void do_srp_up(struct srp_semaphore* sem)
10228+{
10229+ /* Determine new system priority ceiling for this CPU. */
10230+ WARN_ON(!in_list(&sem->ceiling.list));
10231+ if (in_list(&sem->ceiling.list))
10232+ list_del(&sem->ceiling.list);
10233+
10234+ sem->owner = NULL;
10235+
10236+ /* Wake tasks on this CPU, if they exceed current ceiling. */
10237+ TRACE_CUR("released srp 0x%p\n", sem);
10238+ wake_up_all(&__get_cpu_var(srp).ceiling_blocked);
10239+}
10240+
10241+/* Adjust the system-wide priority ceiling if resource is claimed. */
10242+asmlinkage long sys_srp_down(int sem_od)
10243+{
10244+ int cpu;
10245+ int ret = -EINVAL;
10246+ struct srp_semaphore* sem;
10247+
10248+ /* disabling preemptions is sufficient protection since
10249+ * SRP is strictly per CPU and we don't interfere with any
10250+ * interrupt handlers
10251+ */
10252+ preempt_disable();
10253+ TS_SRP_DOWN_START;
10254+
10255+ cpu = smp_processor_id();
10256+ sem = lookup_srp_sem(sem_od);
10257+ if (sem && sem->cpu == cpu) {
10258+ do_srp_down(sem);
10259+ ret = 0;
10260+ }
10261+
10262+ TS_SRP_DOWN_END;
10263+ preempt_enable();
10264+ return ret;
10265+}
10266+
10267+/* Adjust the system-wide priority ceiling if resource is freed. */
10268+asmlinkage long sys_srp_up(int sem_od)
10269+{
10270+ int cpu;
10271+ int ret = -EINVAL;
10272+ struct srp_semaphore* sem;
10273+
10274+ preempt_disable();
10275+ TS_SRP_UP_START;
10276+
10277+ cpu = smp_processor_id();
10278+ sem = lookup_srp_sem(sem_od);
10279+
10280+ if (sem && sem->cpu == cpu) {
10281+ do_srp_up(sem);
10282+ ret = 0;
10283+ }
10284+
10285+ TS_SRP_UP_END;
10286+ preempt_enable();
10287+ return ret;
10288+}
10289+
10290+static int srp_wake_up(wait_queue_t *wait, unsigned mode, int sync,
10291+ void *key)
10292+{
10293+ int cpu = smp_processor_id();
10294+ struct task_struct *tsk = wait->private;
10295+ if (cpu != get_partition(tsk))
10296+ TRACE_TASK(tsk, "srp_wake_up on wrong cpu, partition is %d\b",
10297+ get_partition(tsk));
10298+ else if (srp_exceeds_ceiling(tsk, &__get_cpu_var(srp)))
10299+ return default_wake_function(wait, mode, sync, key);
10300+ return 0;
10301+}
10302+
10303+
10304+
10305+static void do_ceiling_block(struct task_struct *tsk)
10306+{
10307+ wait_queue_t wait = {
10308+ .private = tsk,
10309+ .func = srp_wake_up,
10310+ .task_list = {NULL, NULL}
10311+ };
10312+
10313+ tsk->state = TASK_UNINTERRUPTIBLE;
10314+ add_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait);
10315+ tsk->rt_param.srp_non_recurse = 1;
10316+ preempt_enable_no_resched();
10317+ schedule();
10318+ preempt_disable();
10319+ tsk->rt_param.srp_non_recurse = 0;
10320+ remove_wait_queue(&__get_cpu_var(srp).ceiling_blocked, &wait);
10321+}
10322+
10323+/* Wait for current task priority to exceed system-wide priority ceiling.
10324+ */
10325+void srp_ceiling_block(void)
10326+{
10327+ struct task_struct *tsk = current;
10328+
10329+ /* Only applies to real-time tasks, but optimize for RT tasks. */
10330+ if (unlikely(!is_realtime(tsk)))
10331+ return;
10332+
10333+ /* Avoid recursive ceiling blocking. */
10334+ if (unlikely(tsk->rt_param.srp_non_recurse))
10335+ return;
10336+
10337+ /* Bail out early if there aren't any SRP resources around. */
10338+ if (likely(!atomic_read(&srp_objects_in_use)))
10339+ return;
10340+
10341+ preempt_disable();
10342+ if (!srp_exceeds_ceiling(tsk, &__get_cpu_var(srp))) {
10343+ TRACE_CUR("is priority ceiling blocked.\n");
10344+ while (!srp_exceeds_ceiling(tsk, &__get_cpu_var(srp)))
10345+ do_ceiling_block(tsk);
10346+ TRACE_CUR("finally exceeds system ceiling.\n");
10347+ } else
10348+ TRACE_CUR("is not priority ceiling blocked\n");
10349+ preempt_enable();
10350+}
10351+
10352+
10353+#else
10354+
10355+asmlinkage long sys_srp_down(int sem_od)
10356+{
10357+ return -ENOSYS;
10358+}
10359+
10360+asmlinkage long sys_srp_up(int sem_od)
10361+{
10362+ return -ENOSYS;
10363+}
10364+
10365+struct fdso_ops srp_sem_ops = {};
10366+
10367+#endif
10368diff --git a/litmus/sync.c b/litmus/sync.c
10369new file mode 100644
10370index 0000000..bd2c677
10371--- /dev/null
10372+++ b/litmus/sync.c
10373@@ -0,0 +1,104 @@
10374+/* litmus/sync.c - Support for synchronous and asynchronous task system releases.
10375+ *
10376+ *
10377+ */
10378+
10379+#include <asm/atomic.h>
10380+#include <asm/uaccess.h>
10381+#include <linux/spinlock.h>
10382+#include <linux/list.h>
10383+#include <linux/sched.h>
10384+#include <linux/completion.h>
10385+
10386+#include <litmus/litmus.h>
10387+#include <litmus/sched_plugin.h>
10388+#include <litmus/jobs.h>
10389+
10390+#include <litmus/sched_trace.h>
10391+
10392+static DECLARE_COMPLETION(ts_release);
10393+
10394+static long do_wait_for_ts_release(void)
10395+{
10396+ long ret = 0;
10397+
10398+ /* If the interruption races with a release, the completion object
10399+ * may have a non-zero counter. To avoid this problem, this should
10400+ * be replaced by wait_for_completion().
10401+ *
10402+ * For debugging purposes, this is interruptible for now.
10403+ */
10404+ ret = wait_for_completion_interruptible(&ts_release);
10405+
10406+ return ret;
10407+}
10408+
10409+int count_tasks_waiting_for_release(void)
10410+{
10411+ long flags;
10412+ int task_count = 0;
10413+ struct list_head *pos;
10414+
10415+ spin_lock_irqsave(&ts_release.wait.lock, flags);
10416+ list_for_each(pos, &ts_release.wait.task_list) {
10417+ task_count++;
10418+ }
10419+ spin_unlock_irqrestore(&ts_release.wait.lock, flags);
10420+
10421+ return task_count;
10422+}
10423+
10424+static long do_release_ts(lt_t start)
10425+{
10426+ int task_count = 0;
10427+ long flags;
10428+ struct list_head *pos;
10429+ struct task_struct *t;
10430+
10431+
10432+ spin_lock_irqsave(&ts_release.wait.lock, flags);
10433+ TRACE("<<<<<< synchronous task system release >>>>>>\n");
10434+
10435+ sched_trace_sys_release(&start);
10436+ list_for_each(pos, &ts_release.wait.task_list) {
10437+ t = (struct task_struct*) list_entry(pos,
10438+ struct __wait_queue,
10439+ task_list)->private;
10440+ task_count++;
10441+ litmus->release_at(t, start + t->rt_param.task_params.phase);
10442+ sched_trace_task_release(t);
10443+ }
10444+
10445+ spin_unlock_irqrestore(&ts_release.wait.lock, flags);
10446+
10447+ complete_n(&ts_release, task_count);
10448+
10449+ return task_count;
10450+}
10451+
10452+
10453+asmlinkage long sys_wait_for_ts_release(void)
10454+{
10455+ long ret = -EPERM;
10456+ struct task_struct *t = current;
10457+
10458+ if (is_realtime(t))
10459+ ret = do_wait_for_ts_release();
10460+
10461+ return ret;
10462+}
10463+
10464+
10465+asmlinkage long sys_release_ts(lt_t __user *__delay)
10466+{
10467+ long ret;
10468+ lt_t delay;
10469+
10470+ /* FIXME: check capabilities... */
10471+
10472+ ret = copy_from_user(&delay, __delay, sizeof(delay));
10473+ if (ret == 0)
10474+ ret = do_release_ts(litmus_clock() + delay);
10475+
10476+ return ret;
10477+}
10478diff --git a/litmus/trace.c b/litmus/trace.c
10479new file mode 100644
10480index 0000000..6a13412
10481--- /dev/null
10482+++ b/litmus/trace.c
10483@@ -0,0 +1,98 @@
10484+#include <linux/module.h>
10485+
10486+#include <litmus/ftdev.h>
10487+#include <litmus/litmus.h>
10488+#include <litmus/trace.h>
10489+
10490+/******************************************************************************/
10491+/* Allocation */
10492+/******************************************************************************/
10493+
10494+static struct ftdev overhead_dev;
10495+
10496+#define trace_ts_buf overhead_dev.minor[0].buf
10497+
10498+static unsigned int ts_seq_no = 0;
10499+
10500+static inline void __save_timestamp_cpu(unsigned long event,
10501+ uint8_t type, uint8_t cpu)
10502+{
10503+ unsigned int seq_no;
10504+ struct timestamp *ts;
10505+ seq_no = fetch_and_inc((int *) &ts_seq_no);
10506+ if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) {
10507+ ts->event = event;
10508+ ts->timestamp = ft_timestamp();
10509+ ts->seq_no = seq_no;
10510+ ts->cpu = cpu;
10511+ ts->task_type = type;
10512+ ft_buffer_finish_write(trace_ts_buf, ts);
10513+ }
10514+}
10515+
10516+static inline void __save_timestamp(unsigned long event,
10517+ uint8_t type)
10518+{
10519+ __save_timestamp_cpu(event, type, raw_smp_processor_id());
10520+}
10521+
10522+feather_callback void save_timestamp(unsigned long event)
10523+{
10524+ __save_timestamp(event, TSK_UNKNOWN);
10525+}
10526+
10527+feather_callback void save_timestamp_def(unsigned long event,
10528+ unsigned long type)
10529+{
10530+ __save_timestamp(event, (uint8_t) type);
10531+}
10532+
10533+feather_callback void save_timestamp_task(unsigned long event,
10534+ unsigned long t_ptr)
10535+{
10536+ int rt = is_realtime((struct task_struct *) t_ptr);
10537+ __save_timestamp(event, rt ? TSK_RT : TSK_BE);
10538+}
10539+
10540+feather_callback void save_timestamp_cpu(unsigned long event,
10541+ unsigned long cpu)
10542+{
10543+ __save_timestamp_cpu(event, TSK_UNKNOWN, cpu);
10544+}
10545+
10546+/******************************************************************************/
10547+/* DEVICE FILE DRIVER */
10548+/******************************************************************************/
10549+
10550+#define NO_TIMESTAMPS (2 << 19) /* that should be 8 megs of ram, we may not get
10551+ * as much */
10552+#define FT_TRACE_MAJOR 252
10553+
10554+static int alloc_timestamp_buffer(struct ftdev* ftdev, unsigned int idx)
10555+{
10556+ unsigned int count = NO_TIMESTAMPS;
10557+ while (count && !trace_ts_buf) {
10558+ printk("time stamp buffer: trying to allocate %u time stamps.\n", count);
10559+ ftdev->minor[idx].buf = alloc_ft_buffer(count, sizeof(struct timestamp));
10560+ count /= 2;
10561+ }
10562+ return ftdev->minor[idx].buf ? 0 : -ENOMEM;
10563+}
10564+
10565+static void free_timestamp_buffer(struct ftdev* ftdev, unsigned int idx)
10566+{
10567+ free_ft_buffer(ftdev->minor[idx].buf);
10568+ ftdev->minor[idx].buf = NULL;
10569+}
10570+
10571+static int __init init_ft_overhead_trace(void)
10572+{
10573+ printk("Initializing Feather-Trace overhead tracing device.\n");
10574+ ftdev_init(&overhead_dev, THIS_MODULE);
10575+ overhead_dev.minor_cnt = 1; /* only one buffer */
10576+ overhead_dev.alloc = alloc_timestamp_buffer;
10577+ overhead_dev.free = free_timestamp_buffer;
10578+ return register_ftdev(&overhead_dev, "ft_trace", FT_TRACE_MAJOR);
10579+}
10580+
10581+module_init(init_ft_overhead_trace);
diff --git a/download/2008.3/qemu-config b/download/2008.3/qemu-config
new file mode 100644
index 0000000..0906a51
--- /dev/null
+++ b/download/2008.3/qemu-config
@@ -0,0 +1,1420 @@
1#
2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.24
4# Tue Apr 28 14:07:23 2009
5#
6# CONFIG_64BIT is not set
7CONFIG_X86_32=y
8# CONFIG_X86_64 is not set
9CONFIG_X86=y
10CONFIG_GENERIC_TIME=y
11CONFIG_GENERIC_CMOS_UPDATE=y
12CONFIG_CLOCKSOURCE_WATCHDOG=y
13CONFIG_GENERIC_CLOCKEVENTS=y
14CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
15CONFIG_LOCKDEP_SUPPORT=y
16CONFIG_STACKTRACE_SUPPORT=y
17CONFIG_SEMAPHORE_SLEEPERS=y
18CONFIG_MMU=y
19CONFIG_ZONE_DMA=y
20CONFIG_QUICKLIST=y
21CONFIG_GENERIC_ISA_DMA=y
22CONFIG_GENERIC_IOMAP=y
23CONFIG_GENERIC_BUG=y
24CONFIG_GENERIC_HWEIGHT=y
25CONFIG_ARCH_MAY_HAVE_PC_FDC=y
26CONFIG_DMI=y
27# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
28CONFIG_RWSEM_XCHGADD_ALGORITHM=y
29# CONFIG_ARCH_HAS_ILOG2_U32 is not set
30# CONFIG_ARCH_HAS_ILOG2_U64 is not set
31CONFIG_GENERIC_CALIBRATE_DELAY=y
32# CONFIG_GENERIC_TIME_VSYSCALL is not set
33CONFIG_ARCH_SUPPORTS_OPROFILE=y
34# CONFIG_ZONE_DMA32 is not set
35CONFIG_ARCH_POPULATES_NODE_MAP=y
36# CONFIG_AUDIT_ARCH is not set
37CONFIG_GENERIC_HARDIRQS=y
38CONFIG_GENERIC_IRQ_PROBE=y
39CONFIG_GENERIC_PENDING_IRQ=y
40CONFIG_X86_SMP=y
41CONFIG_X86_HT=y
42CONFIG_X86_BIOS_REBOOT=y
43CONFIG_X86_TRAMPOLINE=y
44CONFIG_KTIME_SCALAR=y
45CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
46
47#
48# General setup
49#
50CONFIG_EXPERIMENTAL=y
51CONFIG_LOCK_KERNEL=y
52CONFIG_INIT_ENV_ARG_LIMIT=32
53CONFIG_LOCALVERSION=""
54# CONFIG_LOCALVERSION_AUTO is not set
55CONFIG_SWAP=y
56CONFIG_SYSVIPC=y
57CONFIG_SYSVIPC_SYSCTL=y
58CONFIG_POSIX_MQUEUE=y
59# CONFIG_BSD_PROCESS_ACCT is not set
60# CONFIG_TASKSTATS is not set
61CONFIG_USER_NS=y
62CONFIG_PID_NS=y
63# CONFIG_AUDIT is not set
64CONFIG_IKCONFIG=y
65CONFIG_IKCONFIG_PROC=y
66CONFIG_LOG_BUF_SHIFT=17
67CONFIG_CGROUPS=y
68CONFIG_CGROUP_DEBUG=y
69CONFIG_CGROUP_NS=y
70# CONFIG_CPUSETS is not set
71# CONFIG_FAIR_GROUP_SCHED is not set
72# CONFIG_CGROUP_CPUACCT is not set
73CONFIG_SYSFS_DEPRECATED=y
74CONFIG_RELAY=y
75CONFIG_BLK_DEV_INITRD=y
76CONFIG_INITRAMFS_SOURCE=""
77# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
78CONFIG_SYSCTL=y
79# CONFIG_EMBEDDED is not set
80CONFIG_UID16=y
81CONFIG_SYSCTL_SYSCALL=y
82CONFIG_KALLSYMS=y
83CONFIG_KALLSYMS_ALL=y
84CONFIG_KALLSYMS_EXTRA_PASS=y
85CONFIG_HOTPLUG=y
86CONFIG_PRINTK=y
87CONFIG_BUG=y
88CONFIG_ELF_CORE=y
89CONFIG_BASE_FULL=y
90CONFIG_FUTEX=y
91CONFIG_ANON_INODES=y
92CONFIG_EPOLL=y
93CONFIG_SIGNALFD=y
94CONFIG_EVENTFD=y
95CONFIG_SHMEM=y
96CONFIG_VM_EVENT_COUNTERS=y
97CONFIG_SLAB=y
98# CONFIG_SLUB is not set
99# CONFIG_SLOB is not set
100CONFIG_SLABINFO=y
101CONFIG_RT_MUTEXES=y
102# CONFIG_TINY_SHMEM is not set
103CONFIG_BASE_SMALL=0
104# CONFIG_MODULES is not set
105CONFIG_BLOCK=y
106CONFIG_LBD=y
107CONFIG_BLK_DEV_IO_TRACE=y
108CONFIG_LSF=y
109# CONFIG_BLK_DEV_BSG is not set
110
111#
112# IO Schedulers
113#
114CONFIG_IOSCHED_NOOP=y
115# CONFIG_IOSCHED_AS is not set
116# CONFIG_IOSCHED_DEADLINE is not set
117# CONFIG_IOSCHED_CFQ is not set
118# CONFIG_DEFAULT_AS is not set
119# CONFIG_DEFAULT_DEADLINE is not set
120# CONFIG_DEFAULT_CFQ is not set
121CONFIG_DEFAULT_NOOP=y
122CONFIG_DEFAULT_IOSCHED="noop"
123
124#
125# Processor type and features
126#
127CONFIG_TICK_ONESHOT=y
128# CONFIG_NO_HZ is not set
129CONFIG_HIGH_RES_TIMERS=y
130CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
131CONFIG_SMP=y
132CONFIG_X86_PC=y
133# CONFIG_X86_ELAN is not set
134# CONFIG_X86_VOYAGER is not set
135# CONFIG_X86_NUMAQ is not set
136# CONFIG_X86_SUMMIT is not set
137# CONFIG_X86_BIGSMP is not set
138# CONFIG_X86_VISWS is not set
139# CONFIG_X86_GENERICARCH is not set
140# CONFIG_X86_ES7000 is not set
141# CONFIG_X86_VSMP is not set
142CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
143# CONFIG_PARAVIRT_GUEST is not set
144# CONFIG_M386 is not set
145# CONFIG_M486 is not set
146# CONFIG_M586 is not set
147# CONFIG_M586TSC is not set
148# CONFIG_M586MMX is not set
149# CONFIG_M686 is not set
150# CONFIG_MPENTIUMII is not set
151# CONFIG_MPENTIUMIII is not set
152# CONFIG_MPENTIUMM is not set
153CONFIG_MPENTIUM4=y
154# CONFIG_MK6 is not set
155# CONFIG_MK7 is not set
156# CONFIG_MK8 is not set
157# CONFIG_MCRUSOE is not set
158# CONFIG_MEFFICEON is not set
159# CONFIG_MWINCHIPC6 is not set
160# CONFIG_MWINCHIP2 is not set
161# CONFIG_MWINCHIP3D is not set
162# CONFIG_MGEODEGX1 is not set
163# CONFIG_MGEODE_LX is not set
164# CONFIG_MCYRIXIII is not set
165# CONFIG_MVIAC3_2 is not set
166# CONFIG_MVIAC7 is not set
167# CONFIG_MPSC is not set
168# CONFIG_MCORE2 is not set
169# CONFIG_GENERIC_CPU is not set
170# CONFIG_X86_GENERIC is not set
171CONFIG_X86_CMPXCHG=y
172CONFIG_X86_L1_CACHE_SHIFT=7
173CONFIG_X86_XADD=y
174CONFIG_X86_WP_WORKS_OK=y
175CONFIG_X86_INVLPG=y
176CONFIG_X86_BSWAP=y
177CONFIG_X86_POPAD_OK=y
178CONFIG_X86_GOOD_APIC=y
179CONFIG_X86_INTEL_USERCOPY=y
180CONFIG_X86_USE_PPRO_CHECKSUM=y
181CONFIG_X86_TSC=y
182CONFIG_X86_CMOV=y
183CONFIG_X86_MINIMUM_CPU_FAMILY=4
184# CONFIG_HPET_TIMER is not set
185CONFIG_NR_CPUS=4
186# CONFIG_SCHED_SMT is not set
187# CONFIG_SCHED_MC is not set
188# CONFIG_PREEMPT_NONE is not set
189# CONFIG_PREEMPT_VOLUNTARY is not set
190CONFIG_PREEMPT=y
191# CONFIG_PREEMPT_BKL is not set
192CONFIG_X86_LOCAL_APIC=y
193CONFIG_X86_IO_APIC=y
194CONFIG_X86_MCE=y
195CONFIG_X86_MCE_NONFATAL=y
196CONFIG_X86_MCE_P4THERMAL=y
197CONFIG_VM86=y
198# CONFIG_TOSHIBA is not set
199# CONFIG_I8K is not set
200# CONFIG_X86_REBOOTFIXUPS is not set
201# CONFIG_MICROCODE is not set
202CONFIG_X86_MSR=y
203CONFIG_X86_CPUID=y
204# CONFIG_NOHIGHMEM is not set
205CONFIG_HIGHMEM4G=y
206# CONFIG_HIGHMEM64G is not set
207CONFIG_PAGE_OFFSET=0xC0000000
208CONFIG_HIGHMEM=y
209CONFIG_ARCH_FLATMEM_ENABLE=y
210CONFIG_ARCH_SPARSEMEM_ENABLE=y
211CONFIG_ARCH_SELECT_MEMORY_MODEL=y
212CONFIG_SELECT_MEMORY_MODEL=y
213CONFIG_FLATMEM_MANUAL=y
214# CONFIG_DISCONTIGMEM_MANUAL is not set
215# CONFIG_SPARSEMEM_MANUAL is not set
216CONFIG_FLATMEM=y
217CONFIG_FLAT_NODE_MEM_MAP=y
218CONFIG_SPARSEMEM_STATIC=y
219# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
220CONFIG_SPLIT_PTLOCK_CPUS=4
221# CONFIG_RESOURCES_64BIT is not set
222CONFIG_ZONE_DMA_FLAG=1
223CONFIG_BOUNCE=y
224CONFIG_NR_QUICK=1
225CONFIG_VIRT_TO_BUS=y
226# CONFIG_HIGHPTE is not set
227# CONFIG_MATH_EMULATION is not set
228CONFIG_MTRR=y
229CONFIG_IRQBALANCE=y
230CONFIG_SECCOMP=y
231# CONFIG_HZ_100 is not set
232# CONFIG_HZ_250 is not set
233# CONFIG_HZ_300 is not set
234CONFIG_HZ_1000=y
235CONFIG_HZ=1000
236# CONFIG_KEXEC is not set
237# CONFIG_CRASH_DUMP is not set
238CONFIG_PHYSICAL_START=0x100000
239# CONFIG_RELOCATABLE is not set
240CONFIG_PHYSICAL_ALIGN=0x100000
241# CONFIG_HOTPLUG_CPU is not set
242CONFIG_COMPAT_VDSO=y
243CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
244
245#
246# Power management options
247#
248# CONFIG_PM is not set
249CONFIG_SUSPEND_SMP_POSSIBLE=y
250CONFIG_HIBERNATION_SMP_POSSIBLE=y
251
252#
253# CPU Frequency scaling
254#
255# CONFIG_CPU_FREQ is not set
256# CONFIG_CPU_IDLE is not set
257
258#
259# Bus options (PCI etc.)
260#
261CONFIG_PCI=y
262# CONFIG_PCI_GOBIOS is not set
263# CONFIG_PCI_GOMMCONFIG is not set
264# CONFIG_PCI_GODIRECT is not set
265CONFIG_PCI_GOANY=y
266CONFIG_PCI_BIOS=y
267CONFIG_PCI_DIRECT=y
268CONFIG_PCI_DOMAINS=y
269# CONFIG_PCIEPORTBUS is not set
270CONFIG_ARCH_SUPPORTS_MSI=y
271# CONFIG_PCI_MSI is not set
272# CONFIG_PCI_LEGACY is not set
273# CONFIG_PCI_DEBUG is not set
274# CONFIG_HT_IRQ is not set
275CONFIG_ISA_DMA_API=y
276CONFIG_ISA=y
277# CONFIG_EISA is not set
278# CONFIG_MCA is not set
279# CONFIG_SCx200 is not set
280CONFIG_K8_NB=y
281# CONFIG_PCCARD is not set
282# CONFIG_HOTPLUG_PCI is not set
283
284#
285# Executable file formats / Emulations
286#
287CONFIG_BINFMT_ELF=y
288CONFIG_BINFMT_AOUT=y
289CONFIG_BINFMT_MISC=y
290
291#
292# Networking
293#
294CONFIG_NET=y
295
296#
297# Networking options
298#
299CONFIG_PACKET=y
300CONFIG_PACKET_MMAP=y
301CONFIG_UNIX=y
302# CONFIG_NET_KEY is not set
303CONFIG_INET=y
304# CONFIG_IP_MULTICAST is not set
305# CONFIG_IP_ADVANCED_ROUTER is not set
306CONFIG_IP_FIB_HASH=y
307# CONFIG_IP_PNP is not set
308# CONFIG_NET_IPIP is not set
309# CONFIG_NET_IPGRE is not set
310# CONFIG_ARPD is not set
311# CONFIG_SYN_COOKIES is not set
312# CONFIG_INET_AH is not set
313# CONFIG_INET_ESP is not set
314# CONFIG_INET_IPCOMP is not set
315# CONFIG_INET_XFRM_TUNNEL is not set
316# CONFIG_INET_TUNNEL is not set
317# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
318# CONFIG_INET_XFRM_MODE_TUNNEL is not set
319# CONFIG_INET_XFRM_MODE_BEET is not set
320# CONFIG_INET_LRO is not set
321# CONFIG_INET_DIAG is not set
322# CONFIG_TCP_CONG_ADVANCED is not set
323CONFIG_TCP_CONG_CUBIC=y
324CONFIG_DEFAULT_TCP_CONG="cubic"
325# CONFIG_TCP_MD5SIG is not set
326# CONFIG_IPV6 is not set
327# CONFIG_INET6_XFRM_TUNNEL is not set
328# CONFIG_INET6_TUNNEL is not set
329# CONFIG_NETWORK_SECMARK is not set
330# CONFIG_NETFILTER is not set
331# CONFIG_IP_DCCP is not set
332# CONFIG_IP_SCTP is not set
333# CONFIG_TIPC is not set
334# CONFIG_ATM is not set
335# CONFIG_BRIDGE is not set
336# CONFIG_VLAN_8021Q is not set
337# CONFIG_DECNET is not set
338# CONFIG_LLC2 is not set
339# CONFIG_IPX is not set
340# CONFIG_ATALK is not set
341# CONFIG_X25 is not set
342# CONFIG_LAPB is not set
343# CONFIG_ECONET is not set
344# CONFIG_WAN_ROUTER is not set
345# CONFIG_NET_SCHED is not set
346
347#
348# Network testing
349#
350# CONFIG_NET_PKTGEN is not set
351# CONFIG_HAMRADIO is not set
352# CONFIG_IRDA is not set
353# CONFIG_BT is not set
354# CONFIG_AF_RXRPC is not set
355
356#
357# Wireless
358#
359# CONFIG_CFG80211 is not set
360# CONFIG_WIRELESS_EXT is not set
361# CONFIG_MAC80211 is not set
362# CONFIG_IEEE80211 is not set
363# CONFIG_RFKILL is not set
364# CONFIG_NET_9P is not set
365
366#
367# Device Drivers
368#
369
370#
371# Generic Driver Options
372#
373CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
374CONFIG_STANDALONE=y
375CONFIG_PREVENT_FIRMWARE_BUILD=y
376CONFIG_FW_LOADER=y
377# CONFIG_DEBUG_DRIVER is not set
378# CONFIG_DEBUG_DEVRES is not set
379# CONFIG_SYS_HYPERVISOR is not set
380CONFIG_CONNECTOR=y
381CONFIG_PROC_EVENTS=y
382# CONFIG_MTD is not set
383# CONFIG_PARPORT is not set
384CONFIG_PNP=y
385# CONFIG_PNP_DEBUG is not set
386
387#
388# Protocols
389#
390CONFIG_ISAPNP=y
391# CONFIG_PNPBIOS is not set
392# CONFIG_PNPACPI is not set
393# CONFIG_BLK_DEV is not set
394# CONFIG_MISC_DEVICES is not set
395CONFIG_IDE=y
396CONFIG_BLK_DEV_IDE=y
397
398#
399# Please see Documentation/ide.txt for help/info on IDE drives
400#
401# CONFIG_BLK_DEV_IDE_SATA is not set
402# CONFIG_BLK_DEV_HD_IDE is not set
403CONFIG_BLK_DEV_IDEDISK=y
404CONFIG_IDEDISK_MULTI_MODE=y
405# CONFIG_BLK_DEV_IDECD is not set
406# CONFIG_BLK_DEV_IDETAPE is not set
407CONFIG_BLK_DEV_IDEFLOPPY=y
408# CONFIG_BLK_DEV_IDESCSI is not set
409# CONFIG_IDE_TASK_IOCTL is not set
410CONFIG_IDE_PROC_FS=y
411
412#
413# IDE chipset support/bugfixes
414#
415CONFIG_IDE_GENERIC=y
416# CONFIG_BLK_DEV_PLATFORM is not set
417# CONFIG_BLK_DEV_CMD640 is not set
418# CONFIG_BLK_DEV_IDEPNP is not set
419
420#
421# PCI IDE chipsets support
422#
423CONFIG_BLK_DEV_IDEPCI=y
424CONFIG_IDEPCI_SHARE_IRQ=y
425CONFIG_IDEPCI_PCIBUS_ORDER=y
426# CONFIG_BLK_DEV_OFFBOARD is not set
427CONFIG_BLK_DEV_GENERIC=y
428# CONFIG_BLK_DEV_OPTI621 is not set
429CONFIG_BLK_DEV_RZ1000=y
430CONFIG_BLK_DEV_IDEDMA_PCI=y
431CONFIG_BLK_DEV_AEC62XX=y
432CONFIG_BLK_DEV_ALI15X3=y
433# CONFIG_WDC_ALI15X3 is not set
434CONFIG_BLK_DEV_AMD74XX=y
435CONFIG_BLK_DEV_ATIIXP=y
436CONFIG_BLK_DEV_CMD64X=y
437CONFIG_BLK_DEV_TRIFLEX=y
438CONFIG_BLK_DEV_CY82C693=y
439# CONFIG_BLK_DEV_CS5520 is not set
440CONFIG_BLK_DEV_CS5530=y
441# CONFIG_BLK_DEV_CS5535 is not set
442CONFIG_BLK_DEV_HPT34X=y
443# CONFIG_HPT34X_AUTODMA is not set
444CONFIG_BLK_DEV_HPT366=y
445CONFIG_BLK_DEV_JMICRON=y
446CONFIG_BLK_DEV_SC1200=y
447CONFIG_BLK_DEV_PIIX=y
448# CONFIG_BLK_DEV_IT8213 is not set
449CONFIG_BLK_DEV_IT821X=y
450CONFIG_BLK_DEV_NS87415=y
451CONFIG_BLK_DEV_PDC202XX_OLD=y
452CONFIG_PDC202XX_BURST=y
453CONFIG_BLK_DEV_PDC202XX_NEW=y
454CONFIG_BLK_DEV_SVWKS=y
455CONFIG_BLK_DEV_SIIMAGE=y
456CONFIG_BLK_DEV_SIS5513=y
457CONFIG_BLK_DEV_SLC90E66=y
458CONFIG_BLK_DEV_TRM290=y
459CONFIG_BLK_DEV_VIA82CXXX=y
460# CONFIG_BLK_DEV_TC86C001 is not set
461# CONFIG_IDE_ARM is not set
462
463#
464# Other IDE chipsets support
465#
466
467#
468# Note: most of these also require special kernel boot parameters
469#
470# CONFIG_BLK_DEV_4DRIVES is not set
471# CONFIG_BLK_DEV_ALI14XX is not set
472# CONFIG_BLK_DEV_DTC2278 is not set
473# CONFIG_BLK_DEV_HT6560B is not set
474# CONFIG_BLK_DEV_QD65XX is not set
475# CONFIG_BLK_DEV_UMC8672 is not set
476CONFIG_BLK_DEV_IDEDMA=y
477CONFIG_IDE_ARCH_OBSOLETE_INIT=y
478# CONFIG_BLK_DEV_HD is not set
479
480#
481# SCSI device support
482#
483# CONFIG_RAID_ATTRS is not set
484CONFIG_SCSI=y
485CONFIG_SCSI_DMA=y
486# CONFIG_SCSI_TGT is not set
487# CONFIG_SCSI_NETLINK is not set
488# CONFIG_SCSI_PROC_FS is not set
489
490#
491# SCSI support type (disk, tape, CD-ROM)
492#
493# CONFIG_BLK_DEV_SD is not set
494# CONFIG_CHR_DEV_ST is not set
495# CONFIG_CHR_DEV_OSST is not set
496# CONFIG_BLK_DEV_SR is not set
497# CONFIG_CHR_DEV_SG is not set
498# CONFIG_CHR_DEV_SCH is not set
499
500#
501# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
502#
503# CONFIG_SCSI_MULTI_LUN is not set
504# CONFIG_SCSI_CONSTANTS is not set
505# CONFIG_SCSI_LOGGING is not set
506# CONFIG_SCSI_SCAN_ASYNC is not set
507
508#
509# SCSI Transports
510#
511# CONFIG_SCSI_SPI_ATTRS is not set
512# CONFIG_SCSI_FC_ATTRS is not set
513# CONFIG_SCSI_ISCSI_ATTRS is not set
514# CONFIG_SCSI_SAS_LIBSAS is not set
515# CONFIG_SCSI_SRP_ATTRS is not set
516# CONFIG_SCSI_LOWLEVEL is not set
517CONFIG_ATA=y
518# CONFIG_ATA_NONSTANDARD is not set
519# CONFIG_SATA_AHCI is not set
520# CONFIG_SATA_SVW is not set
521# CONFIG_ATA_PIIX is not set
522# CONFIG_SATA_MV is not set
523# CONFIG_SATA_NV is not set
524# CONFIG_PDC_ADMA is not set
525# CONFIG_SATA_QSTOR is not set
526# CONFIG_SATA_PROMISE is not set
527# CONFIG_SATA_SX4 is not set
528# CONFIG_SATA_SIL is not set
529# CONFIG_SATA_SIL24 is not set
530# CONFIG_SATA_SIS is not set
531# CONFIG_SATA_ULI is not set
532# CONFIG_SATA_VIA is not set
533# CONFIG_SATA_VITESSE is not set
534# CONFIG_SATA_INIC162X is not set
535# CONFIG_PATA_ALI is not set
536# CONFIG_PATA_AMD is not set
537# CONFIG_PATA_ARTOP is not set
538# CONFIG_PATA_ATIIXP is not set
539# CONFIG_PATA_CMD640_PCI is not set
540# CONFIG_PATA_CMD64X is not set
541# CONFIG_PATA_CS5520 is not set
542# CONFIG_PATA_CS5530 is not set
543# CONFIG_PATA_CS5535 is not set
544# CONFIG_PATA_CS5536 is not set
545# CONFIG_PATA_CYPRESS is not set
546# CONFIG_PATA_EFAR is not set
547# CONFIG_ATA_GENERIC is not set
548# CONFIG_PATA_HPT366 is not set
549# CONFIG_PATA_HPT37X is not set
550# CONFIG_PATA_HPT3X2N is not set
551# CONFIG_PATA_HPT3X3 is not set
552# CONFIG_PATA_ISAPNP is not set
553# CONFIG_PATA_IT821X is not set
554# CONFIG_PATA_IT8213 is not set
555# CONFIG_PATA_JMICRON is not set
556# CONFIG_PATA_LEGACY is not set
557# CONFIG_PATA_TRIFLEX is not set
558# CONFIG_PATA_MARVELL is not set
559# CONFIG_PATA_MPIIX is not set
560CONFIG_PATA_OLDPIIX=y
561# CONFIG_PATA_NETCELL is not set
562# CONFIG_PATA_NS87410 is not set
563# CONFIG_PATA_NS87415 is not set
564# CONFIG_PATA_OPTI is not set
565# CONFIG_PATA_OPTIDMA is not set
566# CONFIG_PATA_PDC_OLD is not set
567# CONFIG_PATA_QDI is not set
568# CONFIG_PATA_RADISYS is not set
569# CONFIG_PATA_RZ1000 is not set
570# CONFIG_PATA_SC1200 is not set
571# CONFIG_PATA_SERVERWORKS is not set
572# CONFIG_PATA_PDC2027X is not set
573# CONFIG_PATA_SIL680 is not set
574# CONFIG_PATA_SIS is not set
575# CONFIG_PATA_VIA is not set
576# CONFIG_PATA_WINBOND is not set
577# CONFIG_PATA_WINBOND_VLB is not set
578# CONFIG_MD is not set
579# CONFIG_FUSION is not set
580
581#
582# IEEE 1394 (FireWire) support
583#
584# CONFIG_FIREWIRE is not set
585# CONFIG_IEEE1394 is not set
586# CONFIG_I2O is not set
587# CONFIG_MACINTOSH_DRIVERS is not set
588CONFIG_NETDEVICES=y
589# CONFIG_NETDEVICES_MULTIQUEUE is not set
590CONFIG_DUMMY=y
591CONFIG_BONDING=y
592# CONFIG_MACVLAN is not set
593CONFIG_EQUALIZER=y
594CONFIG_TUN=y
595# CONFIG_VETH is not set
596CONFIG_NET_SB1000=y
597# CONFIG_ARCNET is not set
598# CONFIG_PHYLIB is not set
599CONFIG_NET_ETHERNET=y
600CONFIG_MII=y
601CONFIG_HAPPYMEAL=y
602CONFIG_SUNGEM=y
603CONFIG_CASSINI=y
604CONFIG_NET_VENDOR_3COM=y
605CONFIG_EL1=y
606CONFIG_EL2=y
607CONFIG_ELPLUS=y
608CONFIG_EL16=y
609CONFIG_EL3=y
610CONFIG_3C515=y
611CONFIG_VORTEX=y
612CONFIG_TYPHOON=y
613CONFIG_LANCE=y
614CONFIG_NET_VENDOR_SMC=y
615CONFIG_WD80x3=y
616CONFIG_ULTRA=y
617CONFIG_SMC9194=y
618CONFIG_NET_VENDOR_RACAL=y
619CONFIG_NI52=y
620CONFIG_NI65=y
621CONFIG_NET_TULIP=y
622CONFIG_DE2104X=y
623CONFIG_TULIP=y
624# CONFIG_TULIP_MWI is not set
625# CONFIG_TULIP_MMIO is not set
626# CONFIG_TULIP_NAPI is not set
627CONFIG_DE4X5=y
628CONFIG_WINBOND_840=y
629CONFIG_DM9102=y
630CONFIG_ULI526X=y
631CONFIG_AT1700=y
632CONFIG_DEPCA=y
633CONFIG_HP100=y
634CONFIG_NET_ISA=y
635CONFIG_E2100=y
636CONFIG_EWRK3=y
637CONFIG_EEXPRESS=y
638CONFIG_EEXPRESS_PRO=y
639CONFIG_HPLAN_PLUS=y
640CONFIG_HPLAN=y
641CONFIG_LP486E=y
642CONFIG_ETH16I=y
643CONFIG_NE2000=y
644CONFIG_ZNET=y
645CONFIG_SEEQ8005=y
646# CONFIG_IBM_NEW_EMAC_ZMII is not set
647# CONFIG_IBM_NEW_EMAC_RGMII is not set
648# CONFIG_IBM_NEW_EMAC_TAH is not set
649# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
650CONFIG_NET_PCI=y
651CONFIG_PCNET32=y
652# CONFIG_PCNET32_NAPI is not set
653CONFIG_AMD8111_ETH=y
654# CONFIG_AMD8111E_NAPI is not set
655CONFIG_ADAPTEC_STARFIRE=y
656# CONFIG_ADAPTEC_STARFIRE_NAPI is not set
657CONFIG_AC3200=y
658CONFIG_APRICOT=y
659CONFIG_B44=y
660CONFIG_B44_PCI_AUTOSELECT=y
661CONFIG_B44_PCICORE_AUTOSELECT=y
662CONFIG_B44_PCI=y
663CONFIG_FORCEDETH=y
664# CONFIG_FORCEDETH_NAPI is not set
665CONFIG_CS89x0=y
666CONFIG_EEPRO100=y
667CONFIG_E100=y
668CONFIG_FEALNX=y
669CONFIG_NATSEMI=y
670CONFIG_NE2K_PCI=y
671CONFIG_8139CP=y
672CONFIG_8139TOO=y
673# CONFIG_8139TOO_PIO is not set
674CONFIG_8139TOO_TUNE_TWISTER=y
675CONFIG_8139TOO_8129=y
676# CONFIG_8139_OLD_RX_RESET is not set
677CONFIG_SIS900=y
678CONFIG_EPIC100=y
679CONFIG_SUNDANCE=y
680# CONFIG_SUNDANCE_MMIO is not set
681CONFIG_TLAN=y
682CONFIG_VIA_RHINE=y
683# CONFIG_VIA_RHINE_MMIO is not set
684# CONFIG_VIA_RHINE_NAPI is not set
685# CONFIG_SC92031 is not set
686CONFIG_NETDEV_1000=y
687# CONFIG_ACENIC is not set
688# CONFIG_DL2K is not set
689# CONFIG_E1000 is not set
690# CONFIG_E1000E is not set
691# CONFIG_IP1000 is not set
692# CONFIG_NS83820 is not set
693# CONFIG_HAMACHI is not set
694# CONFIG_YELLOWFIN is not set
695# CONFIG_R8169 is not set
696# CONFIG_SIS190 is not set
697# CONFIG_SKGE is not set
698# CONFIG_SKY2 is not set
699# CONFIG_SK98LIN is not set
700# CONFIG_VIA_VELOCITY is not set
701CONFIG_TIGON3=y
702# CONFIG_BNX2 is not set
703# CONFIG_QLA3XXX is not set
704# CONFIG_ATL1 is not set
705# CONFIG_NETDEV_10000 is not set
706# CONFIG_TR is not set
707
708#
709# Wireless LAN
710#
711# CONFIG_WLAN_PRE80211 is not set
712# CONFIG_WLAN_80211 is not set
713# CONFIG_WAN is not set
714# CONFIG_FDDI is not set
715# CONFIG_HIPPI is not set
716CONFIG_PPP=y
717CONFIG_PPP_MULTILINK=y
718CONFIG_PPP_FILTER=y
719CONFIG_PPP_ASYNC=y
720CONFIG_PPP_SYNC_TTY=y
721CONFIG_PPP_DEFLATE=y
722CONFIG_PPP_BSDCOMP=y
723CONFIG_PPP_MPPE=y
724CONFIG_PPPOE=y
725# CONFIG_PPPOL2TP is not set
726CONFIG_SLIP=y
727# CONFIG_SLIP_COMPRESSED is not set
728CONFIG_SLHC=y
729# CONFIG_SLIP_SMART is not set
730# CONFIG_SLIP_MODE_SLIP6 is not set
731# CONFIG_NET_FC is not set
732# CONFIG_SHAPER is not set
733CONFIG_NETCONSOLE=y
734# CONFIG_NETCONSOLE_DYNAMIC is not set
735CONFIG_NETPOLL=y
736# CONFIG_NETPOLL_TRAP is not set
737CONFIG_NET_POLL_CONTROLLER=y
738# CONFIG_ISDN is not set
739# CONFIG_PHONE is not set
740
741#
742# Input device support
743#
744CONFIG_INPUT=y
745CONFIG_INPUT_FF_MEMLESS=y
746CONFIG_INPUT_POLLDEV=y
747
748#
749# Userland interfaces
750#
751CONFIG_INPUT_MOUSEDEV=y
752CONFIG_INPUT_MOUSEDEV_PSAUX=y
753CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
754CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
755CONFIG_INPUT_JOYDEV=y
756CONFIG_INPUT_EVDEV=y
757# CONFIG_INPUT_EVBUG is not set
758
759#
760# Input Device Drivers
761#
762CONFIG_INPUT_KEYBOARD=y
763CONFIG_KEYBOARD_ATKBD=y
764# CONFIG_KEYBOARD_SUNKBD is not set
765# CONFIG_KEYBOARD_LKKBD is not set
766# CONFIG_KEYBOARD_XTKBD is not set
767# CONFIG_KEYBOARD_NEWTON is not set
768CONFIG_KEYBOARD_STOWAWAY=y
769CONFIG_INPUT_MOUSE=y
770CONFIG_MOUSE_PS2=y
771CONFIG_MOUSE_PS2_ALPS=y
772CONFIG_MOUSE_PS2_LOGIPS2PP=y
773CONFIG_MOUSE_PS2_SYNAPTICS=y
774CONFIG_MOUSE_PS2_LIFEBOOK=y
775CONFIG_MOUSE_PS2_TRACKPOINT=y
776# CONFIG_MOUSE_PS2_TOUCHKIT is not set
777CONFIG_MOUSE_SERIAL=y
778# CONFIG_MOUSE_INPORT is not set
779# CONFIG_MOUSE_LOGIBM is not set
780# CONFIG_MOUSE_PC110PAD is not set
781# CONFIG_MOUSE_VSXXXAA is not set
782CONFIG_INPUT_JOYSTICK=y
783CONFIG_JOYSTICK_ANALOG=y
784CONFIG_JOYSTICK_A3D=y
785CONFIG_JOYSTICK_ADI=y
786CONFIG_JOYSTICK_COBRA=y
787CONFIG_JOYSTICK_GF2K=y
788CONFIG_JOYSTICK_GRIP=y
789CONFIG_JOYSTICK_GRIP_MP=y
790CONFIG_JOYSTICK_GUILLEMOT=y
791CONFIG_JOYSTICK_INTERACT=y
792CONFIG_JOYSTICK_SIDEWINDER=y
793CONFIG_JOYSTICK_TMDC=y
794CONFIG_JOYSTICK_IFORCE=y
795CONFIG_JOYSTICK_IFORCE_232=y
796CONFIG_JOYSTICK_WARRIOR=y
797CONFIG_JOYSTICK_MAGELLAN=y
798CONFIG_JOYSTICK_SPACEORB=y
799CONFIG_JOYSTICK_SPACEBALL=y
800CONFIG_JOYSTICK_STINGER=y
801CONFIG_JOYSTICK_TWIDJOY=y
802# CONFIG_JOYSTICK_JOYDUMP is not set
803# CONFIG_INPUT_TABLET is not set
804CONFIG_INPUT_TOUCHSCREEN=y
805# CONFIG_TOUCHSCREEN_ADS7846 is not set
806# CONFIG_TOUCHSCREEN_FUJITSU is not set
807CONFIG_TOUCHSCREEN_GUNZE=y
808CONFIG_TOUCHSCREEN_ELO=y
809CONFIG_TOUCHSCREEN_MTOUCH=y
810CONFIG_TOUCHSCREEN_MK712=y
811CONFIG_TOUCHSCREEN_PENMOUNT=y
812CONFIG_TOUCHSCREEN_TOUCHRIGHT=y
813CONFIG_TOUCHSCREEN_TOUCHWIN=y
814# CONFIG_TOUCHSCREEN_UCB1400 is not set
815CONFIG_INPUT_MISC=y
816CONFIG_INPUT_PCSPKR=y
817# CONFIG_INPUT_WISTRON_BTNS is not set
818CONFIG_INPUT_UINPUT=y
819
820#
821# Hardware I/O ports
822#
823CONFIG_SERIO=y
824CONFIG_SERIO_I8042=y
825CONFIG_SERIO_SERPORT=y
826CONFIG_SERIO_CT82C710=y
827CONFIG_SERIO_PCIPS2=y
828CONFIG_SERIO_LIBPS2=y
829CONFIG_SERIO_RAW=y
830CONFIG_GAMEPORT=y
831CONFIG_GAMEPORT_NS558=y
832CONFIG_GAMEPORT_L4=y
833CONFIG_GAMEPORT_EMU10K1=y
834CONFIG_GAMEPORT_FM801=y
835
836#
837# Character devices
838#
839CONFIG_VT=y
840CONFIG_VT_CONSOLE=y
841CONFIG_HW_CONSOLE=y
842CONFIG_VT_HW_CONSOLE_BINDING=y
843CONFIG_SERIAL_NONSTANDARD=y
844# CONFIG_COMPUTONE is not set
845CONFIG_ROCKETPORT=y
846CONFIG_CYCLADES=y
847# CONFIG_CYZ_INTR is not set
848# CONFIG_DIGIEPCA is not set
849# CONFIG_ESPSERIAL is not set
850# CONFIG_MOXA_INTELLIO is not set
851# CONFIG_MOXA_SMARTIO is not set
852# CONFIG_MOXA_SMARTIO_NEW is not set
853# CONFIG_ISI is not set
854CONFIG_SYNCLINK=y
855CONFIG_SYNCLINKMP=y
856# CONFIG_SYNCLINK_GT is not set
857CONFIG_N_HDLC=y
858# CONFIG_SPECIALIX is not set
859# CONFIG_SX is not set
860# CONFIG_RIO is not set
861# CONFIG_STALDRV is not set
862
863#
864# Serial drivers
865#
866CONFIG_SERIAL_8250=y
867CONFIG_SERIAL_8250_CONSOLE=y
868CONFIG_FIX_EARLYCON_MEM=y
869CONFIG_SERIAL_8250_PCI=y
870CONFIG_SERIAL_8250_PNP=y
871CONFIG_SERIAL_8250_NR_UARTS=4
872CONFIG_SERIAL_8250_RUNTIME_UARTS=4
873# CONFIG_SERIAL_8250_EXTENDED is not set
874
875#
876# Non-8250 serial port support
877#
878CONFIG_SERIAL_CORE=y
879CONFIG_SERIAL_CORE_CONSOLE=y
880CONFIG_SERIAL_JSM=y
881CONFIG_UNIX98_PTYS=y
882# CONFIG_LEGACY_PTYS is not set
883CONFIG_IPMI_HANDLER=y
884# CONFIG_IPMI_PANIC_EVENT is not set
885CONFIG_IPMI_DEVICE_INTERFACE=y
886CONFIG_IPMI_SI=y
887CONFIG_IPMI_WATCHDOG=y
888CONFIG_IPMI_POWEROFF=y
889CONFIG_HW_RANDOM=y
890CONFIG_HW_RANDOM_INTEL=y
891CONFIG_HW_RANDOM_AMD=y
892CONFIG_HW_RANDOM_GEODE=y
893CONFIG_HW_RANDOM_VIA=y
894CONFIG_NVRAM=y
895CONFIG_RTC=y
896# CONFIG_DTLK is not set
897# CONFIG_R3964 is not set
898# CONFIG_APPLICOM is not set
899# CONFIG_SONYPI is not set
900# CONFIG_MWAVE is not set
901# CONFIG_PC8736x_GPIO is not set
902# CONFIG_NSC_GPIO is not set
903# CONFIG_CS5535_GPIO is not set
904# CONFIG_RAW_DRIVER is not set
905CONFIG_HANGCHECK_TIMER=y
906CONFIG_TCG_TPM=y
907CONFIG_TCG_ATMEL=y
908# CONFIG_TELCLOCK is not set
909CONFIG_DEVPORT=y
910# CONFIG_I2C is not set
911
912#
913# SPI support
914#
915CONFIG_SPI=y
916# CONFIG_SPI_DEBUG is not set
917CONFIG_SPI_MASTER=y
918
919#
920# SPI Master Controller Drivers
921#
922# CONFIG_SPI_BITBANG is not set
923
924#
925# SPI Protocol Masters
926#
927# CONFIG_SPI_AT25 is not set
928# CONFIG_SPI_SPIDEV is not set
929# CONFIG_SPI_TLE62X0 is not set
930# CONFIG_W1 is not set
931# CONFIG_POWER_SUPPLY is not set
932# CONFIG_HWMON is not set
933# CONFIG_WATCHDOG is not set
934
935#
936# Sonics Silicon Backplane
937#
938CONFIG_SSB_POSSIBLE=y
939CONFIG_SSB=y
940CONFIG_SSB_PCIHOST_POSSIBLE=y
941CONFIG_SSB_PCIHOST=y
942# CONFIG_SSB_DEBUG is not set
943CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
944CONFIG_SSB_DRIVER_PCICORE=y
945
946#
947# Multifunction device drivers
948#
949# CONFIG_MFD_SM501 is not set
950
951#
952# Multimedia devices
953#
954# CONFIG_VIDEO_DEV is not set
955# CONFIG_DVB_CORE is not set
956CONFIG_DAB=y
957
958#
959# Graphics support
960#
961CONFIG_AGP=y
962CONFIG_AGP_ALI=y
963CONFIG_AGP_ATI=y
964CONFIG_AGP_AMD=y
965CONFIG_AGP_AMD64=y
966CONFIG_AGP_INTEL=y
967CONFIG_AGP_NVIDIA=y
968CONFIG_AGP_SIS=y
969CONFIG_AGP_SWORKS=y
970CONFIG_AGP_VIA=y
971CONFIG_AGP_EFFICEON=y
972CONFIG_DRM=y
973# CONFIG_DRM_TDFX is not set
974CONFIG_DRM_R128=y
975CONFIG_DRM_RADEON=y
976# CONFIG_DRM_I810 is not set
977CONFIG_DRM_I830=y
978# CONFIG_DRM_I915 is not set
979CONFIG_DRM_MGA=y
980CONFIG_DRM_SIS=y
981CONFIG_DRM_VIA=y
982CONFIG_DRM_SAVAGE=y
983# CONFIG_VGASTATE is not set
984# CONFIG_VIDEO_OUTPUT_CONTROL is not set
985CONFIG_FB=y
986CONFIG_FIRMWARE_EDID=y
987# CONFIG_FB_DDC is not set
988CONFIG_FB_CFB_FILLRECT=y
989CONFIG_FB_CFB_COPYAREA=y
990CONFIG_FB_CFB_IMAGEBLIT=y
991# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
992# CONFIG_FB_SYS_FILLRECT is not set
993# CONFIG_FB_SYS_COPYAREA is not set
994# CONFIG_FB_SYS_IMAGEBLIT is not set
995# CONFIG_FB_SYS_FOPS is not set
996CONFIG_FB_DEFERRED_IO=y
997# CONFIG_FB_SVGALIB is not set
998# CONFIG_FB_MACMODES is not set
999# CONFIG_FB_BACKLIGHT is not set
1000CONFIG_FB_MODE_HELPERS=y
1001# CONFIG_FB_TILEBLITTING is not set
1002
1003#
1004# Frame buffer hardware drivers
1005#
1006# CONFIG_FB_CIRRUS is not set
1007# CONFIG_FB_PM2 is not set
1008# CONFIG_FB_CYBER2000 is not set
1009# CONFIG_FB_ARC is not set
1010# CONFIG_FB_ASILIANT is not set
1011# CONFIG_FB_IMSTT is not set
1012# CONFIG_FB_VGA16 is not set
1013# CONFIG_FB_UVESA is not set
1014CONFIG_FB_VESA=y
1015# CONFIG_FB_EFI is not set
1016# CONFIG_FB_HECUBA is not set
1017# CONFIG_FB_HGA is not set
1018# CONFIG_FB_S1D13XXX is not set
1019# CONFIG_FB_NVIDIA is not set
1020# CONFIG_FB_RIVA is not set
1021# CONFIG_FB_I810 is not set
1022# CONFIG_FB_LE80578 is not set
1023# CONFIG_FB_INTEL is not set
1024# CONFIG_FB_MATROX is not set
1025# CONFIG_FB_RADEON is not set
1026# CONFIG_FB_ATY128 is not set
1027# CONFIG_FB_ATY is not set
1028# CONFIG_FB_S3 is not set
1029# CONFIG_FB_SAVAGE is not set
1030# CONFIG_FB_SIS is not set
1031# CONFIG_FB_NEOMAGIC is not set
1032# CONFIG_FB_KYRO is not set
1033# CONFIG_FB_3DFX is not set
1034# CONFIG_FB_VOODOO1 is not set
1035# CONFIG_FB_VT8623 is not set
1036# CONFIG_FB_CYBLA is not set
1037# CONFIG_FB_TRIDENT is not set
1038# CONFIG_FB_ARK is not set
1039# CONFIG_FB_PM3 is not set
1040# CONFIG_FB_GEODE is not set
1041# CONFIG_FB_VIRTUAL is not set
1042CONFIG_BACKLIGHT_LCD_SUPPORT=y
1043CONFIG_LCD_CLASS_DEVICE=y
1044# CONFIG_LCD_LTV350QV is not set
1045CONFIG_BACKLIGHT_CLASS_DEVICE=y
1046# CONFIG_BACKLIGHT_CORGI is not set
1047# CONFIG_BACKLIGHT_PROGEAR is not set
1048
1049#
1050# Display device support
1051#
1052# CONFIG_DISPLAY_SUPPORT is not set
1053
1054#
1055# Console display driver support
1056#
1057CONFIG_VGA_CONSOLE=y
1058# CONFIG_VGACON_SOFT_SCROLLBACK is not set
1059CONFIG_VIDEO_SELECT=y
1060# CONFIG_MDA_CONSOLE is not set
1061CONFIG_DUMMY_CONSOLE=y
1062CONFIG_FRAMEBUFFER_CONSOLE=y
1063# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
1064# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
1065CONFIG_FONTS=y
1066# CONFIG_FONT_8x8 is not set
1067CONFIG_FONT_8x16=y
1068# CONFIG_FONT_6x11 is not set
1069# CONFIG_FONT_7x14 is not set
1070# CONFIG_FONT_PEARL_8x8 is not set
1071# CONFIG_FONT_ACORN_8x8 is not set
1072# CONFIG_FONT_MINI_4x6 is not set
1073# CONFIG_FONT_SUN8x16 is not set
1074# CONFIG_FONT_SUN12x22 is not set
1075# CONFIG_FONT_10x18 is not set
1076CONFIG_LOGO=y
1077CONFIG_LOGO_LINUX_MONO=y
1078CONFIG_LOGO_LINUX_VGA16=y
1079CONFIG_LOGO_LINUX_CLUT224=y
1080
1081#
1082# Sound
1083#
1084# CONFIG_SOUND is not set
1085CONFIG_HID_SUPPORT=y
1086CONFIG_HID=y
1087CONFIG_HID_DEBUG=y
1088# CONFIG_HIDRAW is not set
1089# CONFIG_USB_SUPPORT is not set
1090# CONFIG_MMC is not set
1091# CONFIG_NEW_LEDS is not set
1092# CONFIG_INFINIBAND is not set
1093# CONFIG_EDAC is not set
1094CONFIG_RTC_LIB=y
1095CONFIG_RTC_CLASS=y
1096CONFIG_RTC_HCTOSYS=y
1097CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
1098# CONFIG_RTC_DEBUG is not set
1099
1100#
1101# RTC interfaces
1102#
1103CONFIG_RTC_INTF_SYSFS=y
1104CONFIG_RTC_INTF_PROC=y
1105CONFIG_RTC_INTF_DEV=y
1106CONFIG_RTC_INTF_DEV_UIE_EMUL=y
1107CONFIG_RTC_DRV_TEST=y
1108
1109#
1110# SPI RTC drivers
1111#
1112CONFIG_RTC_DRV_RS5C348=y
1113CONFIG_RTC_DRV_MAX6902=y
1114
1115#
1116# Platform RTC drivers
1117#
1118# CONFIG_RTC_DRV_CMOS is not set
1119CONFIG_RTC_DRV_DS1553=y
1120# CONFIG_RTC_DRV_STK17TA8 is not set
1121CONFIG_RTC_DRV_DS1742=y
1122CONFIG_RTC_DRV_M48T86=y
1123# CONFIG_RTC_DRV_M48T59 is not set
1124CONFIG_RTC_DRV_V3020=y
1125
1126#
1127# on-CPU RTC drivers
1128#
1129# CONFIG_DMADEVICES is not set
1130# CONFIG_VIRTUALIZATION is not set
1131
1132#
1133# Userspace I/O
1134#
1135# CONFIG_UIO is not set
1136
1137#
1138# Firmware Drivers
1139#
1140CONFIG_EDD=y
1141CONFIG_DELL_RBU=y
1142CONFIG_DCDBAS=y
1143CONFIG_DMIID=y
1144
1145#
1146# File systems
1147#
1148CONFIG_EXT2_FS=y
1149CONFIG_EXT2_FS_XATTR=y
1150CONFIG_EXT2_FS_POSIX_ACL=y
1151CONFIG_EXT2_FS_SECURITY=y
1152# CONFIG_EXT2_FS_XIP is not set
1153CONFIG_EXT3_FS=y
1154CONFIG_EXT3_FS_XATTR=y
1155CONFIG_EXT3_FS_POSIX_ACL=y
1156CONFIG_EXT3_FS_SECURITY=y
1157# CONFIG_EXT4DEV_FS is not set
1158CONFIG_JBD=y
1159# CONFIG_JBD_DEBUG is not set
1160CONFIG_FS_MBCACHE=y
1161# CONFIG_REISERFS_FS is not set
1162# CONFIG_JFS_FS is not set
1163CONFIG_FS_POSIX_ACL=y
1164# CONFIG_XFS_FS is not set
1165# CONFIG_GFS2_FS is not set
1166# CONFIG_OCFS2_FS is not set
1167# CONFIG_MINIX_FS is not set
1168# CONFIG_ROMFS_FS is not set
1169CONFIG_INOTIFY=y
1170CONFIG_INOTIFY_USER=y
1171# CONFIG_QUOTA is not set
1172CONFIG_DNOTIFY=y
1173# CONFIG_AUTOFS_FS is not set
1174# CONFIG_AUTOFS4_FS is not set
1175CONFIG_FUSE_FS=y
1176CONFIG_GENERIC_ACL=y
1177
1178#
1179# CD-ROM/DVD Filesystems
1180#
1181CONFIG_ISO9660_FS=y
1182CONFIG_JOLIET=y
1183CONFIG_ZISOFS=y
1184CONFIG_UDF_FS=y
1185CONFIG_UDF_NLS=y
1186
1187#
1188# DOS/FAT/NT Filesystems
1189#
1190CONFIG_FAT_FS=y
1191# CONFIG_MSDOS_FS is not set
1192CONFIG_VFAT_FS=y
1193CONFIG_FAT_DEFAULT_CODEPAGE=437
1194CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
1195# CONFIG_NTFS_FS is not set
1196
1197#
1198# Pseudo filesystems
1199#
1200CONFIG_PROC_FS=y
1201CONFIG_PROC_KCORE=y
1202CONFIG_PROC_SYSCTL=y
1203CONFIG_SYSFS=y
1204CONFIG_TMPFS=y
1205CONFIG_TMPFS_POSIX_ACL=y
1206# CONFIG_HUGETLBFS is not set
1207# CONFIG_HUGETLB_PAGE is not set
1208CONFIG_CONFIGFS_FS=y
1209
1210#
1211# Miscellaneous filesystems
1212#
1213# CONFIG_ADFS_FS is not set
1214# CONFIG_AFFS_FS is not set
1215# CONFIG_HFS_FS is not set
1216# CONFIG_HFSPLUS_FS is not set
1217# CONFIG_BEFS_FS is not set
1218# CONFIG_BFS_FS is not set
1219# CONFIG_EFS_FS is not set
1220# CONFIG_CRAMFS is not set
1221# CONFIG_VXFS_FS is not set
1222# CONFIG_HPFS_FS is not set
1223# CONFIG_QNX4FS_FS is not set
1224# CONFIG_SYSV_FS is not set
1225# CONFIG_UFS_FS is not set
1226# CONFIG_NETWORK_FILESYSTEMS is not set
1227
1228#
1229# Partition Types
1230#
1231# CONFIG_PARTITION_ADVANCED is not set
1232CONFIG_MSDOS_PARTITION=y
1233CONFIG_NLS=y
1234CONFIG_NLS_DEFAULT="iso8859-1"
1235CONFIG_NLS_CODEPAGE_437=y
1236# CONFIG_NLS_CODEPAGE_737 is not set
1237# CONFIG_NLS_CODEPAGE_775 is not set
1238# CONFIG_NLS_CODEPAGE_850 is not set
1239# CONFIG_NLS_CODEPAGE_852 is not set
1240# CONFIG_NLS_CODEPAGE_855 is not set
1241# CONFIG_NLS_CODEPAGE_857 is not set
1242# CONFIG_NLS_CODEPAGE_860 is not set
1243# CONFIG_NLS_CODEPAGE_861 is not set
1244# CONFIG_NLS_CODEPAGE_862 is not set
1245# CONFIG_NLS_CODEPAGE_863 is not set
1246# CONFIG_NLS_CODEPAGE_864 is not set
1247# CONFIG_NLS_CODEPAGE_865 is not set
1248# CONFIG_NLS_CODEPAGE_866 is not set
1249# CONFIG_NLS_CODEPAGE_869 is not set
1250# CONFIG_NLS_CODEPAGE_936 is not set
1251# CONFIG_NLS_CODEPAGE_950 is not set
1252# CONFIG_NLS_CODEPAGE_932 is not set
1253# CONFIG_NLS_CODEPAGE_949 is not set
1254# CONFIG_NLS_CODEPAGE_874 is not set
1255# CONFIG_NLS_ISO8859_8 is not set
1256# CONFIG_NLS_CODEPAGE_1250 is not set
1257# CONFIG_NLS_CODEPAGE_1251 is not set
1258# CONFIG_NLS_ASCII is not set
1259# CONFIG_NLS_ISO8859_1 is not set
1260# CONFIG_NLS_ISO8859_2 is not set
1261# CONFIG_NLS_ISO8859_3 is not set
1262# CONFIG_NLS_ISO8859_4 is not set
1263# CONFIG_NLS_ISO8859_5 is not set
1264# CONFIG_NLS_ISO8859_6 is not set
1265# CONFIG_NLS_ISO8859_7 is not set
1266# CONFIG_NLS_ISO8859_9 is not set
1267# CONFIG_NLS_ISO8859_13 is not set
1268# CONFIG_NLS_ISO8859_14 is not set
1269# CONFIG_NLS_ISO8859_15 is not set
1270# CONFIG_NLS_KOI8_R is not set
1271# CONFIG_NLS_KOI8_U is not set
1272# CONFIG_NLS_UTF8 is not set
1273# CONFIG_DLM is not set
1274# CONFIG_INSTRUMENTATION is not set
1275
1276#
1277# Kernel hacking
1278#
1279CONFIG_TRACE_IRQFLAGS_SUPPORT=y
1280CONFIG_PRINTK_TIME=y
1281CONFIG_ENABLE_WARN_DEPRECATED=y
1282CONFIG_ENABLE_MUST_CHECK=y
1283CONFIG_MAGIC_SYSRQ=y
1284# CONFIG_UNUSED_SYMBOLS is not set
1285CONFIG_DEBUG_FS=y
1286# CONFIG_HEADERS_CHECK is not set
1287CONFIG_DEBUG_KERNEL=y
1288# CONFIG_DEBUG_SHIRQ is not set
1289# CONFIG_DETECT_SOFTLOCKUP is not set
1290# CONFIG_SCHED_DEBUG is not set
1291# CONFIG_SCHEDSTATS is not set
1292CONFIG_TIMER_STATS=y
1293CONFIG_DEBUG_SLAB=y
1294# CONFIG_DEBUG_SLAB_LEAK is not set
1295CONFIG_DEBUG_PREEMPT=y
1296# CONFIG_DEBUG_RT_MUTEXES is not set
1297# CONFIG_RT_MUTEX_TESTER is not set
1298CONFIG_DEBUG_SPINLOCK=y
1299CONFIG_DEBUG_MUTEXES=y
1300CONFIG_DEBUG_LOCK_ALLOC=y
1301CONFIG_PROVE_LOCKING=y
1302CONFIG_LOCKDEP=y
1303CONFIG_LOCK_STAT=y
1304# CONFIG_DEBUG_LOCKDEP is not set
1305CONFIG_TRACE_IRQFLAGS=y
1306CONFIG_DEBUG_SPINLOCK_SLEEP=y
1307CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
1308CONFIG_STACKTRACE=y
1309# CONFIG_DEBUG_KOBJECT is not set
1310# CONFIG_DEBUG_HIGHMEM is not set
1311CONFIG_DEBUG_BUGVERBOSE=y
1312CONFIG_DEBUG_INFO=y
1313CONFIG_DEBUG_VM=y
1314CONFIG_DEBUG_LIST=y
1315# CONFIG_DEBUG_SG is not set
1316CONFIG_FRAME_POINTER=y
1317CONFIG_FORCED_INLINING=y
1318# CONFIG_BOOT_PRINTK_DELAY is not set
1319# CONFIG_FAULT_INJECTION is not set
1320# CONFIG_SAMPLES is not set
1321CONFIG_EARLY_PRINTK=y
1322# CONFIG_DEBUG_STACKOVERFLOW is not set
1323# CONFIG_DEBUG_STACK_USAGE is not set
1324# CONFIG_DEBUG_PAGEALLOC is not set
1325# CONFIG_DEBUG_RODATA is not set
1326# CONFIG_4KSTACKS is not set
1327CONFIG_X86_FIND_SMP_CONFIG=y
1328CONFIG_X86_MPPARSE=y
1329CONFIG_DOUBLEFAULT=y
1330
1331#
1332# Security options
1333#
1334# CONFIG_KEYS is not set
1335# CONFIG_SECURITY is not set
1336# CONFIG_SECURITY_FILE_CAPABILITIES is not set
1337CONFIG_CRYPTO=y
1338CONFIG_CRYPTO_ALGAPI=y
1339CONFIG_CRYPTO_BLKCIPHER=y
1340CONFIG_CRYPTO_HASH=y
1341CONFIG_CRYPTO_MANAGER=y
1342CONFIG_CRYPTO_HMAC=y
1343# CONFIG_CRYPTO_XCBC is not set
1344CONFIG_CRYPTO_NULL=y
1345CONFIG_CRYPTO_MD4=y
1346CONFIG_CRYPTO_MD5=y
1347CONFIG_CRYPTO_SHA1=y
1348CONFIG_CRYPTO_SHA256=y
1349CONFIG_CRYPTO_SHA512=y
1350CONFIG_CRYPTO_WP512=y
1351CONFIG_CRYPTO_TGR192=y
1352# CONFIG_CRYPTO_GF128MUL is not set
1353CONFIG_CRYPTO_ECB=y
1354CONFIG_CRYPTO_CBC=y
1355# CONFIG_CRYPTO_PCBC is not set
1356# CONFIG_CRYPTO_LRW is not set
1357# CONFIG_CRYPTO_XTS is not set
1358# CONFIG_CRYPTO_CRYPTD is not set
1359CONFIG_CRYPTO_DES=y
1360# CONFIG_CRYPTO_FCRYPT is not set
1361CONFIG_CRYPTO_BLOWFISH=y
1362CONFIG_CRYPTO_TWOFISH=y
1363CONFIG_CRYPTO_TWOFISH_COMMON=y
1364CONFIG_CRYPTO_TWOFISH_586=y
1365CONFIG_CRYPTO_SERPENT=y
1366CONFIG_CRYPTO_AES=y
1367CONFIG_CRYPTO_AES_586=y
1368CONFIG_CRYPTO_CAST5=y
1369CONFIG_CRYPTO_CAST6=y
1370CONFIG_CRYPTO_TEA=y
1371CONFIG_CRYPTO_ARC4=y
1372CONFIG_CRYPTO_KHAZAD=y
1373CONFIG_CRYPTO_ANUBIS=y
1374# CONFIG_CRYPTO_SEED is not set
1375CONFIG_CRYPTO_DEFLATE=y
1376CONFIG_CRYPTO_MICHAEL_MIC=y
1377CONFIG_CRYPTO_CRC32C=y
1378# CONFIG_CRYPTO_CAMELLIA is not set
1379# CONFIG_CRYPTO_AUTHENC is not set
1380CONFIG_CRYPTO_HW=y
1381CONFIG_CRYPTO_DEV_PADLOCK=y
1382CONFIG_CRYPTO_DEV_PADLOCK_AES=y
1383CONFIG_CRYPTO_DEV_PADLOCK_SHA=y
1384CONFIG_CRYPTO_DEV_GEODE=y
1385
1386#
1387# Library routines
1388#
1389CONFIG_BITREVERSE=y
1390CONFIG_CRC_CCITT=y
1391CONFIG_CRC16=y
1392# CONFIG_CRC_ITU_T is not set
1393CONFIG_CRC32=y
1394# CONFIG_CRC7 is not set
1395CONFIG_LIBCRC32C=y
1396CONFIG_ZLIB_INFLATE=y
1397CONFIG_ZLIB_DEFLATE=y
1398CONFIG_PLIST=y
1399CONFIG_HAS_IOMEM=y
1400CONFIG_HAS_IOPORT=y
1401CONFIG_HAS_DMA=y
1402
1403#
1404# LITMUS^RT
1405#
1406
1407#
1408# Real-Time Synchronization
1409#
1410CONFIG_NP_SECTION=y
1411CONFIG_SRP=y
1412CONFIG_FMLP=y
1413
1414#
1415# Tracing
1416#
1417CONFIG_FEATHER_TRACE=y
1418CONFIG_SCHED_TASK_TRACE=y
1419CONFIG_SCHED_DEBUG_TRACE=y
1420CONFIG_SCHED_OVERHEAD_TRACE=y
diff --git a/index.html b/index.html
index 1603d07..62c0013 100644
--- a/index.html
+++ b/index.html
@@ -50,8 +50,8 @@
50 </p> 50 </p>
51 <h3>Current Version</h3> 51 <h3>Current Version</h3>
52 <p class="notopmargin"> 52 <p class="notopmargin">
53 The current version of LITMUS<sup>RT</sup> is <strong>2008.2</strong> and is based on Linux&nbsp;2.6.24. 53 The current version of LITMUS<sup>RT</sup> is <strong>2008.3</strong> and is based on Linux&nbsp;2.6.24.
54 It was released on 12/01/2008 and includes plugins for the following 54 It was released on 09/24/2009 and includes plugins for the following
55 scheduling policies: 55 scheduling policies:
56 </p> 56 </p>
57 <ul> 57 <ul>
@@ -257,7 +257,7 @@ Technology and Applications Symposium</cite>, pp. 342-353, April 2008.
257 General Public License (GPL)</a>. 257 General Public License (GPL)</a>.
258 </p> 258 </p>
259 <p> 259 <p>
260 The current release of LITMUS<sup>RT</sup> is 2008.2. 260 The current release of LITMUS<sup>RT</sup> is 2008.3.
261 It consists of our Linux kernel modifications in the form of 261 It consists of our Linux kernel modifications in the form of
262 a patch against Linux 2.6.24 and 262 a patch against Linux 2.6.24 and
263 263
@@ -266,6 +266,50 @@ Technology and Applications Symposium</cite>, pp. 342-353, April 2008.
266 used for tracing with <a href="http://www.cs.unc.edu/~bbb/feather-trace/">Feather-Trace</a> (which is part of the LITMUS<sup>RT</sup> patch). 266 used for tracing with <a href="http://www.cs.unc.edu/~bbb/feather-trace/">Feather-Trace</a> (which is part of the LITMUS<sup>RT</sup> patch).
267 </p> 267 </p>
268 268
269 <h3 class="relname">LITMUS<sup>RT</sup> 2008.3</h3>
270 <div class="release">
271 <p>
272 Based on Linux 2.6.24. Released in September 2009.
273
274 </p>
275 <h4>Files:</h4>
276 <ul>
277 <li>
278 <a href="download/2008.3/litmus-rt-2008.3.patch">litmus-rt-2008.3.patch</a>
279 </li>
280 <li>
281 <a href="download/2008.3/liblitmus-2008.3.tgz">liblitmus-2008.3.tgz</a>
282 </li>
283 <li>
284 <a href="download/2008.3/ft_tools-2008.3.tgz">ft_tools-2008.3.tgz</a>
285 </li>
286
287 <li><a href="download/2008.3/SHA256SUMS">SHA256 check sums</a>
288 </li>
289 </ul>
290 <h4>Major changes (since LITMUS<sup>RT</sup> 2008.2):</h4>
291 <ul>
292 <li>
293 <code>sys_null_call()</code>, a dummy system call that simplifies determining system call overheads.
294 </li>
295 <li>
296 Support for starting timers on remote CPUs via <code>hrtimer_start_on()</code>.
297 </li>
298 <li>
299 Support for dedicated release handling in GSN-EDF and a corresponding <code>/proc</code> interface.
300 </li>
301 <li>
302 Support for IPI latency tracing.
303 </li>
304 <li>Several bugfixes.</li>
305 <li>Switched to <a href="http://www.scons.org/">scons</a> as build system in libraries.</li>
306 <li>Support for cross compiling the libraries on x86-64 systems to i386 binaries (specify <code>ARCH=i386</code> in your environment).</li>
307 </ul>
308 <p>
309 Please consult the <a href="doc/changes.html">Change Log</a> for further details.
310 </p>
311 </div>
312
269 <h3 class="relname">LITMUS<sup>RT</sup> 2008.2</h3> 313 <h3 class="relname">LITMUS<sup>RT</sup> 2008.2</h3>
270 <div class="release"> 314 <div class="release">
271 <p> 315 <p>
@@ -386,11 +430,11 @@ cd $DIR
386# get Linux 2.6.24 430# get Linux 2.6.24
387wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.24.tar.bz2 431wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.24.tar.bz2
388tar xjf linux-2.6.24.tar.bz2 432tar xjf linux-2.6.24.tar.bz2
389wget http://www.cs.unc.edu/~anderson/litmus-rt/download/2008.2/litmus-rt-2008.2.patch 433wget http://www.cs.unc.edu/~anderson/litmus-rt/download/2008.3/litmus-rt-2008.3.patch
390mv linux-2.6.24 litmus2008 434mv linux-2.6.24 litmus2008
391# apply the LITMUS RT patch 435# apply the LITMUS RT patch
392cd litmus2008 436cd litmus2008
393patch -p1 &lt; ../litmus-rt-2008.2.patch 437patch -p1 &lt; ../litmus-rt-2008.3.patch
394# create a working kernel configuration 438# create a working kernel configuration
395# - select HZ=1000 439# - select HZ=1000
396# - enable in-kernel preemptions 440# - enable in-kernel preemptions
@@ -406,24 +450,24 @@ make modules
406</pre> 450</pre>
407 <p> 451 <p>
408 When configuring the kernel, note that there is a menu (at the very end of the list) 452 When configuring the kernel, note that there is a menu (at the very end of the list)
409 with LITMUS<sup>RT</sup>-specific configuration options. For reference, <a href="download/2008.2/qemu-config">we provide a configuration that is known to work under QEMU</a>. 453 with LITMUS<sup>RT</sup>-specific configuration options. For reference, <a href="download/2008.3/qemu-config">we provide a configuration that is known to work under QEMU</a>.
410 </p> 454 </p>
411 455
412 <h3>Libraries</h3> 456 <h3>Libraries</h3>
413 <p class="notopmargin"> 457 <p class="notopmargin">
414 The user-space library for real-time tasks, <span class="src">liblitmus</span>, 458 The user-space library for real-time tasks, <span class="src">liblitmus</span>,
415 depends on the LITMUS<sup>RT</sup> kernel kernel and provides its own makefile. 459 depends on the LITMUS<sup>RT</sup> kernel kernel and provides its own build system (based on <a href="http://www.scons.org/">scons</a>).
416 In order to compile <span class="src">liblitmus</span>, you need to adjust the 460 In order to compile <span class="src">liblitmus</span>, you need to adjust the
417 variable <span class="src">KERNEL_DIR</span> in the Makfile to point to your 461 variable <span class="src">LITMUS_KERNEL</span> in the <span class="src">SConstruct</span> file to point to your
418 copy of the kernel. 462 copy of the kernel.
419 </p> 463 </p>
420<pre class="shell"> 464<pre class="shell">
421cd $DIR 465cd $DIR
422wget http://www.cs.unc.edu/~anderson/litmus-rt/download/2008.2/liblitmus-2008.2.tgz 466wget http://www.cs.unc.edu/~anderson/litmus-rt/download/2008.3/liblitmus-2008.3.tgz
423tar xzf liblitmus-2008.2.tgz 467tar xzf liblitmus-2008.3.tgz
424cd liblitmus 468cd liblitmus
425# change KERNEL_DIR in Makefile to point to the kernel source 469# change LITMUS_KERNEL in SConstruct to point to the kernel source
426make 470scons
427</pre> 471</pre>
428 <p class="nobottommargin"> 472 <p class="nobottommargin">
429 Please refer to the <a href="#doc">documentation</a> on how to use the LITMUS<sup>RT</sup> 473 Please refer to the <a href="#doc">documentation</a> on how to use the LITMUS<sup>RT</sup>