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.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/litmus/sched_plugin.c b/litmus/sched_plugin.c
new file mode 100644
index 000000000000..3767b30e610a
--- /dev/null
+++ b/litmus/sched_plugin.c
@@ -0,0 +1,265 @@
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
10#include <litmus/litmus.h>
11#include <litmus/sched_plugin.h>
12
13#include <litmus/jobs.h>
14
15/*
16 * Generic function to trigger preemption on either local or remote cpu
17 * from scheduler plugins. The key feature is that this function is
18 * non-preemptive section aware and does not invoke the scheduler / send
19 * IPIs if the to-be-preempted task is actually non-preemptive.
20 */
21void preempt_if_preemptable(struct task_struct* t, int on_cpu)
22{
23 /* t is the real-time task executing on CPU on_cpu If t is NULL, then
24 * on_cpu is currently scheduling background work.
25 */
26
27 int send_ipi;
28
29 if (smp_processor_id() == on_cpu) {
30 /* local CPU case */
31 if (t) {
32 /* check if we need to poke userspace */
33 if (is_user_np(t))
34 /* yes, poke it */
35 request_exit_np(t);
36 else
37 /* no, see if we are allowed to preempt the
38 * currently-executing task */
39 if (!is_kernel_np(t))
40 set_tsk_need_resched(t);
41 } else
42 /* move non-real-time task out of the way */
43 set_tsk_need_resched(current);
44 } else {
45 /* remote CPU case */
46 if (!t)
47 /* currently schedules non-real-time work */
48 send_ipi = 1;
49 else {
50 /* currently schedules real-time work */
51 if (is_user_np(t)) {
52 /* need to notify user space of delayed
53 * preemption */
54
55 /* to avoid a race, set the flag, then test
56 * again */
57 request_exit_np(t);
58 /* make sure it got written */
59 mb();
60 }
61 /* Only send an ipi if remote task might have raced our
62 * request, i.e., send an IPI to make sure if it exited
63 * its critical section.
64 */
65 send_ipi = !is_np(t) && !is_kernel_np(t);
66 }
67 if (likely(send_ipi))
68 smp_send_reschedule(on_cpu);
69 }
70}
71
72
73/*************************************************************
74 * Dummy plugin functions *
75 *************************************************************/
76
77static void litmus_dummy_finish_switch(struct task_struct * prev)
78{
79}
80
81static struct task_struct* litmus_dummy_schedule(struct task_struct * prev)
82{
83 return NULL;
84}
85
86static void litmus_dummy_tick(struct task_struct* tsk)
87{
88}
89
90static long litmus_dummy_admit_task(struct task_struct* tsk)
91{
92 printk(KERN_CRIT "LITMUS^RT: Linux plugin rejects %s/%d.\n",
93 tsk->comm, tsk->pid);
94 return -EINVAL;
95}
96
97static void litmus_dummy_task_new(struct task_struct *t, int on_rq, int running)
98{
99}
100
101static void litmus_dummy_task_wake_up(struct task_struct *task)
102{
103}
104
105static void litmus_dummy_task_block(struct task_struct *task)
106{
107}
108
109static void litmus_dummy_task_exit(struct task_struct *task)
110{
111}
112
113static long litmus_dummy_complete_job(void)
114{
115 return -ENOSYS;
116}
117
118static long litmus_dummy_activate_plugin(void)
119{
120 return 0;
121}
122
123static long litmus_dummy_deactivate_plugin(void)
124{
125 return 0;
126}
127
128#ifdef CONFIG_FMLP
129
130static long litmus_dummy_inherit_priority(struct pi_semaphore *sem,
131 struct task_struct *new_owner)
132{
133 return -ENOSYS;
134}
135
136static long litmus_dummy_return_priority(struct pi_semaphore *sem)
137{
138 return -ENOSYS;
139}
140
141static long litmus_dummy_pi_block(struct pi_semaphore *sem,
142 struct task_struct *new_waiter)
143{
144 return -ENOSYS;
145}
146
147#endif
148
149
150/* The default scheduler plugin. It doesn't do anything and lets Linux do its
151 * job.
152 */
153struct sched_plugin linux_sched_plugin = {
154 .plugin_name = "Linux",
155 .tick = litmus_dummy_tick,
156 .task_new = litmus_dummy_task_new,
157 .task_exit = litmus_dummy_task_exit,
158 .task_wake_up = litmus_dummy_task_wake_up,
159 .task_block = litmus_dummy_task_block,
160 .complete_job = litmus_dummy_complete_job,
161 .schedule = litmus_dummy_schedule,
162 .finish_switch = litmus_dummy_finish_switch,
163 .activate_plugin = litmus_dummy_activate_plugin,
164 .deactivate_plugin = litmus_dummy_deactivate_plugin,
165#ifdef CONFIG_FMLP
166 .inherit_priority = litmus_dummy_inherit_priority,
167 .return_priority = litmus_dummy_return_priority,
168 .pi_block = litmus_dummy_pi_block,
169#endif
170 .admit_task = litmus_dummy_admit_task
171};
172
173/*
174 * The cluster size is needed in C-EDF: it makes sense only to cluster
175 * around L2 or L3, so if cluster_cache_index = 2 (default) we cluster
176 * all the CPUs that shares a L2 cache, while cluster_cache_index = 3
177 * we cluster all CPs that shares a L3 cache
178 */
179int cluster_cache_index = 2;
180
181/*
182 * The reference to current plugin that is used to schedule tasks within
183 * the system. It stores references to actual function implementations
184 * Should be initialized by calling "init_***_plugin()"
185 */
186struct sched_plugin *litmus = &linux_sched_plugin;
187
188/* the list of registered scheduling plugins */
189static LIST_HEAD(sched_plugins);
190static DEFINE_SPINLOCK(sched_plugins_lock);
191
192#define CHECK(func) {\
193 if (!plugin->func) \
194 plugin->func = litmus_dummy_ ## func;}
195
196/* FIXME: get reference to module */
197int register_sched_plugin(struct sched_plugin* plugin)
198{
199 printk(KERN_INFO "Registering LITMUS^RT plugin %s.\n",
200 plugin->plugin_name);
201
202 /* make sure we don't trip over null pointers later */
203 CHECK(finish_switch);
204 CHECK(schedule);
205 CHECK(tick);
206 CHECK(task_wake_up);
207 CHECK(task_exit);
208 CHECK(task_block);
209 CHECK(task_new);
210 CHECK(complete_job);
211 CHECK(activate_plugin);
212 CHECK(deactivate_plugin);
213#ifdef CONFIG_FMLP
214 CHECK(inherit_priority);
215 CHECK(return_priority);
216 CHECK(pi_block);
217#endif
218 CHECK(admit_task);
219
220 if (!plugin->release_at)
221 plugin->release_at = release_at;
222
223 spin_lock(&sched_plugins_lock);
224 list_add(&plugin->list, &sched_plugins);
225 spin_unlock(&sched_plugins_lock);
226
227 return 0;
228}
229
230
231/* FIXME: reference counting, etc. */
232struct sched_plugin* find_sched_plugin(const char* name)
233{
234 struct list_head *pos;
235 struct sched_plugin *plugin;
236
237 spin_lock(&sched_plugins_lock);
238 list_for_each(pos, &sched_plugins) {
239 plugin = list_entry(pos, struct sched_plugin, list);
240 if (!strcmp(plugin->plugin_name, name))
241 goto out_unlock;
242 }
243 plugin = NULL;
244
245out_unlock:
246 spin_unlock(&sched_plugins_lock);
247 return plugin;
248}
249
250int print_sched_plugins(char* buf, int max)
251{
252 int count = 0;
253 struct list_head *pos;
254 struct sched_plugin *plugin;
255
256 spin_lock(&sched_plugins_lock);
257 list_for_each(pos, &sched_plugins) {
258 plugin = list_entry(pos, struct sched_plugin, list);
259 count += snprintf(buf + count, max - count, "%s\n", plugin->plugin_name);
260 if (max - count <= 0)
261 break;
262 }
263 spin_unlock(&sched_plugins_lock);
264 return count;
265}