aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2011-02-08 00:29:16 -0500
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2011-02-08 00:29:16 -0500
commitffe6756d28b517e56c3ee8496a92f4e58e2bcebe (patch)
tree03808b6ac5b70c2025b87cb11971bfd08fb49d81
parent9bdb1c134488b8bfa9dca6d50555ed9a9f86ffb7 (diff)
P-FP: add new partitioned fixed-priority plugin
Currently, this is basically the PSN-EDF plugin with a bit of renaming going on. The priority queue implementation and priority boosting implementation should change next.
-rw-r--r--include/litmus/fp_common.h19
-rw-r--r--include/litmus/litmus.h1
-rw-r--r--litmus/Makefile4
-rw-r--r--litmus/fp_common.c112
-rw-r--r--litmus/sched_pfp.c620
5 files changed, 755 insertions, 1 deletions
diff --git a/include/litmus/fp_common.h b/include/litmus/fp_common.h
new file mode 100644
index 000000000000..f23727ba913d
--- /dev/null
+++ b/include/litmus/fp_common.h
@@ -0,0 +1,19 @@
1/* Fixed-priority scheduler support.
2 */
3
4#ifndef __FP_COMMON_H__
5#define __FP_COMMON_H__
6
7#include <litmus/rt_domain.h>
8
9void fp_domain_init(rt_domain_t* rt, check_resched_needed_t resched,
10 release_jobs_t release);
11
12int fp_higher_prio(struct task_struct* first,
13 struct task_struct* second);
14
15int fp_ready_order(struct bheap_node* a, struct bheap_node* b);
16
17int fp_preemption_needed(rt_domain_t* rt, struct task_struct *t);
18
19#endif
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h
index 94086e2b38db..c5df5eeeea24 100644
--- a/include/litmus/litmus.h
+++ b/include/litmus/litmus.h
@@ -52,6 +52,7 @@ void litmus_exit_task(struct task_struct *tsk);
52#define get_rt_period(t) (tsk_rt(t)->task_params.period) 52#define get_rt_period(t) (tsk_rt(t)->task_params.period)
53#define get_rt_phase(t) (tsk_rt(t)->task_params.phase) 53#define get_rt_phase(t) (tsk_rt(t)->task_params.phase)
54#define get_partition(t) (tsk_rt(t)->task_params.cpu) 54#define get_partition(t) (tsk_rt(t)->task_params.cpu)
55#define get_priority(t) (tsk_rt(t)->task_params.priority)
55#define get_deadline(t) (tsk_rt(t)->job_params.deadline) 56#define get_deadline(t) (tsk_rt(t)->job_params.deadline)
56#define get_release(t) (tsk_rt(t)->job_params.release) 57#define get_release(t) (tsk_rt(t)->job_params.release)
57#define get_class(t) (tsk_rt(t)->task_params.cls) 58#define get_class(t) (tsk_rt(t)->task_params.cls)
diff --git a/litmus/Makefile b/litmus/Makefile
index ad9936e07b83..e86fad8c25ec 100644
--- a/litmus/Makefile
+++ b/litmus/Makefile
@@ -11,13 +11,15 @@ obj-y = sched_plugin.o litmus.o \
11 sync.o \ 11 sync.o \
12 rt_domain.o \ 12 rt_domain.o \
13 edf_common.o \ 13 edf_common.o \
14 fp_common.o \
14 fdso.o \ 15 fdso.o \
15 locking.o \ 16 locking.o \
16 srp.o \ 17 srp.o \
17 bheap.o \ 18 bheap.o \
18 ctrldev.o \ 19 ctrldev.o \
19 sched_gsn_edf.o \ 20 sched_gsn_edf.o \
20 sched_psn_edf.o 21 sched_psn_edf.o \
22 sched_pfp.o
21 23
22obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o 24obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o
23obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o 25obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o
diff --git a/litmus/fp_common.c b/litmus/fp_common.c
new file mode 100644
index 000000000000..fa36574d5992
--- /dev/null
+++ b/litmus/fp_common.c
@@ -0,0 +1,112 @@
1/*
2 * litmus/fp_common.c
3 *
4 * Common functions for fixed-priority scheduler.
5 */
6
7#include <linux/percpu.h>
8#include <linux/sched.h>
9#include <linux/list.h>
10
11#include <litmus/litmus.h>
12#include <litmus/sched_plugin.h>
13#include <litmus/sched_trace.h>
14
15#include <litmus/fp_common.h>
16
17/* fp_higher_prio - returns true if first has a higher static priority
18 * than second. Deadline ties are broken by PID.
19 *
20 * both first and second may be NULL
21 */
22int fp_higher_prio(struct task_struct* first,
23 struct task_struct* second)
24{
25 struct task_struct *first_task = first;
26 struct task_struct *second_task = second;
27
28 /* There is no point in comparing a task to itself. */
29 if (first && first == second) {
30 TRACE_TASK(first,
31 "WARNING: pointless FP priority comparison.\n");
32 return 0;
33 }
34
35
36 /* check for NULL tasks */
37 if (!first || !second)
38 return first && !second;
39
40#ifdef CONFIG_LITMUS_LOCKING
41
42 /* Check for inherited priorities. Change task
43 * used for comparison in such a case.
44 */
45 if (unlikely(first->rt_param.inh_task))
46 first_task = first->rt_param.inh_task;
47 if (unlikely(second->rt_param.inh_task))
48 second_task = second->rt_param.inh_task;
49
50 /* Check for priority boosting. Tie-break by start of boosting.
51 */
52 if (unlikely(is_priority_boosted(first_task))) {
53 /* first_task is boosted, how about second_task? */
54 if (!is_priority_boosted(second_task) ||
55 lt_before(get_boost_start(first_task),
56 get_boost_start(second_task)))
57 return 1;
58 else
59 return 0;
60 } else if (unlikely(is_priority_boosted(second_task)))
61 /* second_task is boosted, first is not*/
62 return 0;
63
64#endif
65
66
67 return !is_realtime(second_task) ||
68
69 /* is the deadline of the first task earlier?
70 * Then it has higher priority.
71 */
72 get_priority(first_task) < get_priority(second_task) ||
73
74 /* Do we have a deadline tie?
75 * Then break by PID.
76 */
77 (get_priority(first_task) == get_priority(second_task) &&
78 (first_task->pid < second_task->pid ||
79
80 /* If the PIDs are the same then the task with the inherited
81 * priority wins.
82 */
83 (first_task->pid == second_task->pid &&
84 !second->rt_param.inh_task)));
85}
86
87int fp_ready_order(struct bheap_node* a, struct bheap_node* b)
88{
89 return fp_higher_prio(bheap2task(a), bheap2task(b));
90}
91
92void fp_domain_init(rt_domain_t* rt, check_resched_needed_t resched,
93 release_jobs_t release)
94{
95 rt_domain_init(rt, fp_ready_order, resched, release);
96}
97
98/* need_to_preempt - check whether the task t needs to be preempted
99 */
100int fp_preemption_needed(rt_domain_t* rt, struct task_struct *t)
101{
102 /* we need the read lock for edf_ready_queue */
103 /* no need to preempt if there is nothing pending */
104 if (!__jobs_pending(rt))
105 return 0;
106 /* we need to reschedule if t doesn't exist */
107 if (!t)
108 return 1;
109
110 /* make sure to get non-rt stuff out of the way */
111 return !is_realtime(t) || fp_higher_prio(__next_ready(rt), t);
112}
diff --git a/litmus/sched_pfp.c b/litmus/sched_pfp.c
new file mode 100644
index 000000000000..183ceedf8308
--- /dev/null
+++ b/litmus/sched_pfp.c
@@ -0,0 +1,620 @@
1/*
2 * litmus/sched_pfp.c
3 *
4 * Implementation of partitioned fixed-priority scheduling.
5 * Based on PSN-EDF.
6 */
7
8#include <linux/percpu.h>
9#include <linux/sched.h>
10#include <linux/list.h>
11#include <linux/spinlock.h>
12#include <linux/module.h>
13
14#include <litmus/litmus.h>
15#include <litmus/jobs.h>
16#include <litmus/preempt.h>
17#include <litmus/fp_common.h>
18#include <litmus/sched_plugin.h>
19#include <litmus/sched_trace.h>
20#include <litmus/trace.h>
21
22typedef struct {
23 rt_domain_t domain;
24 int cpu;
25 struct task_struct* scheduled; /* only RT tasks */
26/*
27 * scheduling lock slock
28 * protects the domain and serializes scheduling decisions
29 */
30#define slock domain.ready_lock
31
32} pfp_domain_t;
33
34DEFINE_PER_CPU(pfp_domain_t, pfp_domains);
35
36#define local_pfp (&__get_cpu_var(pfp_domains))
37#define remote_dom(cpu) (&per_cpu(pfp_domains, cpu).domain)
38#define remote_pfp(cpu) (&per_cpu(pfp_domains, cpu))
39#define task_dom(task) remote_dom(get_partition(task))
40#define task_pfp(task) remote_pfp(get_partition(task))
41
42
43static void pfp_domain_init(pfp_domain_t* pfp,
44 check_resched_needed_t check,
45 release_jobs_t release,
46 int cpu)
47{
48 fp_domain_init(&pfp->domain, check, release);
49 pfp->cpu = cpu;
50 pfp->scheduled = NULL;
51}
52
53static void requeue(struct task_struct* t, rt_domain_t *dom)
54{
55 if (t->state != TASK_RUNNING)
56 TRACE_TASK(t, "requeue: !TASK_RUNNING\n");
57
58 set_rt_flags(t, RT_F_RUNNING);
59 if (is_released(t, litmus_clock()))
60 __add_ready(dom, t);
61 else
62 add_release(dom, t); /* it has got to wait */
63}
64
65/* we assume the lock is being held */
66static void preempt(pfp_domain_t *pfp)
67{
68 preempt_if_preemptable(pfp->scheduled, pfp->cpu);
69}
70
71/* This check is trivial in partioned systems as we only have to consider
72 * the CPU of the partition.
73 */
74static int pfp_check_resched(rt_domain_t *dom)
75{
76 pfp_domain_t *pfp = container_of(dom, pfp_domain_t, domain);
77
78 /* because this is a callback from rt_domain_t we already hold
79 * the necessary lock for the ready queue
80 */
81 if (fp_preemption_needed(dom, pfp->scheduled)) {
82 preempt(pfp);
83 return 1;
84 } else
85 return 0;
86}
87
88static void job_completion(struct task_struct* t, int forced)
89{
90 sched_trace_task_completion(t,forced);
91 TRACE_TASK(t, "job_completion().\n");
92
93 set_rt_flags(t, RT_F_SLEEP);
94 prepare_for_next_period(t);
95}
96
97static void pfp_tick(struct task_struct *t)
98{
99 pfp_domain_t *pfp = local_pfp;
100
101 /* Check for inconsistency. We don't need the lock for this since
102 * ->scheduled is only changed in schedule, which obviously is not
103 * executing in parallel on this CPU
104 */
105 BUG_ON(is_realtime(t) && t != pfp->scheduled);
106
107 if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) {
108 if (!is_np(t)) {
109 litmus_reschedule_local();
110 TRACE("pfp_scheduler_tick: "
111 "%d is preemptable "
112 " => FORCE_RESCHED\n", t->pid);
113 } else if (is_user_np(t)) {
114 TRACE("pfp_scheduler_tick: "
115 "%d is non-preemptable, "
116 "preemption delayed.\n", t->pid);
117 request_exit_np(t);
118 }
119 }
120}
121
122static struct task_struct* pfp_schedule(struct task_struct * prev)
123{
124 pfp_domain_t* pfp = local_pfp;
125 rt_domain_t* dom = &pfp->domain;
126 struct task_struct* next;
127
128 int out_of_time, sleep, preempt,
129 np, exists, blocks, resched;
130
131 raw_spin_lock(&pfp->slock);
132
133 /* sanity checking
134 * differently from gedf, when a task exits (dead)
135 * pfp->schedule may be null and prev _is_ realtime
136 */
137 BUG_ON(pfp->scheduled && pfp->scheduled != prev);
138 BUG_ON(pfp->scheduled && !is_realtime(prev));
139
140 /* (0) Determine state */
141 exists = pfp->scheduled != NULL;
142 blocks = exists && !is_running(pfp->scheduled);
143 out_of_time = exists &&
144 budget_enforced(pfp->scheduled) &&
145 budget_exhausted(pfp->scheduled);
146 np = exists && is_np(pfp->scheduled);
147 sleep = exists && get_rt_flags(pfp->scheduled) == RT_F_SLEEP;
148 preempt = fp_preemption_needed(dom, prev);
149
150 /* If we need to preempt do so.
151 * The following checks set resched to 1 in case of special
152 * circumstances.
153 */
154 resched = preempt;
155
156 /* If a task blocks we have no choice but to reschedule.
157 */
158 if (blocks)
159 resched = 1;
160
161 /* Request a sys_exit_np() call if we would like to preempt but cannot.
162 * Multiple calls to request_exit_np() don't hurt.
163 */
164 if (np && (out_of_time || preempt || sleep))
165 request_exit_np(pfp->scheduled);
166
167 /* Any task that is preemptable and either exhausts its execution
168 * budget or wants to sleep completes. We may have to reschedule after
169 * this.
170 */
171 if (!np && (out_of_time || sleep) && !blocks) {
172 job_completion(pfp->scheduled, !sleep);
173 resched = 1;
174 }
175
176 /* The final scheduling decision. Do we need to switch for some reason?
177 * Switch if we are in RT mode and have no task or if we need to
178 * resched.
179 */
180 next = NULL;
181 if ((!np || blocks) && (resched || !exists)) {
182 /* When preempting a task that does not block, then
183 * re-insert it into either the ready queue or the
184 * release queue (if it completed). requeue() picks
185 * the appropriate queue.
186 */
187 if (pfp->scheduled && !blocks)
188 requeue(pfp->scheduled, dom);
189 next = __take_ready(dom);
190 } else
191 /* Only override Linux scheduler if we have a real-time task
192 * scheduled that needs to continue.
193 */
194 if (exists)
195 next = prev;
196
197 if (next) {
198 TRACE_TASK(next, "scheduled at %llu\n", litmus_clock());
199 set_rt_flags(next, RT_F_RUNNING);
200 } else {
201 TRACE("becoming idle at %llu\n", litmus_clock());
202 }
203
204 pfp->scheduled = next;
205 sched_state_task_picked();
206 raw_spin_unlock(&pfp->slock);
207
208 return next;
209}
210
211
212/* Prepare a task for running in RT mode
213 */
214static void pfp_task_new(struct task_struct * t, int on_rq, int running)
215{
216 rt_domain_t* dom = task_dom(t);
217 pfp_domain_t* pfp = task_pfp(t);
218 unsigned long flags;
219
220 TRACE_TASK(t, "P-FP: task new, cpu = %d\n",
221 t->rt_param.task_params.cpu);
222
223 /* setup job parameters */
224 release_at(t, litmus_clock());
225
226 /* The task should be running in the queue, otherwise signal
227 * code will try to wake it up with fatal consequences.
228 */
229 raw_spin_lock_irqsave(&pfp->slock, flags);
230 if (running) {
231 /* there shouldn't be anything else running at the time */
232 BUG_ON(pfp->scheduled);
233 pfp->scheduled = t;
234 } else {
235 requeue(t, dom);
236 /* maybe we have to reschedule */
237 preempt(pfp);
238 }
239 raw_spin_unlock_irqrestore(&pfp->slock, flags);
240}
241
242static void pfp_task_wake_up(struct task_struct *task)
243{
244 unsigned long flags;
245 pfp_domain_t* pfp = task_pfp(task);
246 rt_domain_t* dom = task_dom(task);
247 lt_t now;
248
249 TRACE_TASK(task, "wake_up at %llu\n", litmus_clock());
250 raw_spin_lock_irqsave(&pfp->slock, flags);
251 BUG_ON(is_queued(task));
252 now = litmus_clock();
253 if (is_tardy(task, now)
254#ifdef CONFIG_LITMUS_LOCKING
255 /* We need to take suspensions because of semaphores into
256 * account! If a job resumes after being suspended due to acquiring
257 * a semaphore, it should never be treated as a new job release.
258 */
259 && !is_priority_boosted(task)
260#endif
261 ) {
262 /* new sporadic release */
263 release_at(task, now);
264 sched_trace_task_release(task);
265 }
266
267 /* Only add to ready queue if it is not the currently-scheduled
268 * task. This could be the case if a task was woken up concurrently
269 * on a remote CPU before the executing CPU got around to actually
270 * de-scheduling the task, i.e., wake_up() raced with schedule()
271 * and won.
272 */
273 if (pfp->scheduled != task)
274 requeue(task, dom);
275
276 raw_spin_unlock_irqrestore(&pfp->slock, flags);
277 TRACE_TASK(task, "wake up done\n");
278}
279
280static void pfp_task_block(struct task_struct *t)
281{
282 /* only running tasks can block, thus t is in no queue */
283 TRACE_TASK(t, "block at %llu, state=%d\n", litmus_clock(), t->state);
284
285 BUG_ON(!is_realtime(t));
286 BUG_ON(is_queued(t));
287}
288
289static void pfp_task_exit(struct task_struct * t)
290{
291 unsigned long flags;
292 pfp_domain_t* pfp = task_pfp(t);
293 rt_domain_t* dom;
294
295 raw_spin_lock_irqsave(&pfp->slock, flags);
296 if (is_queued(t)) {
297 /* dequeue */
298 dom = task_dom(t);
299 remove(dom, t);
300 }
301 if (pfp->scheduled == t)
302 pfp->scheduled = NULL;
303
304 TRACE_TASK(t, "RIP, now reschedule\n");
305
306 preempt(pfp);
307 raw_spin_unlock_irqrestore(&pfp->slock, flags);
308}
309
310#ifdef CONFIG_LITMUS_LOCKING
311
312#include <litmus/fdso.h>
313#include <litmus/srp.h>
314
315static void boost_priority(struct task_struct* t)
316{
317 unsigned long flags;
318 pfp_domain_t* pfp = task_pfp(t);
319 lt_t now;
320
321 raw_spin_lock_irqsave(&pfp->slock, flags);
322 now = litmus_clock();
323
324 TRACE_TASK(t, "priority boosted at %llu\n", now);
325
326 tsk_rt(t)->priority_boosted = 1;
327 tsk_rt(t)->boost_start_time = now;
328
329 if (pfp->scheduled != t) {
330 /* holder may be queued: first stop queue changes */
331 raw_spin_lock(&pfp->domain.release_lock);
332 if (is_queued(t) &&
333 /* If it is queued, then we need to re-order. */
334 bheap_decrease(fp_ready_order, tsk_rt(t)->heap_node) &&
335 /* If we bubbled to the top, then we need to check for preemptions. */
336 fp_preemption_needed(&pfp->domain, pfp->scheduled))
337 preempt(pfp);
338 raw_spin_unlock(&pfp->domain.release_lock);
339 } /* else: nothing to do since the job is not queued while scheduled */
340
341 raw_spin_unlock_irqrestore(&pfp->slock, flags);
342}
343
344static void unboost_priority(struct task_struct* t)
345{
346 unsigned long flags;
347 pfp_domain_t* pfp = task_pfp(t);
348 lt_t now;
349
350 raw_spin_lock_irqsave(&pfp->slock, flags);
351 now = litmus_clock();
352
353 /* assumption: this only happens when the job is scheduled */
354 BUG_ON(pfp->scheduled != t);
355
356 TRACE_TASK(t, "priority restored at %llu\n", now);
357
358 /* priority boosted jobs must be scheduled */
359 BUG_ON(pfp->scheduled != t);
360
361 tsk_rt(t)->priority_boosted = 0;
362 tsk_rt(t)->boost_start_time = 0;
363
364 /* check if this changes anything */
365 if (fp_preemption_needed(&pfp->domain, pfp->scheduled))
366 preempt(pfp);
367
368 raw_spin_unlock_irqrestore(&pfp->slock, flags);
369}
370
371/* ******************** SRP support ************************ */
372
373static unsigned int pfp_get_srp_prio(struct task_struct* t)
374{
375 return get_priority(t);
376}
377
378static long pfp_activate_plugin(void)
379{
380 get_srp_prio = pfp_get_srp_prio;
381 return 0;
382}
383
384/* ******************** FMLP support ********************** */
385
386/* struct for semaphore with priority inheritance */
387struct fmlp_semaphore {
388 struct litmus_lock litmus_lock;
389
390 /* current resource holder */
391 struct task_struct *owner;
392
393 /* FIFO queue of waiting tasks */
394 wait_queue_head_t wait;
395};
396
397static inline struct fmlp_semaphore* fmlp_from_lock(struct litmus_lock* lock)
398{
399 return container_of(lock, struct fmlp_semaphore, litmus_lock);
400}
401int pfp_fmlp_lock(struct litmus_lock* l)
402{
403 struct task_struct* t = current;
404 struct fmlp_semaphore *sem = fmlp_from_lock(l);
405 wait_queue_t wait;
406 unsigned long flags;
407
408 if (!is_realtime(t))
409 return -EPERM;
410
411 spin_lock_irqsave(&sem->wait.lock, flags);
412
413 if (sem->owner) {
414 /* resource is not free => must suspend and wait */
415
416 init_waitqueue_entry(&wait, t);
417
418 /* FIXME: interruptible would be nice some day */
419 set_task_state(t, TASK_UNINTERRUPTIBLE);
420
421 __add_wait_queue_tail_exclusive(&sem->wait, &wait);
422
423 TS_LOCK_SUSPEND;
424
425 /* release lock before sleeping */
426 spin_unlock_irqrestore(&sem->wait.lock, flags);
427
428 /* We depend on the FIFO order. Thus, we don't need to recheck
429 * when we wake up; we are guaranteed to have the lock since
430 * there is only one wake up per release.
431 */
432
433 schedule();
434
435 TS_LOCK_RESUME;
436
437 /* Since we hold the lock, no other task will change
438 * ->owner. We can thus check it without acquiring the spin
439 * lock. */
440 BUG_ON(sem->owner != t);
441
442 /* FIXME: could we punt the dequeuing to the previous job,
443 * which is holding the spinlock anyway? */
444 remove_wait_queue(&sem->wait, &wait);
445 } else {
446 /* it's ours now */
447 sem->owner = t;
448
449 /* mark the task as priority-boosted. */
450 boost_priority(t);
451
452 spin_unlock_irqrestore(&sem->wait.lock, flags);
453 }
454
455 return 0;
456}
457
458int pfp_fmlp_unlock(struct litmus_lock* l)
459{
460 struct task_struct *t = current, *next;
461 struct fmlp_semaphore *sem = fmlp_from_lock(l);
462 unsigned long flags;
463 int err = 0;
464
465 spin_lock_irqsave(&sem->wait.lock, flags);
466
467 if (sem->owner != t) {
468 err = -EINVAL;
469 goto out;
470 }
471
472 /* we lose the benefit of priority boosting */
473
474 unboost_priority(t);
475
476 /* check if there are jobs waiting for this resource */
477 next = waitqueue_first(&sem->wait);
478 if (next) {
479 /* boost next job */
480 boost_priority(next);
481
482 /* next becomes the resouce holder */
483 sem->owner = next;
484
485 /* wake up next */
486 wake_up_process(next);
487 } else
488 /* resource becomes available */
489 sem->owner = NULL;
490
491out:
492 spin_unlock_irqrestore(&sem->wait.lock, flags);
493 return err;
494}
495
496int pfp_fmlp_close(struct litmus_lock* l)
497{
498 struct task_struct *t = current;
499 struct fmlp_semaphore *sem = fmlp_from_lock(l);
500 unsigned long flags;
501
502 int owner;
503
504 spin_lock_irqsave(&sem->wait.lock, flags);
505
506 owner = sem->owner == t;
507
508 spin_unlock_irqrestore(&sem->wait.lock, flags);
509
510 if (owner)
511 pfp_fmlp_unlock(l);
512
513 return 0;
514}
515
516void pfp_fmlp_free(struct litmus_lock* lock)
517{
518 kfree(fmlp_from_lock(lock));
519}
520
521static struct litmus_lock_ops pfp_fmlp_lock_ops = {
522 .close = pfp_fmlp_close,
523 .lock = pfp_fmlp_lock,
524 .unlock = pfp_fmlp_unlock,
525 .deallocate = pfp_fmlp_free,
526};
527
528static struct litmus_lock* pfp_new_fmlp(void)
529{
530 struct fmlp_semaphore* sem;
531
532 sem = kmalloc(sizeof(*sem), GFP_KERNEL);
533 if (!sem)
534 return NULL;
535
536 sem->owner = NULL;
537 init_waitqueue_head(&sem->wait);
538 sem->litmus_lock.ops = &pfp_fmlp_lock_ops;
539
540 return &sem->litmus_lock;
541}
542
543/* **** lock constructor **** */
544
545
546static long pfp_allocate_lock(struct litmus_lock **lock, int type,
547 void* __user unused)
548{
549 int err = -ENXIO;
550 struct srp_semaphore* srp;
551
552 /* P-FP currently supports the SRP for local resources and the FMLP
553 * for global resources. */
554 switch (type) {
555 case FMLP_SEM:
556 /* Flexible Multiprocessor Locking Protocol */
557 *lock = pfp_new_fmlp();
558 if (*lock)
559 err = 0;
560 else
561 err = -ENOMEM;
562 break;
563
564 case SRP_SEM:
565 /* Baker's Stack Resource Policy */
566 srp = allocate_srp_semaphore();
567 if (srp) {
568 *lock = &srp->litmus_lock;
569 err = 0;
570 } else
571 err = -ENOMEM;
572 break;
573 };
574
575 return err;
576}
577
578#endif
579
580static long pfp_admit_task(struct task_struct* tsk)
581{
582 return task_cpu(tsk) == tsk->rt_param.task_params.cpu ? 0 : -EINVAL;
583}
584
585/* Plugin object */
586static struct sched_plugin pfp_plugin __cacheline_aligned_in_smp = {
587 .plugin_name = "P-FP",
588 .tick = pfp_tick,
589 .task_new = pfp_task_new,
590 .complete_job = complete_job,
591 .task_exit = pfp_task_exit,
592 .schedule = pfp_schedule,
593 .task_wake_up = pfp_task_wake_up,
594 .task_block = pfp_task_block,
595 .admit_task = pfp_admit_task,
596#ifdef CONFIG_LITMUS_LOCKING
597 .allocate_lock = pfp_allocate_lock,
598 .activate_plugin = pfp_activate_plugin,
599#endif
600};
601
602
603static int __init init_pfp(void)
604{
605 int i;
606
607 /* We do not really want to support cpu hotplug, do we? ;)
608 * However, if we are so crazy to do so,
609 * we cannot use num_online_cpu()
610 */
611 for (i = 0; i < num_online_cpus(); i++) {
612 pfp_domain_init(remote_pfp(i),
613 pfp_check_resched,
614 NULL, i);
615 }
616 return register_sched_plugin(&pfp_plugin);
617}
618
619module_init(init_pfp);
620