From 0b28a3122d6917784701377e15a863489aee1c6c Mon Sep 17 00:00:00 2001 From: Andrea Bastoni Date: Thu, 17 Dec 2009 21:47:19 -0500 Subject: [ported from 2008.3] Add release-master support --- include/litmus/rt_domain.h | 3 +++ kernel/hrtimer.c | 2 ++ litmus/rt_domain.c | 21 ++++++++++++++------- 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 { /* real-time tasks waiting for release are in here */ spinlock_t release_lock; struct release_queue release_queue; + int release_master; /* for moving tasks to the release queue */ spinlock_t tobe_lock; @@ -51,6 +52,8 @@ struct release_heap { struct heap heap; /* used to trigger the release */ struct hrtimer timer; + /* used to delegate releases */ + struct hrtimer_start_on_info info; /* required for the timer callback */ rt_domain_t* dom; }; 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, /* start timer locally; we may get called * with rq->lock held, do not wake up anything */ + TRACE("hrtimer_start_on: starting on local CPU\n"); __hrtimer_start_range_ns(info->timer, info->time, 0, info->mode, 0); } else { + TRACE("hrtimer_start_on: pulling to remote CPU\n"); base = &per_cpu(hrtimer_bases, cpu); spin_lock_irqsave(&base->lock, flags); 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) /* initialize */ heap_init(&rh->heap); + atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE); } /* arm_release_timer() - start local release timer or trigger * remote timer (pull timer) @@ -217,14 +218,18 @@ static void arm_release_timer(rt_domain_t *_rt) TRACE_TASK(t, "arming timer 0x%p\n", &rh->timer); /* we cannot arm the timer using hrtimer_start() * as it may deadlock on rq->lock + * + * PINNED mode is ok on both local and remote CPU */ - /* FIXME now only one cpu without pulling - * later more cpus; hrtimer_pull should call - * __hrtimer_start... always with PINNED mode - */ - __hrtimer_start_range_ns(&rh->timer, - ns_to_ktime(rh->release_time), - 0, HRTIMER_MODE_ABS_PINNED, 0); + if (rt->release_master == NO_CPU) + __hrtimer_start_range_ns(&rh->timer, + ns_to_ktime(rh->release_time), + 0, HRTIMER_MODE_ABS_PINNED, 0); + else + hrtimer_start_on(rt->release_master, + &rh->info, &rh->timer, + ns_to_ktime(rh->release_time), + HRTIMER_MODE_ABS_PINNED); } else TRACE_TASK(t, "0x%p is not my timer\n", &rh->timer); } @@ -246,6 +251,8 @@ void rt_domain_init(rt_domain_t *rt, if (!order) order = dummy_order; + rt->release_master = NO_CPU; + heap_init(&rt->ready_queue); INIT_LIST_HEAD(&rt->tobe_released); 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) int out_of_time, sleep, preempt, np, exists, blocks; struct task_struct* next = NULL; + /* Bail out early if we are the release master. + * The release master never schedules any real-time tasks. + */ + if (gsnedf.release_master == entry->cpu) + return NULL; + spin_lock(&gsnedf_lock); clear_will_schedule(); @@ -515,8 +521,15 @@ static void gsnedf_task_new(struct task_struct * t, int on_rq, int running) if (running) { entry = &per_cpu(gsnedf_cpu_entries, task_cpu(t)); BUG_ON(entry->scheduled); - entry->scheduled = t; - tsk_rt(t)->scheduled_on = task_cpu(t); + + if (entry->cpu != gsnedf.release_master) { + entry->scheduled = t; + tsk_rt(t)->scheduled_on = task_cpu(t); + } else { + /* do not schedule on release master */ + preempt(entry); /* force resched */ + tsk_rt(t)->scheduled_on = NO_CPU; + } } else { t->rt_param.scheduled_on = NO_CPU; } @@ -758,6 +771,7 @@ static long gsnedf_activate_plugin(void) cpu_entry_t *entry; heap_init(&gsnedf_cpu_heap); + gsnedf.release_master = atomic_read(&release_master_cpu); for_each_online_cpu(cpu) { entry = &per_cpu(gsnedf_cpu_entries, cpu); @@ -765,8 +779,12 @@ static long gsnedf_activate_plugin(void) atomic_set(&entry->will_schedule, 0); entry->linked = NULL; entry->scheduled = NULL; - TRACE("GSN-EDF: Initializing CPU #%d.\n", cpu); - update_cpu_position(entry); + if (cpu != gsnedf.release_master) { + TRACE("GSN-EDF: Initializing CPU #%d.\n", cpu); + update_cpu_position(entry); + } else { + TRACE("GSN-EDF: CPU %d is release master.\n", cpu); + } } return 0; } -- cgit v1.2.2