diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-05-01 00:08:56 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-05-01 00:08:56 -0400 |
commit | 922eb113844e1837e401405a8558660fff72ebe1 (patch) | |
tree | c1a469b4a44dad60323b349001dd46e4c6950221 | |
parent | f31140bd20871265106d4854b9f6c81e58bd7c48 (diff) | |
parent | d5f64980b4e9970bf9bdcb0acf35cfc6e3dfa701 (diff) |
Merge branch 'synch_quanta' into merge
Conflicts:
litmus/edf_common.c
litmus/sched_gsn_edf.c
litmus/sched_psn_edf.c
Minor clashes between sched_clock() -> litmus_clock() and jobs.c refactoring
merged by hand. The result has been compile-tested.
-rw-r--r-- | include/litmus/edf_common.h | 3 | ||||
-rw-r--r-- | include/litmus/litmus.h | 12 | ||||
-rw-r--r-- | include/litmus/rt_domain.h | 7 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 4 | ||||
-rw-r--r-- | litmus/edf_common.c | 5 | ||||
-rw-r--r-- | litmus/rt_domain.c | 46 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 63 | ||||
-rw-r--r-- | litmus/sched_litmus.c | 6 | ||||
-rw-r--r-- | litmus/sched_psn_edf.c | 53 |
9 files changed, 147 insertions, 52 deletions
diff --git a/include/litmus/edf_common.h b/include/litmus/edf_common.h index dd40e1c882..f79bd76e17 100644 --- a/include/litmus/edf_common.h +++ b/include/litmus/edf_common.h | |||
@@ -12,7 +12,8 @@ | |||
12 | #include <litmus/rt_domain.h> | 12 | #include <litmus/rt_domain.h> |
13 | 13 | ||
14 | 14 | ||
15 | void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched); | 15 | void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched, |
16 | release_at_t release); | ||
16 | 17 | ||
17 | int edf_higher_prio(struct task_struct* first, | 18 | int edf_higher_prio(struct task_struct* first, |
18 | struct task_struct* second); | 19 | struct task_struct* second); |
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 6e99e651d7..7a27c987b6 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -163,6 +163,18 @@ inline static int budget_exhausted(struct task_struct* t) | |||
163 | 163 | ||
164 | #define get_release(t) ((t)->rt_param.job_params.release) | 164 | #define get_release(t) ((t)->rt_param.job_params.release) |
165 | 165 | ||
166 | /* Our notion of time within LITMUS: kernel monotonic time. */ | ||
167 | static inline lt_t litmus_clock(void) | ||
168 | { | ||
169 | return ktime_to_ns(ktime_get()); | ||
170 | } | ||
171 | |||
172 | /* A macro to convert from nanoseconds to ktime_t. */ | ||
173 | #define ns_to_ktime(t) ktime_add_ns(ktime_set(0, 0), t) | ||
174 | |||
175 | /* The high-resolution release timer for a task. */ | ||
176 | #define release_timer(t) ((t)->rt_param.job_params.release_timer) | ||
177 | |||
166 | /* Honor the flag in the preempt_count variable that is set | 178 | /* Honor the flag in the preempt_count variable that is set |
167 | * when scheduling is in progress. | 179 | * when scheduling is in progress. |
168 | */ | 180 | */ |
diff --git a/include/litmus/rt_domain.h b/include/litmus/rt_domain.h index 79b6034f22..fd3c205bcc 100644 --- a/include/litmus/rt_domain.h +++ b/include/litmus/rt_domain.h | |||
@@ -8,7 +8,7 @@ | |||
8 | struct _rt_domain; | 8 | struct _rt_domain; |
9 | 9 | ||
10 | typedef int (*check_resched_needed_t)(struct _rt_domain *rt); | 10 | typedef int (*check_resched_needed_t)(struct _rt_domain *rt); |
11 | typedef void (*release_at_t)(struct task_struct *t, lt_t start); | 11 | typedef void (*release_at_t)(struct task_struct *t); |
12 | 12 | ||
13 | typedef struct _rt_domain { | 13 | typedef struct _rt_domain { |
14 | /* runnable rt tasks are in here */ | 14 | /* runnable rt tasks are in here */ |
@@ -22,6 +22,9 @@ typedef struct _rt_domain { | |||
22 | /* how do we check if we need to kick another CPU? */ | 22 | /* how do we check if we need to kick another CPU? */ |
23 | check_resched_needed_t check_resched; | 23 | check_resched_needed_t check_resched; |
24 | 24 | ||
25 | /* how do we setup a job release? */ | ||
26 | release_at_t setup_release; | ||
27 | |||
25 | /* how are tasks ordered in the ready queue? */ | 28 | /* how are tasks ordered in the ready queue? */ |
26 | list_cmp_t order; | 29 | list_cmp_t order; |
27 | } rt_domain_t; | 30 | } rt_domain_t; |
@@ -33,7 +36,7 @@ typedef struct _rt_domain { | |||
33 | (!list_empty(&(rt)->ready_queue)) | 36 | (!list_empty(&(rt)->ready_queue)) |
34 | 37 | ||
35 | void rt_domain_init(rt_domain_t *rt, check_resched_needed_t f, | 38 | void rt_domain_init(rt_domain_t *rt, check_resched_needed_t f, |
36 | list_cmp_t order); | 39 | release_at_t g, list_cmp_t order); |
37 | 40 | ||
38 | void __add_ready(rt_domain_t* rt, struct task_struct *new); | 41 | void __add_ready(rt_domain_t* rt, struct task_struct *new); |
39 | void __add_release(rt_domain_t* rt, struct task_struct *task); | 42 | void __add_release(rt_domain_t* rt, struct task_struct *task); |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index 1f94e45578..8ffbf300b0 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -43,6 +43,10 @@ struct rt_job { | |||
43 | lt_t release; | 43 | lt_t release; |
44 | /* What is the current deadline? */ | 44 | /* What is the current deadline? */ |
45 | lt_t deadline; | 45 | lt_t deadline; |
46 | |||
47 | /* The high-resolution timer used to control its release. */ | ||
48 | struct hrtimer release_timer; | ||
49 | |||
46 | /* How much service has this job received so far? | 50 | /* How much service has this job received so far? |
47 | */ | 51 | */ |
48 | lt_t exec_time; | 52 | lt_t exec_time; |
diff --git a/litmus/edf_common.c b/litmus/edf_common.c index 2a52835a04..0b05194a04 100644 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c | |||
@@ -67,9 +67,10 @@ int edf_ready_order(struct list_head* a, struct list_head* b) | |||
67 | list_entry(b, struct task_struct, rt_list)); | 67 | list_entry(b, struct task_struct, rt_list)); |
68 | } | 68 | } |
69 | 69 | ||
70 | void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched) | 70 | void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched, |
71 | release_at_t release) | ||
71 | { | 72 | { |
72 | rt_domain_init(rt, resched, edf_ready_order); | 73 | rt_domain_init(rt, resched, release, edf_ready_order); |
73 | } | 74 | } |
74 | 75 | ||
75 | /* need_to_preempt - check whether the task t needs to be preempted | 76 | /* need_to_preempt - check whether the task t needs to be preempted |
diff --git a/litmus/rt_domain.c b/litmus/rt_domain.c index fe7bd29b19..d29325f232 100644 --- a/litmus/rt_domain.c +++ b/litmus/rt_domain.c | |||
@@ -22,26 +22,48 @@ static int dummy_resched(rt_domain_t *rt) | |||
22 | return 0; | 22 | return 0; |
23 | } | 23 | } |
24 | 24 | ||
25 | static void dummy_setup_release(struct task_struct *t) | ||
26 | { | ||
27 | } | ||
28 | |||
25 | static int dummy_order(struct list_head* a, struct list_head* b) | 29 | static int dummy_order(struct list_head* a, struct list_head* b) |
26 | { | 30 | { |
27 | return 0; | 31 | return 0; |
28 | } | 32 | } |
29 | 33 | ||
34 | /* We now set or clear a per_cpu flag indicating if a plugin-specific call | ||
35 | * to setup a timer (that handles a job release) needs to be made. There is | ||
36 | * no need to setup multiple timers for jobs that are released at the same | ||
37 | * time. The actual clearing of this flag is a side effect of the release_order | ||
38 | * comparison function that is used when inserting a task into the | ||
39 | * release queue. | ||
40 | */ | ||
41 | DEFINE_PER_CPU(int, call_setup_release) = 1; | ||
30 | int release_order(struct list_head* a, struct list_head* b) | 42 | int release_order(struct list_head* a, struct list_head* b) |
31 | { | 43 | { |
32 | return earlier_release( | 44 | struct task_struct *task_a = list_entry(a, struct task_struct, rt_list); |
33 | list_entry(a, struct task_struct, rt_list), | 45 | struct task_struct *task_b = list_entry(b, struct task_struct, rt_list); |
34 | list_entry(b, struct task_struct, rt_list)); | 46 | |
47 | /* If the release times are equal, clear the flag. */ | ||
48 | if (get_release(task_a) == get_release(task_b)) { | ||
49 | __get_cpu_var(call_setup_release) = 0; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | return earlier_release(task_a, task_b); | ||
35 | } | 54 | } |
36 | 55 | ||
37 | 56 | ||
38 | void rt_domain_init(rt_domain_t *rt, | 57 | void rt_domain_init(rt_domain_t *rt, |
39 | check_resched_needed_t f, | 58 | check_resched_needed_t f, |
59 | release_at_t g, | ||
40 | list_cmp_t order) | 60 | list_cmp_t order) |
41 | { | 61 | { |
42 | BUG_ON(!rt); | 62 | BUG_ON(!rt); |
43 | if (!f) | 63 | if (!f) |
44 | f = dummy_resched; | 64 | f = dummy_resched; |
65 | if (!g) | ||
66 | g = dummy_setup_release; | ||
45 | if (!order) | 67 | if (!order) |
46 | order = dummy_order; | 68 | order = dummy_order; |
47 | INIT_LIST_HEAD(&rt->ready_queue); | 69 | INIT_LIST_HEAD(&rt->ready_queue); |
@@ -49,6 +71,7 @@ void rt_domain_init(rt_domain_t *rt, | |||
49 | rt->ready_lock = RW_LOCK_UNLOCKED; | 71 | rt->ready_lock = RW_LOCK_UNLOCKED; |
50 | rt->release_lock = SPIN_LOCK_UNLOCKED; | 72 | rt->release_lock = SPIN_LOCK_UNLOCKED; |
51 | rt->check_resched = f; | 73 | rt->check_resched = f; |
74 | rt->setup_release = g; | ||
52 | rt->order = order; | 75 | rt->order = order; |
53 | } | 76 | } |
54 | 77 | ||
@@ -57,9 +80,9 @@ void rt_domain_init(rt_domain_t *rt, | |||
57 | */ | 80 | */ |
58 | void __add_ready(rt_domain_t* rt, struct task_struct *new) | 81 | void __add_ready(rt_domain_t* rt, struct task_struct *new) |
59 | { | 82 | { |
60 | TRACE("rt: adding %s/%d (%llu, %llu) to ready queue at %llu\n", | 83 | TRACE("rt: adding %s/%d (%llu, %llu) rel=%llu to ready queue at %llu\n", |
61 | new->comm, new->pid, get_exec_cost(new), get_rt_period(new), | 84 | new->comm, new->pid, get_exec_cost(new), get_rt_period(new), |
62 | sched_clock()); | 85 | get_release(new), litmus_clock()); |
63 | 86 | ||
64 | if (!list_insert(&new->rt_list, &rt->ready_queue, rt->order)) | 87 | if (!list_insert(&new->rt_list, &rt->ready_queue, rt->order)) |
65 | rt->check_resched(rt); | 88 | rt->check_resched(rt); |
@@ -92,14 +115,25 @@ void __add_release(rt_domain_t* rt, struct task_struct *task) | |||
92 | task->comm, task->pid, get_exec_cost(task), get_rt_period(task), | 115 | task->comm, task->pid, get_exec_cost(task), get_rt_period(task), |
93 | get_release(task)); | 116 | get_release(task)); |
94 | 117 | ||
118 | /* Set flag assuming that we will need to setup another timer for | ||
119 | * the release of this job. If it turns out that this is unnecessary | ||
120 | * (because another job is already being released at that time, | ||
121 | * and setting up two timers is redundant and inefficient), then | ||
122 | * we will clear that flag so another release timer isn't setup. | ||
123 | */ | ||
124 | __get_cpu_var(call_setup_release) = 1; | ||
95 | list_insert(&task->rt_list, &rt->release_queue, release_order); | 125 | list_insert(&task->rt_list, &rt->release_queue, release_order); |
126 | |||
127 | /* Setup a job release -- this typically involves a timer. */ | ||
128 | if (__get_cpu_var(call_setup_release)) | ||
129 | rt->setup_release(task); | ||
96 | } | 130 | } |
97 | 131 | ||
98 | void __release_pending(rt_domain_t* rt) | 132 | void __release_pending(rt_domain_t* rt) |
99 | { | 133 | { |
100 | struct list_head *pos, *save; | 134 | struct list_head *pos, *save; |
101 | struct task_struct *queued; | 135 | struct task_struct *queued; |
102 | lt_t now = sched_clock(); | 136 | lt_t now = litmus_clock(); |
103 | list_for_each_safe(pos, save, &rt->release_queue) { | 137 | list_for_each_safe(pos, save, &rt->release_queue) { |
104 | queued = list_entry(pos, struct task_struct, rt_list); | 138 | queued = list_entry(pos, struct task_struct, rt_list); |
105 | if (likely(is_released(queued, now))) { | 139 | if (likely(is_released(queued, now))) { |
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 7a7d9a2dfb..6d9539cc0b 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -265,7 +265,7 @@ static noinline void requeue(struct task_struct* task) | |||
265 | * the release and | 265 | * the release and |
266 | * deadline. We just must check if it has been released. | 266 | * deadline. We just must check if it has been released. |
267 | */ | 267 | */ |
268 | if (is_released(task, sched_clock())) | 268 | if (is_released(task, litmus_clock())) |
269 | __add_ready(&gsnedf, task); | 269 | __add_ready(&gsnedf, task); |
270 | else { | 270 | else { |
271 | /* it has got to wait */ | 271 | /* it has got to wait */ |
@@ -307,17 +307,16 @@ static noinline void gsnedf_job_arrival(struct task_struct* task) | |||
307 | } | 307 | } |
308 | 308 | ||
309 | /* check for current job releases */ | 309 | /* check for current job releases */ |
310 | static noinline void gsnedf_release_jobs(void) | 310 | static noinline void gsnedf_release_jobs(void) |
311 | { | 311 | { |
312 | struct list_head *pos, *save; | 312 | struct list_head *pos, *save; |
313 | struct task_struct *queued; | 313 | struct task_struct *queued; |
314 | lt_t now = sched_clock(); | 314 | lt_t now = litmus_clock(); |
315 | |||
316 | 315 | ||
317 | list_for_each_safe(pos, save, &gsnedf.release_queue) { | 316 | list_for_each_safe(pos, save, &gsnedf.release_queue) { |
318 | queued = list_entry(pos, struct task_struct, rt_list); | 317 | queued = list_entry(pos, struct task_struct, rt_list); |
319 | if (likely(is_released(queued, now))) { | 318 | if (likely(is_released(queued, now))) { |
320 | /* this one is ready to go*/ | 319 | /* this one is ready to go */ |
321 | list_del(pos); | 320 | list_del(pos); |
322 | set_rt_flags(queued, RT_F_RUNNING); | 321 | set_rt_flags(queued, RT_F_RUNNING); |
323 | 322 | ||
@@ -330,6 +329,37 @@ static noinline void gsnedf_release_jobs(void) | |||
330 | } | 329 | } |
331 | } | 330 | } |
332 | 331 | ||
332 | /* handles job releases when a timer expires */ | ||
333 | static enum hrtimer_restart gsnedf_release_job_timer(struct hrtimer *timer) | ||
334 | { | ||
335 | unsigned long flags; | ||
336 | |||
337 | spin_lock_irqsave(&gsnedf_lock, flags); | ||
338 | |||
339 | /* Release all pending ready jobs. */ | ||
340 | gsnedf_release_jobs(); | ||
341 | |||
342 | spin_unlock_irqrestore(&gsnedf_lock, flags); | ||
343 | |||
344 | return HRTIMER_NORESTART; | ||
345 | } | ||
346 | |||
347 | /* setup a new job release timer */ | ||
348 | static void gsnedf_setup_release_job_timer(struct task_struct *task) | ||
349 | { | ||
350 | hrtimer_init(&release_timer(task), CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
351 | release_timer(task).function = gsnedf_release_job_timer; | ||
352 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
353 | release_timer(task).cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART; | ||
354 | #endif | ||
355 | |||
356 | /* Expiration time of timer is release time of task. */ | ||
357 | release_timer(task).expires = ns_to_ktime(get_release(task)); | ||
358 | |||
359 | hrtimer_start(&release_timer(task), release_timer(task).expires, | ||
360 | HRTIMER_MODE_ABS); | ||
361 | } | ||
362 | |||
333 | /* gsnedf_tick - this function is called for every local timer | 363 | /* gsnedf_tick - this function is called for every local timer |
334 | * interrupt. | 364 | * interrupt. |
335 | * | 365 | * |
@@ -338,8 +368,6 @@ static noinline void gsnedf_release_jobs(void) | |||
338 | */ | 368 | */ |
339 | static void gsnedf_tick(struct task_struct* t) | 369 | static void gsnedf_tick(struct task_struct* t) |
340 | { | 370 | { |
341 | unsigned long flags; | ||
342 | |||
343 | if (is_realtime(t) && budget_exhausted(t)) { | 371 | if (is_realtime(t) && budget_exhausted(t)) { |
344 | if (!is_np(t)) { | 372 | if (!is_np(t)) { |
345 | /* np tasks will be preempted when they become | 373 | /* np tasks will be preempted when they become |
@@ -357,21 +385,6 @@ static void gsnedf_tick(struct task_struct* t) | |||
357 | request_exit_np(t); | 385 | request_exit_np(t); |
358 | } | 386 | } |
359 | } | 387 | } |
360 | |||
361 | /* only the first CPU needs to release jobs */ | ||
362 | /* FIXME: drive this from a hrtimer */ | ||
363 | if (smp_processor_id() == 0) { | ||
364 | spin_lock_irqsave(&gsnedf_lock, flags); | ||
365 | |||
366 | /* Try to release pending jobs */ | ||
367 | gsnedf_release_jobs(); | ||
368 | |||
369 | /* We don't need to check linked != scheduled since | ||
370 | * set_tsk_need_resched has been set by preempt() if necessary. | ||
371 | */ | ||
372 | |||
373 | spin_unlock_irqrestore(&gsnedf_lock, flags); | ||
374 | } | ||
375 | } | 388 | } |
376 | 389 | ||
377 | /* caller holds gsnedf_lock */ | 390 | /* caller holds gsnedf_lock */ |
@@ -525,7 +538,7 @@ static void gsnedf_task_new(struct task_struct * t, int on_rq, int running) | |||
525 | t->rt_param.linked_on = NO_CPU; | 538 | t->rt_param.linked_on = NO_CPU; |
526 | 539 | ||
527 | /* setup job params */ | 540 | /* setup job params */ |
528 | release_at(t, sched_clock()); | 541 | release_at(t, litmus_clock()); |
529 | 542 | ||
530 | gsnedf_job_arrival(t); | 543 | gsnedf_job_arrival(t); |
531 | spin_unlock_irqrestore(&gsnedf_lock, flags); | 544 | spin_unlock_irqrestore(&gsnedf_lock, flags); |
@@ -544,7 +557,7 @@ static void gsnedf_task_wake_up(struct task_struct *task) | |||
544 | if (get_rt_flags(task) == RT_F_EXIT_SEM) { | 557 | if (get_rt_flags(task) == RT_F_EXIT_SEM) { |
545 | set_rt_flags(task, RT_F_RUNNING); | 558 | set_rt_flags(task, RT_F_RUNNING); |
546 | } else { | 559 | } else { |
547 | now = sched_clock(); | 560 | now = litmus_clock(); |
548 | if (is_tardy(task, now)) { | 561 | if (is_tardy(task, now)) { |
549 | /* new sporadic release */ | 562 | /* new sporadic release */ |
550 | release_at(task, now); | 563 | release_at(task, now); |
@@ -712,7 +725,7 @@ static int __init init_gsn_edf(void) | |||
712 | INIT_LIST_HEAD(&entry->list); | 725 | INIT_LIST_HEAD(&entry->list); |
713 | } | 726 | } |
714 | 727 | ||
715 | edf_domain_init(&gsnedf, NULL); | 728 | edf_domain_init(&gsnedf, NULL, gsnedf_setup_release_job_timer); |
716 | return register_sched_plugin(&gsn_edf_plugin); | 729 | return register_sched_plugin(&gsn_edf_plugin); |
717 | } | 730 | } |
718 | 731 | ||
diff --git a/litmus/sched_litmus.c b/litmus/sched_litmus.c index 89ae3941db..16cdf2db59 100644 --- a/litmus/sched_litmus.c +++ b/litmus/sched_litmus.c | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | static void update_time_litmus(struct rq *rq, struct task_struct *p) | 6 | static void update_time_litmus(struct rq *rq, struct task_struct *p) |
7 | { | 7 | { |
8 | lt_t now = sched_clock(); | 8 | lt_t now = litmus_clock(); |
9 | p->rt_param.job_params.exec_time += | 9 | p->rt_param.job_params.exec_time += |
10 | now - p->rt_param.job_params.exec_start; | 10 | now - p->rt_param.job_params.exec_start; |
11 | p->rt_param.job_params.exec_start = now; | 11 | p->rt_param.job_params.exec_start = now; |
@@ -88,7 +88,7 @@ static struct task_struct *pick_next_task_litmus(struct rq *rq) | |||
88 | struct task_struct* picked = rq->litmus_next; | 88 | struct task_struct* picked = rq->litmus_next; |
89 | rq->litmus_next = NULL; | 89 | rq->litmus_next = NULL; |
90 | if (picked) | 90 | if (picked) |
91 | picked->rt_param.job_params.exec_start = sched_clock(); | 91 | picked->rt_param.job_params.exec_start = litmus_clock(); |
92 | return picked; | 92 | return picked; |
93 | } | 93 | } |
94 | 94 | ||
@@ -103,7 +103,7 @@ static void task_tick_litmus(struct rq *rq, struct task_struct *p) | |||
103 | */ | 103 | */ |
104 | static void set_curr_task_litmus(struct rq *rq) | 104 | static void set_curr_task_litmus(struct rq *rq) |
105 | { | 105 | { |
106 | rq->curr->rt_param.job_params.exec_start = sched_clock(); | 106 | rq->curr->rt_param.job_params.exec_start = litmus_clock(); |
107 | } | 107 | } |
108 | 108 | ||
109 | 109 | ||
diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c index 81c6f1d69a..7fb61ff75a 100644 --- a/litmus/sched_psn_edf.c +++ b/litmus/sched_psn_edf.c | |||
@@ -43,9 +43,10 @@ DEFINE_PER_CPU(psnedf_domain_t, psnedf_domains); | |||
43 | 43 | ||
44 | static void psnedf_domain_init(psnedf_domain_t* pedf, | 44 | static void psnedf_domain_init(psnedf_domain_t* pedf, |
45 | check_resched_needed_t check, | 45 | check_resched_needed_t check, |
46 | release_at_t release, | ||
46 | int cpu) | 47 | int cpu) |
47 | { | 48 | { |
48 | edf_domain_init(&pedf->domain, check); | 49 | edf_domain_init(&pedf->domain, check, release); |
49 | pedf->cpu = cpu; | 50 | pedf->cpu = cpu; |
50 | pedf->lock = SPIN_LOCK_UNLOCKED; | 51 | pedf->lock = SPIN_LOCK_UNLOCKED; |
51 | pedf->scheduled = NULL; | 52 | pedf->scheduled = NULL; |
@@ -60,7 +61,7 @@ static void requeue(struct task_struct* t, rt_domain_t *edf) | |||
60 | TRACE_TASK(t, "requeue: !TASK_RUNNING"); | 61 | TRACE_TASK(t, "requeue: !TASK_RUNNING"); |
61 | 62 | ||
62 | set_rt_flags(t, RT_F_RUNNING); | 63 | set_rt_flags(t, RT_F_RUNNING); |
63 | if (is_released(t, sched_clock())) | 64 | if (is_released(t, litmus_clock())) |
64 | __add_ready(edf, t); | 65 | __add_ready(edf, t); |
65 | else | 66 | else |
66 | __add_release(edf, t); /* it has got to wait */ | 67 | __add_release(edf, t); /* it has got to wait */ |
@@ -99,11 +100,41 @@ static int psnedf_check_resched(rt_domain_t *edf) | |||
99 | return ret; | 100 | return ret; |
100 | } | 101 | } |
101 | 102 | ||
103 | /* handles job releases when a timer expires */ | ||
104 | static enum hrtimer_restart psnedf_release_job_timer(struct hrtimer *timer) | ||
105 | { | ||
106 | unsigned long flags; | ||
107 | rt_domain_t *edf = local_edf; | ||
108 | psnedf_domain_t *pedf = local_pedf; | ||
109 | |||
110 | spin_lock_irqsave(&pedf->lock, flags); | ||
111 | |||
112 | /* Release all pending ready jobs. */ | ||
113 | __release_pending(edf); | ||
114 | |||
115 | spin_unlock_irqrestore(&pedf->lock, flags); | ||
116 | |||
117 | return HRTIMER_NORESTART; | ||
118 | } | ||
119 | |||
120 | /* setup a new job release timer */ | ||
121 | static void psnedf_setup_release_job_timer(struct task_struct *task) | ||
122 | { | ||
123 | hrtimer_init(&release_timer(task), CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
124 | release_timer(task).function = psnedf_release_job_timer; | ||
125 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
126 | release_timer(task).cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART; | ||
127 | #endif | ||
128 | |||
129 | /* Expiration time of timer is release time of task. */ | ||
130 | release_timer(task).expires = ns_to_ktime(get_release(task)); | ||
131 | |||
132 | hrtimer_start(&release_timer(task), release_timer(task).expires, | ||
133 | HRTIMER_MODE_ABS); | ||
134 | } | ||
102 | 135 | ||
103 | static void psnedf_tick(struct task_struct *t) | 136 | static void psnedf_tick(struct task_struct *t) |
104 | { | 137 | { |
105 | unsigned long flags; | ||
106 | rt_domain_t *edf = local_edf; | ||
107 | psnedf_domain_t *pedf = local_pedf; | 138 | psnedf_domain_t *pedf = local_pedf; |
108 | 139 | ||
109 | /* Check for inconsistency. We don't need the lock for this since | 140 | /* Check for inconsistency. We don't need the lock for this since |
@@ -122,11 +153,6 @@ static void psnedf_tick(struct task_struct *t) | |||
122 | request_exit_np(t); | 153 | request_exit_np(t); |
123 | } | 154 | } |
124 | } | 155 | } |
125 | |||
126 | spin_lock_irqsave(&pedf->lock, flags); | ||
127 | /* FIXME: release via hrtimer */ | ||
128 | __release_pending(edf); | ||
129 | spin_unlock_irqrestore(&pedf->lock, flags); | ||
130 | } | 156 | } |
131 | 157 | ||
132 | static void job_completion(struct task_struct* t) | 158 | static void job_completion(struct task_struct* t) |
@@ -226,7 +252,7 @@ static void psnedf_task_new(struct task_struct * t, int on_rq, int running) | |||
226 | smp_processor_id(), t->pid, get_partition(t)); | 252 | smp_processor_id(), t->pid, get_partition(t)); |
227 | 253 | ||
228 | /* setup job parameters */ | 254 | /* setup job parameters */ |
229 | release_at(t, sched_clock()); | 255 | release_at(t, litmus_clock()); |
230 | 256 | ||
231 | /* The task should be running in the queue, otherwise signal | 257 | /* The task should be running in the queue, otherwise signal |
232 | * code will try to wake it up with fatal consequences. | 258 | * code will try to wake it up with fatal consequences. |
@@ -259,7 +285,7 @@ static void psnedf_task_wake_up(struct task_struct *task) | |||
259 | * | 285 | * |
260 | * FIXME: This should be done in some more predictable and userspace-controlled way. | 286 | * FIXME: This should be done in some more predictable and userspace-controlled way. |
261 | */ | 287 | */ |
262 | now = sched_clock(); | 288 | now = litmus_clock(); |
263 | if (is_tardy(task, now) && | 289 | if (is_tardy(task, now) && |
264 | get_rt_flags(task) != RT_F_EXIT_SEM) { | 290 | get_rt_flags(task) != RT_F_EXIT_SEM) { |
265 | /* new sporadic release */ | 291 | /* new sporadic release */ |
@@ -320,7 +346,7 @@ static long psnedf_pi_block(struct pi_semaphore *sem, | |||
320 | /* queued in domain*/ | 346 | /* queued in domain*/ |
321 | list_del(&t->rt_list); | 347 | list_del(&t->rt_list); |
322 | /* readd to make priority change take place */ | 348 | /* readd to make priority change take place */ |
323 | if (is_released(t, sched_clock())) | 349 | if (is_released(t, litmus_clock())) |
324 | __add_ready(edf, t); | 350 | __add_ready(edf, t); |
325 | else | 351 | else |
326 | __add_release(edf, t); | 352 | __add_release(edf, t); |
@@ -431,7 +457,8 @@ static int __init init_psn_edf(void) | |||
431 | for (i = 0; i < NR_CPUS; i++) | 457 | for (i = 0; i < NR_CPUS; i++) |
432 | { | 458 | { |
433 | psnedf_domain_init(remote_pedf(i), | 459 | psnedf_domain_init(remote_pedf(i), |
434 | psnedf_check_resched, i); | 460 | psnedf_check_resched, |
461 | psnedf_setup_release_job_timer, i); | ||
435 | } | 462 | } |
436 | return register_sched_plugin(&psn_edf_plugin); | 463 | return register_sched_plugin(&psn_edf_plugin); |
437 | } | 464 | } |