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