aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/sched_plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/sched_plugin.c')
-rw-r--r--litmus/sched_plugin.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/litmus/sched_plugin.c b/litmus/sched_plugin.c
new file mode 100644
index 000000000000..c4747e0ef2ab
--- /dev/null
+++ b/litmus/sched_plugin.c
@@ -0,0 +1,224 @@
1/* sched_plugin.c -- core infrastructure for the scheduler plugin system
2 *
3 * This file includes the initialization of the plugin system, the no-op Linux
4 * scheduler plugin, some dummy functions, and some helper functions.
5 */
6
7#include <linux/list.h>
8#include <linux/spinlock.h>
9#include <linux/sched.h>
10#include <linux/seq_file.h>
11
12#include <litmus/litmus.h>
13#include <litmus/sched_plugin.h>
14#include <litmus/preempt.h>
15#include <litmus/jobs.h>
16
17/*
18 * Generic function to trigger preemption on either local or remote cpu
19 * from scheduler plugins. The key feature is that this function is
20 * non-preemptive section aware and does not invoke the scheduler / send
21 * IPIs if the to-be-preempted task is actually non-preemptive.
22 */
23void preempt_if_preemptable(struct task_struct* t, int cpu)
24{
25 /* t is the real-time task executing on CPU on_cpu If t is NULL, then
26 * on_cpu is currently scheduling background work.
27 */
28
29 int reschedule = 0;
30
31 if (!t)
32 /* move non-real-time task out of the way */
33 reschedule = 1;
34 else {
35 if (smp_processor_id() == cpu) {
36 /* local CPU case */
37 /* check if we need to poke userspace */
38 if (is_user_np(t))
39 /* Yes, poke it. This doesn't have to be atomic since
40 * the task is definitely not executing. */
41 request_exit_np(t);
42 else if (!is_kernel_np(t))
43 /* only if we are allowed to preempt the
44 * currently-executing task */
45 reschedule = 1;
46 } else {
47 /* Remote CPU case. Only notify if it's not a kernel
48 * NP section and if we didn't set the userspace
49 * flag. */
50 reschedule = !(is_kernel_np(t) || request_exit_np_atomic(t));
51 }
52 }
53 if (likely(reschedule))
54 litmus_reschedule(cpu);
55}
56
57
58/*************************************************************
59 * Dummy plugin functions *
60 *************************************************************/
61
62static void litmus_dummy_finish_switch(struct task_struct * prev)
63{
64}
65
66static struct task_struct* litmus_dummy_schedule(struct task_struct * prev)
67{
68 sched_state_task_picked();
69 return NULL;
70}
71
72static void litmus_dummy_tick(struct task_struct* tsk)
73{
74}
75
76static long litmus_dummy_admit_task(struct task_struct* tsk)
77{
78 printk(KERN_CRIT "LITMUS^RT: Linux plugin rejects %s/%d.\n",
79 tsk->comm, tsk->pid);
80 return -EINVAL;
81}
82
83static void litmus_dummy_task_new(struct task_struct *t, int on_rq, int running)
84{
85}
86
87static void litmus_dummy_task_wake_up(struct task_struct *task)
88{
89}
90
91static void litmus_dummy_task_block(struct task_struct *task)
92{
93}
94
95static void litmus_dummy_task_exit(struct task_struct *task)
96{
97}
98
99static long litmus_dummy_complete_job(void)
100{
101 return -ENOSYS;
102}
103
104static long litmus_dummy_activate_plugin(void)
105{
106 return 0;
107}
108
109static long litmus_dummy_deactivate_plugin(void)
110{
111 return 0;
112}
113
114#ifdef CONFIG_LITMUS_LOCKING
115
116static long litmus_dummy_allocate_lock(struct litmus_lock **lock, int type,
117 void* __user config)
118{
119 return -ENXIO;
120}
121
122#endif
123
124
125/* The default scheduler plugin. It doesn't do anything and lets Linux do its
126 * job.
127 */
128struct sched_plugin linux_sched_plugin = {
129 .plugin_name = "Linux",
130 .tick = litmus_dummy_tick,
131 .task_new = litmus_dummy_task_new,
132 .task_exit = litmus_dummy_task_exit,
133 .task_wake_up = litmus_dummy_task_wake_up,
134 .task_block = litmus_dummy_task_block,
135 .complete_job = litmus_dummy_complete_job,
136 .schedule = litmus_dummy_schedule,
137 .finish_switch = litmus_dummy_finish_switch,
138 .activate_plugin = litmus_dummy_activate_plugin,
139 .deactivate_plugin = litmus_dummy_deactivate_plugin,
140#ifdef CONFIG_LITMUS_LOCKING
141 .allocate_lock = litmus_dummy_allocate_lock,
142#endif
143 .admit_task = litmus_dummy_admit_task
144};
145
146/*
147 * The reference to current plugin that is used to schedule tasks within
148 * the system. It stores references to actual function implementations
149 * Should be initialized by calling "init_***_plugin()"
150 */
151struct sched_plugin *litmus = &linux_sched_plugin;
152
153/* the list of registered scheduling plugins */
154static LIST_HEAD(sched_plugins);
155static DEFINE_RAW_SPINLOCK(sched_plugins_lock);
156
157#define CHECK(func) {\
158 if (!plugin->func) \
159 plugin->func = litmus_dummy_ ## func;}
160
161/* FIXME: get reference to module */
162int register_sched_plugin(struct sched_plugin* plugin)
163{
164 printk(KERN_INFO "Registering LITMUS^RT plugin %s.\n",
165 plugin->plugin_name);
166
167 /* make sure we don't trip over null pointers later */
168 CHECK(finish_switch);
169 CHECK(schedule);
170 CHECK(tick);
171 CHECK(task_wake_up);
172 CHECK(task_exit);
173 CHECK(task_block);
174 CHECK(task_new);
175 CHECK(complete_job);
176 CHECK(activate_plugin);
177 CHECK(deactivate_plugin);
178#ifdef CONFIG_LITMUS_LOCKING
179 CHECK(allocate_lock);
180#endif
181 CHECK(admit_task);
182
183 if (!plugin->release_at)
184 plugin->release_at = release_at;
185
186 raw_spin_lock(&sched_plugins_lock);
187 list_add(&plugin->list, &sched_plugins);
188 raw_spin_unlock(&sched_plugins_lock);
189
190 return 0;
191}
192
193
194/* FIXME: reference counting, etc. */
195struct sched_plugin* find_sched_plugin(const char* name)
196{
197 struct list_head *pos;
198 struct sched_plugin *plugin;
199
200 raw_spin_lock(&sched_plugins_lock);
201 list_for_each(pos, &sched_plugins) {
202 plugin = list_entry(pos, struct sched_plugin, list);
203 if (!strcmp(plugin->plugin_name, name))
204 goto out_unlock;
205 }
206 plugin = NULL;
207
208out_unlock:
209 raw_spin_unlock(&sched_plugins_lock);
210 return plugin;
211}
212
213void print_sched_plugins(struct seq_file *m)
214{
215 struct list_head *pos;
216 struct sched_plugin *plugin;
217
218 raw_spin_lock(&sched_plugins_lock);
219 list_for_each(pos, &sched_plugins) {
220 plugin = list_entry(pos, struct sched_plugin, list);
221 seq_printf(m, "%s\n", plugin->plugin_name);
222 }
223 raw_spin_unlock(&sched_plugins_lock);
224}