diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-29 23:35:01 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-29 23:35:01 -0400 |
commit | 6ffc1fee98c4b995eb3a0285f4f8fb467cb0306e (patch) | |
tree | 69a05892a41e7f7400fa598ee0bdf8027c8f0fd6 /litmus/sched_plugin.c | |
parent | e40152ee1e1c7a63f4777791863215e3faa37a86 (diff) | |
parent | 7c1ff4c544dd650cceff3cd69a04bcba60856678 (diff) |
Merge branch 'master' into wip-merge-2.6.34
Simple merge between master and 2.6.34 with conflicts resolved.
This commit does not compile, the following main problems are still
unresolved:
- spinlock -> raw_spinlock API changes
- kfifo API changes
- sched_class API changes
Conflicts:
Makefile
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/unistd_32.h
arch/x86/kernel/syscall_table_32.S
include/linux/hrtimer.h
kernel/sched.c
kernel/sched_fair.c
Diffstat (limited to 'litmus/sched_plugin.c')
-rw-r--r-- | litmus/sched_plugin.c | 265 |
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 | */ | ||
21 | void 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 | |||
77 | static void litmus_dummy_finish_switch(struct task_struct * prev) | ||
78 | { | ||
79 | } | ||
80 | |||
81 | static struct task_struct* litmus_dummy_schedule(struct task_struct * prev) | ||
82 | { | ||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | static void litmus_dummy_tick(struct task_struct* tsk) | ||
87 | { | ||
88 | } | ||
89 | |||
90 | static 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 | |||
97 | static void litmus_dummy_task_new(struct task_struct *t, int on_rq, int running) | ||
98 | { | ||
99 | } | ||
100 | |||
101 | static void litmus_dummy_task_wake_up(struct task_struct *task) | ||
102 | { | ||
103 | } | ||
104 | |||
105 | static void litmus_dummy_task_block(struct task_struct *task) | ||
106 | { | ||
107 | } | ||
108 | |||
109 | static void litmus_dummy_task_exit(struct task_struct *task) | ||
110 | { | ||
111 | } | ||
112 | |||
113 | static long litmus_dummy_complete_job(void) | ||
114 | { | ||
115 | return -ENOSYS; | ||
116 | } | ||
117 | |||
118 | static long litmus_dummy_activate_plugin(void) | ||
119 | { | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static long litmus_dummy_deactivate_plugin(void) | ||
124 | { | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | #ifdef CONFIG_FMLP | ||
129 | |||
130 | static long litmus_dummy_inherit_priority(struct pi_semaphore *sem, | ||
131 | struct task_struct *new_owner) | ||
132 | { | ||
133 | return -ENOSYS; | ||
134 | } | ||
135 | |||
136 | static long litmus_dummy_return_priority(struct pi_semaphore *sem) | ||
137 | { | ||
138 | return -ENOSYS; | ||
139 | } | ||
140 | |||
141 | static 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 | */ | ||
153 | struct 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 | */ | ||
179 | int 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 | */ | ||
186 | struct sched_plugin *litmus = &linux_sched_plugin; | ||
187 | |||
188 | /* the list of registered scheduling plugins */ | ||
189 | static LIST_HEAD(sched_plugins); | ||
190 | static 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 */ | ||
197 | int 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. */ | ||
232 | struct 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 | |||
245 | out_unlock: | ||
246 | spin_unlock(&sched_plugins_lock); | ||
247 | return plugin; | ||
248 | } | ||
249 | |||
250 | int 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 | } | ||