diff options
-rw-r--r-- | include/litmus/rt_domain.h | 3 | ||||
-rw-r--r-- | kernel/hrtimer.c | 2 | ||||
-rw-r--r-- | litmus/rt_domain.c | 21 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 26 |
4 files changed, 41 insertions, 11 deletions
diff --git a/include/litmus/rt_domain.h b/include/litmus/rt_domain.h index bde1e5a54812..c7c55bef3e42 100644 --- a/include/litmus/rt_domain.h +++ b/include/litmus/rt_domain.h | |||
@@ -28,6 +28,7 @@ typedef struct _rt_domain { | |||
28 | /* real-time tasks waiting for release are in here */ | 28 | /* real-time tasks waiting for release are in here */ |
29 | spinlock_t release_lock; | 29 | spinlock_t release_lock; |
30 | struct release_queue release_queue; | 30 | struct release_queue release_queue; |
31 | int release_master; | ||
31 | 32 | ||
32 | /* for moving tasks to the release queue */ | 33 | /* for moving tasks to the release queue */ |
33 | spinlock_t tobe_lock; | 34 | spinlock_t tobe_lock; |
@@ -51,6 +52,8 @@ struct release_heap { | |||
51 | struct heap heap; | 52 | struct heap heap; |
52 | /* used to trigger the release */ | 53 | /* used to trigger the release */ |
53 | struct hrtimer timer; | 54 | struct hrtimer timer; |
55 | /* used to delegate releases */ | ||
56 | struct hrtimer_start_on_info info; | ||
54 | /* required for the timer callback */ | 57 | /* required for the timer callback */ |
55 | rt_domain_t* dom; | 58 | rt_domain_t* dom; |
56 | }; | 59 | }; |
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 509ecaea3016..7b19403900ad 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -1077,9 +1077,11 @@ int hrtimer_start_on(int cpu, struct hrtimer_start_on_info* info, | |||
1077 | /* start timer locally; we may get called | 1077 | /* start timer locally; we may get called |
1078 | * with rq->lock held, do not wake up anything | 1078 | * with rq->lock held, do not wake up anything |
1079 | */ | 1079 | */ |
1080 | TRACE("hrtimer_start_on: starting on local CPU\n"); | ||
1080 | __hrtimer_start_range_ns(info->timer, info->time, | 1081 | __hrtimer_start_range_ns(info->timer, info->time, |
1081 | 0, info->mode, 0); | 1082 | 0, info->mode, 0); |
1082 | } else { | 1083 | } else { |
1084 | TRACE("hrtimer_start_on: pulling to remote CPU\n"); | ||
1083 | base = &per_cpu(hrtimer_bases, cpu); | 1085 | base = &per_cpu(hrtimer_bases, cpu); |
1084 | spin_lock_irqsave(&base->lock, flags); | 1086 | spin_lock_irqsave(&base->lock, flags); |
1085 | was_empty = list_empty(&base->to_pull); | 1087 | was_empty = list_empty(&base->to_pull); |
diff --git a/litmus/rt_domain.c b/litmus/rt_domain.c index 78e76421aeba..62c9fdcd22be 100644 --- a/litmus/rt_domain.c +++ b/litmus/rt_domain.c | |||
@@ -158,6 +158,7 @@ static void reinit_release_heap(struct task_struct* t) | |||
158 | 158 | ||
159 | /* initialize */ | 159 | /* initialize */ |
160 | heap_init(&rh->heap); | 160 | heap_init(&rh->heap); |
161 | atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE); | ||
161 | } | 162 | } |
162 | /* arm_release_timer() - start local release timer or trigger | 163 | /* arm_release_timer() - start local release timer or trigger |
163 | * remote timer (pull timer) | 164 | * remote timer (pull timer) |
@@ -217,14 +218,18 @@ static void arm_release_timer(rt_domain_t *_rt) | |||
217 | TRACE_TASK(t, "arming timer 0x%p\n", &rh->timer); | 218 | TRACE_TASK(t, "arming timer 0x%p\n", &rh->timer); |
218 | /* we cannot arm the timer using hrtimer_start() | 219 | /* we cannot arm the timer using hrtimer_start() |
219 | * as it may deadlock on rq->lock | 220 | * as it may deadlock on rq->lock |
221 | * | ||
222 | * PINNED mode is ok on both local and remote CPU | ||
220 | */ | 223 | */ |
221 | /* FIXME now only one cpu without pulling | 224 | if (rt->release_master == NO_CPU) |
222 | * later more cpus; hrtimer_pull should call | 225 | __hrtimer_start_range_ns(&rh->timer, |
223 | * __hrtimer_start... always with PINNED mode | 226 | ns_to_ktime(rh->release_time), |
224 | */ | 227 | 0, HRTIMER_MODE_ABS_PINNED, 0); |
225 | __hrtimer_start_range_ns(&rh->timer, | 228 | else |
226 | ns_to_ktime(rh->release_time), | 229 | hrtimer_start_on(rt->release_master, |
227 | 0, HRTIMER_MODE_ABS_PINNED, 0); | 230 | &rh->info, &rh->timer, |
231 | ns_to_ktime(rh->release_time), | ||
232 | HRTIMER_MODE_ABS_PINNED); | ||
228 | } else | 233 | } else |
229 | TRACE_TASK(t, "0x%p is not my timer\n", &rh->timer); | 234 | TRACE_TASK(t, "0x%p is not my timer\n", &rh->timer); |
230 | } | 235 | } |
@@ -246,6 +251,8 @@ void rt_domain_init(rt_domain_t *rt, | |||
246 | if (!order) | 251 | if (!order) |
247 | order = dummy_order; | 252 | order = dummy_order; |
248 | 253 | ||
254 | rt->release_master = NO_CPU; | ||
255 | |||
249 | heap_init(&rt->ready_queue); | 256 | heap_init(&rt->ready_queue); |
250 | INIT_LIST_HEAD(&rt->tobe_released); | 257 | INIT_LIST_HEAD(&rt->tobe_released); |
251 | for (i = 0; i < RELEASE_QUEUE_SLOTS; i++) | 258 | for (i = 0; i < RELEASE_QUEUE_SLOTS; i++) |
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 69990805e16a..a223e69f2efb 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -393,6 +393,12 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) | |||
393 | int out_of_time, sleep, preempt, np, exists, blocks; | 393 | int out_of_time, sleep, preempt, np, exists, blocks; |
394 | struct task_struct* next = NULL; | 394 | struct task_struct* next = NULL; |
395 | 395 | ||
396 | /* Bail out early if we are the release master. | ||
397 | * The release master never schedules any real-time tasks. | ||
398 | */ | ||
399 | if (gsnedf.release_master == entry->cpu) | ||
400 | return NULL; | ||
401 | |||
396 | spin_lock(&gsnedf_lock); | 402 | spin_lock(&gsnedf_lock); |
397 | clear_will_schedule(); | 403 | clear_will_schedule(); |
398 | 404 | ||
@@ -515,8 +521,15 @@ static void gsnedf_task_new(struct task_struct * t, int on_rq, int running) | |||
515 | if (running) { | 521 | if (running) { |
516 | entry = &per_cpu(gsnedf_cpu_entries, task_cpu(t)); | 522 | entry = &per_cpu(gsnedf_cpu_entries, task_cpu(t)); |
517 | BUG_ON(entry->scheduled); | 523 | BUG_ON(entry->scheduled); |
518 | entry->scheduled = t; | 524 | |
519 | tsk_rt(t)->scheduled_on = task_cpu(t); | 525 | if (entry->cpu != gsnedf.release_master) { |
526 | entry->scheduled = t; | ||
527 | tsk_rt(t)->scheduled_on = task_cpu(t); | ||
528 | } else { | ||
529 | /* do not schedule on release master */ | ||
530 | preempt(entry); /* force resched */ | ||
531 | tsk_rt(t)->scheduled_on = NO_CPU; | ||
532 | } | ||
520 | } else { | 533 | } else { |
521 | t->rt_param.scheduled_on = NO_CPU; | 534 | t->rt_param.scheduled_on = NO_CPU; |
522 | } | 535 | } |
@@ -758,6 +771,7 @@ static long gsnedf_activate_plugin(void) | |||
758 | cpu_entry_t *entry; | 771 | cpu_entry_t *entry; |
759 | 772 | ||
760 | heap_init(&gsnedf_cpu_heap); | 773 | heap_init(&gsnedf_cpu_heap); |
774 | gsnedf.release_master = atomic_read(&release_master_cpu); | ||
761 | 775 | ||
762 | for_each_online_cpu(cpu) { | 776 | for_each_online_cpu(cpu) { |
763 | entry = &per_cpu(gsnedf_cpu_entries, cpu); | 777 | entry = &per_cpu(gsnedf_cpu_entries, cpu); |
@@ -765,8 +779,12 @@ static long gsnedf_activate_plugin(void) | |||
765 | atomic_set(&entry->will_schedule, 0); | 779 | atomic_set(&entry->will_schedule, 0); |
766 | entry->linked = NULL; | 780 | entry->linked = NULL; |
767 | entry->scheduled = NULL; | 781 | entry->scheduled = NULL; |
768 | TRACE("GSN-EDF: Initializing CPU #%d.\n", cpu); | 782 | if (cpu != gsnedf.release_master) { |
769 | update_cpu_position(entry); | 783 | TRACE("GSN-EDF: Initializing CPU #%d.\n", cpu); |
784 | update_cpu_position(entry); | ||
785 | } else { | ||
786 | TRACE("GSN-EDF: CPU %d is release master.\n", cpu); | ||
787 | } | ||
770 | } | 788 | } |
771 | return 0; | 789 | return 0; |
772 | } | 790 | } |