diff options
author | John M. Calandrino <jmc@cs.unc.edu> | 2008-04-30 17:23:35 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-04-30 17:23:35 -0400 |
commit | d5f64980b4e9970bf9bdcb0acf35cfc6e3dfa701 (patch) | |
tree | b605f4e240c7bde76e60c7ea5e618d1469c82346 | |
parent | c7d1f86705369bed0c65be15b898a9251de21c76 (diff) |
LITMUS CORE: Release jobs with hrtimers
John's proposal for how to release jobs with hrtimers.
-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 f3c930b137..669900bc4c 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 9fb5b19b78..3704924729 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -42,6 +42,10 @@ struct rt_job { | |||
42 | lt_t release; | 42 | lt_t release; |
43 | /* What is the current deadline? */ | 43 | /* What is the current deadline? */ |
44 | lt_t deadline; | 44 | lt_t deadline; |
45 | |||
46 | /* The high-resolution timer used to control its release. */ | ||
47 | struct hrtimer release_timer; | ||
48 | |||
45 | /* How much service has this job received so far? | 49 | /* How much service has this job received so far? |
46 | */ | 50 | */ |
47 | lt_t exec_time; | 51 | lt_t exec_time; |
diff --git a/litmus/edf_common.c b/litmus/edf_common.c index 3d9dca852d..2e055222ea 100644 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c | |||
@@ -74,9 +74,10 @@ void edf_release_at(struct task_struct *t, lt_t start) | |||
74 | set_rt_flags(t, RT_F_RUNNING); | 74 | set_rt_flags(t, RT_F_RUNNING); |
75 | } | 75 | } |
76 | 76 | ||
77 | void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched) | 77 | void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched, |
78 | release_at_t release) | ||
78 | { | 79 | { |
79 | rt_domain_init(rt, resched, edf_ready_order); | 80 | rt_domain_init(rt, resched, release, edf_ready_order); |
80 | } | 81 | } |
81 | 82 | ||
82 | void edf_prepare_for_next_period(struct task_struct *t) | 83 | void edf_prepare_for_next_period(struct task_struct *t) |
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 e879b02888..0381ddf98b 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -264,7 +264,7 @@ static noinline void requeue(struct task_struct* task) | |||
264 | * the release and | 264 | * the release and |
265 | * deadline. We just must check if it has been released. | 265 | * deadline. We just must check if it has been released. |
266 | */ | 266 | */ |
267 | if (is_released(task, sched_clock())) | 267 | if (is_released(task, litmus_clock())) |
268 | __add_ready(&gsnedf, task); | 268 | __add_ready(&gsnedf, task); |
269 | else { | 269 | else { |
270 | /* it has got to wait */ | 270 | /* it has got to wait */ |
@@ -306,17 +306,16 @@ static noinline void gsnedf_job_arrival(struct task_struct* task) | |||
306 | } | 306 | } |
307 | 307 | ||
308 | /* check for current job releases */ | 308 | /* check for current job releases */ |
309 | static noinline void gsnedf_release_jobs(void) | 309 | static noinline void gsnedf_release_jobs(void) |
310 | { | 310 | { |
311 | struct list_head *pos, *save; | 311 | struct list_head *pos, *save; |
312 | struct task_struct *queued; | 312 | struct task_struct *queued; |
313 | lt_t now = sched_clock(); | 313 | lt_t now = litmus_clock(); |
314 | |||
315 | 314 | ||
316 | list_for_each_safe(pos, save, &gsnedf.release_queue) { | 315 | list_for_each_safe(pos, save, &gsnedf.release_queue) { |
317 | queued = list_entry(pos, struct task_struct, rt_list); | 316 | queued = list_entry(pos, struct task_struct, rt_list); |
318 | if (likely(is_released(queued, now))) { | 317 | if (likely(is_released(queued, now))) { |
319 | /* this one is ready to go*/ | 318 | /* this one is ready to go */ |
320 | list_del(pos); | 319 | list_del(pos); |
321 | set_rt_flags(queued, RT_F_RUNNING); | 320 | set_rt_flags(queued, RT_F_RUNNING); |
322 | 321 | ||
@@ -329,6 +328,37 @@ static noinline void gsnedf_release_jobs(void) | |||
329 | } | 328 | } |
330 | } | 329 | } |
331 | 330 | ||
331 | /* handles job releases when a timer expires */ | ||
332 | static enum hrtimer_restart gsnedf_release_job_timer(struct hrtimer *timer) | ||
333 | { | ||
334 | unsigned long flags; | ||
335 | |||
336 | spin_lock_irqsave(&gsnedf_lock, flags); | ||
337 | |||
338 | /* Release all pending ready jobs. */ | ||
339 | gsnedf_release_jobs(); | ||
340 | |||
341 | spin_unlock_irqrestore(&gsnedf_lock, flags); | ||
342 | |||
343 | return HRTIMER_NORESTART; | ||
344 | } | ||
345 | |||
346 | /* setup a new job release timer */ | ||
347 | static void gsnedf_setup_release_job_timer(struct task_struct *task) | ||
348 | { | ||
349 | hrtimer_init(&release_timer(task), CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
350 | release_timer(task).function = gsnedf_release_job_timer; | ||
351 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
352 | release_timer(task).cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART; | ||
353 | #endif | ||
354 | |||
355 | /* Expiration time of timer is release time of task. */ | ||
356 | release_timer(task).expires = ns_to_ktime(get_release(task)); | ||
357 | |||
358 | hrtimer_start(&release_timer(task), release_timer(task).expires, | ||
359 | HRTIMER_MODE_ABS); | ||
360 | } | ||
361 | |||
332 | /* gsnedf_tick - this function is called for every local timer | 362 | /* gsnedf_tick - this function is called for every local timer |
333 | * interrupt. | 363 | * interrupt. |
334 | * | 364 | * |
@@ -337,8 +367,6 @@ static noinline void gsnedf_release_jobs(void) | |||
337 | */ | 367 | */ |
338 | static void gsnedf_tick(struct task_struct* t) | 368 | static void gsnedf_tick(struct task_struct* t) |
339 | { | 369 | { |
340 | unsigned long flags; | ||
341 | |||
342 | if (is_realtime(t) && budget_exhausted(t)) { | 370 | if (is_realtime(t) && budget_exhausted(t)) { |
343 | if (!is_np(t)) { | 371 | if (!is_np(t)) { |
344 | /* np tasks will be preempted when they become | 372 | /* np tasks will be preempted when they become |
@@ -356,21 +384,6 @@ static void gsnedf_tick(struct task_struct* t) | |||
356 | request_exit_np(t); | 384 | request_exit_np(t); |
357 | } | 385 | } |
358 | } | 386 | } |
359 | |||
360 | /* only the first CPU needs to release jobs */ | ||
361 | /* FIXME: drive this from a hrtimer */ | ||
362 | if (smp_processor_id() == 0) { | ||
363 | spin_lock_irqsave(&gsnedf_lock, flags); | ||
364 | |||
365 | /* Try to release pending jobs */ | ||
366 | gsnedf_release_jobs(); | ||
367 | |||
368 | /* We don't need to check linked != scheduled since | ||
369 | * set_tsk_need_resched has been set by preempt() if necessary. | ||
370 | */ | ||
371 | |||
372 | spin_unlock_irqrestore(&gsnedf_lock, flags); | ||
373 | } | ||
374 | } | 387 | } |
375 | 388 | ||
376 | /* caller holds gsnedf_lock */ | 389 | /* caller holds gsnedf_lock */ |
@@ -524,7 +537,7 @@ static void gsnedf_task_new(struct task_struct * t, int on_rq, int running) | |||
524 | t->rt_param.linked_on = NO_CPU; | 537 | t->rt_param.linked_on = NO_CPU; |
525 | 538 | ||
526 | /* setup job params */ | 539 | /* setup job params */ |
527 | edf_release_at(t, sched_clock()); | 540 | edf_release_at(t, litmus_clock()); |
528 | 541 | ||
529 | gsnedf_job_arrival(t); | 542 | gsnedf_job_arrival(t); |
530 | spin_unlock_irqrestore(&gsnedf_lock, flags); | 543 | spin_unlock_irqrestore(&gsnedf_lock, flags); |
@@ -543,7 +556,7 @@ static void gsnedf_task_wake_up(struct task_struct *task) | |||
543 | if (get_rt_flags(task) == RT_F_EXIT_SEM) { | 556 | if (get_rt_flags(task) == RT_F_EXIT_SEM) { |
544 | set_rt_flags(task, RT_F_RUNNING); | 557 | set_rt_flags(task, RT_F_RUNNING); |
545 | } else { | 558 | } else { |
546 | now = sched_clock(); | 559 | now = litmus_clock(); |
547 | if (is_tardy(task, now)) { | 560 | if (is_tardy(task, now)) { |
548 | /* new sporadic release */ | 561 | /* new sporadic release */ |
549 | edf_release_at(task, now); | 562 | edf_release_at(task, now); |
@@ -711,7 +724,7 @@ static int __init init_gsn_edf(void) | |||
711 | INIT_LIST_HEAD(&entry->list); | 724 | INIT_LIST_HEAD(&entry->list); |
712 | } | 725 | } |
713 | 726 | ||
714 | edf_domain_init(&gsnedf, NULL); | 727 | edf_domain_init(&gsnedf, NULL, gsnedf_setup_release_job_timer); |
715 | return register_sched_plugin(&gsn_edf_plugin); | 728 | return register_sched_plugin(&gsn_edf_plugin); |
716 | } | 729 | } |
717 | 730 | ||
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 961680d0a6..b60c2ce0b7 100644 --- a/litmus/sched_psn_edf.c +++ b/litmus/sched_psn_edf.c | |||
@@ -42,9 +42,10 @@ DEFINE_PER_CPU(psnedf_domain_t, psnedf_domains); | |||
42 | 42 | ||
43 | static void psnedf_domain_init(psnedf_domain_t* pedf, | 43 | static void psnedf_domain_init(psnedf_domain_t* pedf, |
44 | check_resched_needed_t check, | 44 | check_resched_needed_t check, |
45 | release_at_t release, | ||
45 | int cpu) | 46 | int cpu) |
46 | { | 47 | { |
47 | edf_domain_init(&pedf->domain, check); | 48 | edf_domain_init(&pedf->domain, check, release); |
48 | pedf->cpu = cpu; | 49 | pedf->cpu = cpu; |
49 | pedf->lock = SPIN_LOCK_UNLOCKED; | 50 | pedf->lock = SPIN_LOCK_UNLOCKED; |
50 | pedf->scheduled = NULL; | 51 | pedf->scheduled = NULL; |
@@ -59,7 +60,7 @@ static void requeue(struct task_struct* t, rt_domain_t *edf) | |||
59 | TRACE_TASK(t, "requeue: !TASK_RUNNING"); | 60 | TRACE_TASK(t, "requeue: !TASK_RUNNING"); |
60 | 61 | ||
61 | set_rt_flags(t, RT_F_RUNNING); | 62 | set_rt_flags(t, RT_F_RUNNING); |
62 | if (is_released(t, sched_clock())) | 63 | if (is_released(t, litmus_clock())) |
63 | __add_ready(edf, t); | 64 | __add_ready(edf, t); |
64 | else | 65 | else |
65 | __add_release(edf, t); /* it has got to wait */ | 66 | __add_release(edf, t); /* it has got to wait */ |
@@ -98,11 +99,41 @@ static int psnedf_check_resched(rt_domain_t *edf) | |||
98 | return ret; | 99 | return ret; |
99 | } | 100 | } |
100 | 101 | ||
102 | /* handles job releases when a timer expires */ | ||
103 | static enum hrtimer_restart psnedf_release_job_timer(struct hrtimer *timer) | ||
104 | { | ||
105 | unsigned long flags; | ||
106 | rt_domain_t *edf = local_edf; | ||
107 | psnedf_domain_t *pedf = local_pedf; | ||
108 | |||
109 | spin_lock_irqsave(&pedf->lock, flags); | ||
110 | |||
111 | /* Release all pending ready jobs. */ | ||
112 | __release_pending(edf); | ||
113 | |||
114 | spin_unlock_irqrestore(&pedf->lock, flags); | ||
115 | |||
116 | return HRTIMER_NORESTART; | ||
117 | } | ||
118 | |||
119 | /* setup a new job release timer */ | ||
120 | static void psnedf_setup_release_job_timer(struct task_struct *task) | ||
121 | { | ||
122 | hrtimer_init(&release_timer(task), CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
123 | release_timer(task).function = psnedf_release_job_timer; | ||
124 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
125 | release_timer(task).cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART; | ||
126 | #endif | ||
127 | |||
128 | /* Expiration time of timer is release time of task. */ | ||
129 | release_timer(task).expires = ns_to_ktime(get_release(task)); | ||
130 | |||
131 | hrtimer_start(&release_timer(task), release_timer(task).expires, | ||
132 | HRTIMER_MODE_ABS); | ||
133 | } | ||
101 | 134 | ||
102 | static void psnedf_tick(struct task_struct *t) | 135 | static void psnedf_tick(struct task_struct *t) |
103 | { | 136 | { |
104 | unsigned long flags; | ||
105 | rt_domain_t *edf = local_edf; | ||
106 | psnedf_domain_t *pedf = local_pedf; | 137 | psnedf_domain_t *pedf = local_pedf; |
107 | 138 | ||
108 | /* Check for inconsistency. We don't need the lock for this since | 139 | /* Check for inconsistency. We don't need the lock for this since |
@@ -121,11 +152,6 @@ static void psnedf_tick(struct task_struct *t) | |||
121 | request_exit_np(t); | 152 | request_exit_np(t); |
122 | } | 153 | } |
123 | } | 154 | } |
124 | |||
125 | spin_lock_irqsave(&pedf->lock, flags); | ||
126 | /* FIXME: release via hrtimer */ | ||
127 | __release_pending(edf); | ||
128 | spin_unlock_irqrestore(&pedf->lock, flags); | ||
129 | } | 155 | } |
130 | 156 | ||
131 | static void job_completion(struct task_struct* t) | 157 | static void job_completion(struct task_struct* t) |
@@ -225,7 +251,7 @@ static void psnedf_task_new(struct task_struct * t, int on_rq, int running) | |||
225 | smp_processor_id(), t->pid, get_partition(t)); | 251 | smp_processor_id(), t->pid, get_partition(t)); |
226 | 252 | ||
227 | /* setup job parameters */ | 253 | /* setup job parameters */ |
228 | edf_release_at(t, sched_clock()); | 254 | edf_release_at(t, litmus_clock()); |
229 | 255 | ||
230 | /* The task should be running in the queue, otherwise signal | 256 | /* The task should be running in the queue, otherwise signal |
231 | * code will try to wake it up with fatal consequences. | 257 | * code will try to wake it up with fatal consequences. |
@@ -258,7 +284,7 @@ static void psnedf_task_wake_up(struct task_struct *task) | |||
258 | * | 284 | * |
259 | * FIXME: This should be done in some more predictable and userspace-controlled way. | 285 | * FIXME: This should be done in some more predictable and userspace-controlled way. |
260 | */ | 286 | */ |
261 | now = sched_clock(); | 287 | now = litmus_clock(); |
262 | if (is_tardy(task, now) && | 288 | if (is_tardy(task, now) && |
263 | get_rt_flags(task) != RT_F_EXIT_SEM) { | 289 | get_rt_flags(task) != RT_F_EXIT_SEM) { |
264 | /* new sporadic release */ | 290 | /* new sporadic release */ |
@@ -319,7 +345,7 @@ static long psnedf_pi_block(struct pi_semaphore *sem, | |||
319 | /* queued in domain*/ | 345 | /* queued in domain*/ |
320 | list_del(&t->rt_list); | 346 | list_del(&t->rt_list); |
321 | /* readd to make priority change take place */ | 347 | /* readd to make priority change take place */ |
322 | if (is_released(t, sched_clock())) | 348 | if (is_released(t, litmus_clock())) |
323 | __add_ready(edf, t); | 349 | __add_ready(edf, t); |
324 | else | 350 | else |
325 | __add_release(edf, t); | 351 | __add_release(edf, t); |
@@ -430,7 +456,8 @@ static int __init init_psn_edf(void) | |||
430 | for (i = 0; i < NR_CPUS; i++) | 456 | for (i = 0; i < NR_CPUS; i++) |
431 | { | 457 | { |
432 | psnedf_domain_init(remote_pedf(i), | 458 | psnedf_domain_init(remote_pedf(i), |
433 | psnedf_check_resched, i); | 459 | psnedf_check_resched, |
460 | psnedf_setup_release_job_timer, i); | ||
434 | } | 461 | } |
435 | return register_sched_plugin(&psn_edf_plugin); | 462 | return register_sched_plugin(&psn_edf_plugin); |
436 | } | 463 | } |