diff options
-rw-r--r-- | include/litmus/litmus.h | 2 | ||||
-rw-r--r-- | include/litmus/rt_domain.h | 6 | ||||
-rw-r--r-- | litmus/Kconfig | 12 | ||||
-rw-r--r-- | litmus/litmus.c | 14 | ||||
-rw-r--r-- | litmus/rt_domain.c | 8 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 12 |
6 files changed, 51 insertions, 3 deletions
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index d515d1af1096..674528eece14 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -9,7 +9,9 @@ | |||
9 | #include <linux/jiffies.h> | 9 | #include <linux/jiffies.h> |
10 | #include <litmus/sched_trace.h> | 10 | #include <litmus/sched_trace.h> |
11 | 11 | ||
12 | #ifdef CONFIG_RELEASE_MASTER | ||
12 | extern atomic_t release_master_cpu; | 13 | extern atomic_t release_master_cpu; |
14 | #endif | ||
13 | 15 | ||
14 | extern atomic_t __log_seq_no; | 16 | extern atomic_t __log_seq_no; |
15 | 17 | ||
diff --git a/include/litmus/rt_domain.h b/include/litmus/rt_domain.h index 9bf980713474..59e6b54e9281 100644 --- a/include/litmus/rt_domain.h +++ b/include/litmus/rt_domain.h | |||
@@ -28,7 +28,10 @@ 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 | raw_spinlock_t release_lock; | 29 | raw_spinlock_t release_lock; |
30 | struct release_queue release_queue; | 30 | struct release_queue release_queue; |
31 | |||
32 | #ifdef CONFIG_RELEASE_MASTER | ||
31 | int release_master; | 33 | int release_master; |
34 | #endif | ||
32 | 35 | ||
33 | /* for moving tasks to the release queue */ | 36 | /* for moving tasks to the release queue */ |
34 | raw_spinlock_t tobe_lock; | 37 | raw_spinlock_t tobe_lock; |
@@ -52,8 +55,11 @@ struct release_heap { | |||
52 | struct bheap heap; | 55 | struct bheap heap; |
53 | /* used to trigger the release */ | 56 | /* used to trigger the release */ |
54 | struct hrtimer timer; | 57 | struct hrtimer timer; |
58 | |||
59 | #ifdef CONFIG_RELEASE_MASTER | ||
55 | /* used to delegate releases */ | 60 | /* used to delegate releases */ |
56 | struct hrtimer_start_on_info info; | 61 | struct hrtimer_start_on_info info; |
62 | #endif | ||
57 | /* required for the timer callback */ | 63 | /* required for the timer callback */ |
58 | rt_domain_t* dom; | 64 | rt_domain_t* dom; |
59 | }; | 65 | }; |
diff --git a/litmus/Kconfig b/litmus/Kconfig index cc49e1a7f9c7..614e1051fa49 100644 --- a/litmus/Kconfig +++ b/litmus/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | menu "LITMUS^RT" | 1 | menu "LITMUS^RT" |
2 | 2 | ||
3 | menu "Plugins" | 3 | menu "Scheduling" |
4 | 4 | ||
5 | config PLUGIN_CEDF | 5 | config PLUGIN_CEDF |
6 | bool "Clustered-EDF" | 6 | bool "Clustered-EDF" |
@@ -11,6 +11,16 @@ config PLUGIN_CEDF | |||
11 | On smaller platforms (e.g., ARM PB11MPCore), using C-EDF | 11 | On smaller platforms (e.g., ARM PB11MPCore), using C-EDF |
12 | makes little sense since there aren't any shared caches. | 12 | makes little sense since there aren't any shared caches. |
13 | 13 | ||
14 | config RELEASE_MASTER | ||
15 | bool "Release-master Support" | ||
16 | default n | ||
17 | help | ||
18 | Allow one processor to act as a dedicated interrupt processor | ||
19 | that services all timer interrupts, but that does not schedule | ||
20 | real-time tasks. See RTSS'09 paper for details | ||
21 | (http://www.cs.unc.edu/~anderson/papers.html). | ||
22 | Currently only supported by GSN-EDF. | ||
23 | |||
14 | endmenu | 24 | endmenu |
15 | 25 | ||
16 | menu "Real-Time Synchronization" | 26 | menu "Real-Time Synchronization" |
diff --git a/litmus/litmus.c b/litmus/litmus.c index b71fc819eb51..c60423228607 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -30,8 +30,10 @@ atomic_t cannot_use_plugin = ATOMIC_INIT(0); | |||
30 | /* Give log messages sequential IDs. */ | 30 | /* Give log messages sequential IDs. */ |
31 | atomic_t __log_seq_no = ATOMIC_INIT(0); | 31 | atomic_t __log_seq_no = ATOMIC_INIT(0); |
32 | 32 | ||
33 | #ifdef CONFIG_RELEASE_MASTER | ||
33 | /* current master CPU for handling timer IRQs */ | 34 | /* current master CPU for handling timer IRQs */ |
34 | atomic_t release_master_cpu = ATOMIC_INIT(NO_CPU); | 35 | atomic_t release_master_cpu = ATOMIC_INIT(NO_CPU); |
36 | #endif | ||
35 | 37 | ||
36 | static struct kmem_cache * bheap_node_cache; | 38 | static struct kmem_cache * bheap_node_cache; |
37 | extern struct kmem_cache * release_heap_cache; | 39 | extern struct kmem_cache * release_heap_cache; |
@@ -627,6 +629,7 @@ static int proc_write_cluster_size(struct file *file, | |||
627 | return len; | 629 | return len; |
628 | } | 630 | } |
629 | 631 | ||
632 | #ifdef CONFIG_RELEASE_MASTER | ||
630 | static int proc_read_release_master(char *page, char **start, | 633 | static int proc_read_release_master(char *page, char **start, |
631 | off_t off, int count, | 634 | off_t off, int count, |
632 | int *eof, void *data) | 635 | int *eof, void *data) |
@@ -676,13 +679,16 @@ static int proc_write_release_master(struct file *file, | |||
676 | } | 679 | } |
677 | } | 680 | } |
678 | } | 681 | } |
682 | #endif | ||
679 | 683 | ||
680 | static struct proc_dir_entry *litmus_dir = NULL, | 684 | static struct proc_dir_entry *litmus_dir = NULL, |
681 | *curr_file = NULL, | 685 | *curr_file = NULL, |
682 | *stat_file = NULL, | 686 | *stat_file = NULL, |
683 | *plugs_file = NULL, | 687 | *plugs_file = NULL, |
684 | *clus_cache_idx_file = NULL, | 688 | #ifdef CONFIG_RELEASE_MASTER |
685 | *release_master_file = NULL; | 689 | *release_master_file = NULL, |
690 | #endif | ||
691 | *clus_cache_idx_file = NULL; | ||
686 | 692 | ||
687 | static int __init init_litmus_proc(void) | 693 | static int __init init_litmus_proc(void) |
688 | { | 694 | { |
@@ -702,6 +708,7 @@ static int __init init_litmus_proc(void) | |||
702 | curr_file->read_proc = proc_read_curr; | 708 | curr_file->read_proc = proc_read_curr; |
703 | curr_file->write_proc = proc_write_curr; | 709 | curr_file->write_proc = proc_write_curr; |
704 | 710 | ||
711 | #ifdef CONFIG_RELEASE_MASTER | ||
705 | release_master_file = create_proc_entry("release_master", | 712 | release_master_file = create_proc_entry("release_master", |
706 | 0644, litmus_dir); | 713 | 0644, litmus_dir); |
707 | if (!release_master_file) { | 714 | if (!release_master_file) { |
@@ -711,6 +718,7 @@ static int __init init_litmus_proc(void) | |||
711 | } | 718 | } |
712 | release_master_file->read_proc = proc_read_release_master; | 719 | release_master_file->read_proc = proc_read_release_master; |
713 | release_master_file->write_proc = proc_write_release_master; | 720 | release_master_file->write_proc = proc_write_release_master; |
721 | #endif | ||
714 | 722 | ||
715 | clus_cache_idx_file = create_proc_entry("cluster_cache", | 723 | clus_cache_idx_file = create_proc_entry("cluster_cache", |
716 | 0644, litmus_dir); | 724 | 0644, litmus_dir); |
@@ -741,8 +749,10 @@ static void exit_litmus_proc(void) | |||
741 | remove_proc_entry("active_plugin", litmus_dir); | 749 | remove_proc_entry("active_plugin", litmus_dir); |
742 | if (clus_cache_idx_file) | 750 | if (clus_cache_idx_file) |
743 | remove_proc_entry("cluster_cache", litmus_dir); | 751 | remove_proc_entry("cluster_cache", litmus_dir); |
752 | #ifdef CONFIG_RELEASE_MASTER | ||
744 | if (release_master_file) | 753 | if (release_master_file) |
745 | remove_proc_entry("release_master", litmus_dir); | 754 | remove_proc_entry("release_master", litmus_dir); |
755 | #endif | ||
746 | if (litmus_dir) | 756 | if (litmus_dir) |
747 | remove_proc_entry("litmus", NULL); | 757 | remove_proc_entry("litmus", NULL); |
748 | } | 758 | } |
diff --git a/litmus/rt_domain.c b/litmus/rt_domain.c index 8d5db6050723..26f1cc48f865 100644 --- a/litmus/rt_domain.c +++ b/litmus/rt_domain.c | |||
@@ -158,7 +158,9 @@ static void reinit_release_heap(struct task_struct* t) | |||
158 | 158 | ||
159 | /* initialize */ | 159 | /* initialize */ |
160 | bheap_init(&rh->heap); | 160 | bheap_init(&rh->heap); |
161 | #ifdef __ARCH_HAS_SEND_PULL_TIMERS | ||
161 | atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE); | 162 | atomic_set(&rh->info.state, HRTIMER_START_ON_INACTIVE); |
163 | #endif | ||
162 | } | 164 | } |
163 | /* arm_release_timer() - start local release timer or trigger | 165 | /* arm_release_timer() - start local release timer or trigger |
164 | * remote timer (pull timer) | 166 | * remote timer (pull timer) |
@@ -221,15 +223,19 @@ static void arm_release_timer(rt_domain_t *_rt) | |||
221 | * | 223 | * |
222 | * PINNED mode is ok on both local and remote CPU | 224 | * PINNED mode is ok on both local and remote CPU |
223 | */ | 225 | */ |
226 | #ifdef CONFIG_RELEASE_MASTER | ||
224 | if (rt->release_master == NO_CPU) | 227 | if (rt->release_master == NO_CPU) |
228 | #endif | ||
225 | __hrtimer_start_range_ns(&rh->timer, | 229 | __hrtimer_start_range_ns(&rh->timer, |
226 | ns_to_ktime(rh->release_time), | 230 | ns_to_ktime(rh->release_time), |
227 | 0, HRTIMER_MODE_ABS_PINNED, 0); | 231 | 0, HRTIMER_MODE_ABS_PINNED, 0); |
232 | #ifdef CONFIG_RELEASE_MASTER | ||
228 | else | 233 | else |
229 | hrtimer_start_on(rt->release_master, | 234 | hrtimer_start_on(rt->release_master, |
230 | &rh->info, &rh->timer, | 235 | &rh->info, &rh->timer, |
231 | ns_to_ktime(rh->release_time), | 236 | ns_to_ktime(rh->release_time), |
232 | HRTIMER_MODE_ABS_PINNED); | 237 | HRTIMER_MODE_ABS_PINNED); |
238 | #endif | ||
233 | } else | 239 | } else |
234 | TRACE_TASK(t, "0x%p is not my timer\n", &rh->timer); | 240 | TRACE_TASK(t, "0x%p is not my timer\n", &rh->timer); |
235 | } | 241 | } |
@@ -251,7 +257,9 @@ void rt_domain_init(rt_domain_t *rt, | |||
251 | if (!order) | 257 | if (!order) |
252 | order = dummy_order; | 258 | order = dummy_order; |
253 | 259 | ||
260 | #ifdef CONFIG_RELEASE_MASTER | ||
254 | rt->release_master = NO_CPU; | 261 | rt->release_master = NO_CPU; |
262 | #endif | ||
255 | 263 | ||
256 | bheap_init(&rt->ready_queue); | 264 | bheap_init(&rt->ready_queue); |
257 | INIT_LIST_HEAD(&rt->tobe_released); | 265 | INIT_LIST_HEAD(&rt->tobe_released); |
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index c0c63eba70ce..e101768740ad 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -382,11 +382,13 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) | |||
382 | int out_of_time, sleep, preempt, np, exists, blocks; | 382 | int out_of_time, sleep, preempt, np, exists, blocks; |
383 | struct task_struct* next = NULL; | 383 | struct task_struct* next = NULL; |
384 | 384 | ||
385 | #ifdef CONFIG_RELEASE_MASTER | ||
385 | /* Bail out early if we are the release master. | 386 | /* Bail out early if we are the release master. |
386 | * The release master never schedules any real-time tasks. | 387 | * The release master never schedules any real-time tasks. |
387 | */ | 388 | */ |
388 | if (gsnedf.release_master == entry->cpu) | 389 | if (gsnedf.release_master == entry->cpu) |
389 | return NULL; | 390 | return NULL; |
391 | #endif | ||
390 | 392 | ||
391 | raw_spin_lock(&gsnedf_lock); | 393 | raw_spin_lock(&gsnedf_lock); |
392 | clear_will_schedule(); | 394 | clear_will_schedule(); |
@@ -518,14 +520,18 @@ static void gsnedf_task_new(struct task_struct * t, int on_rq, int running) | |||
518 | entry = &per_cpu(gsnedf_cpu_entries, task_cpu(t)); | 520 | entry = &per_cpu(gsnedf_cpu_entries, task_cpu(t)); |
519 | BUG_ON(entry->scheduled); | 521 | BUG_ON(entry->scheduled); |
520 | 522 | ||
523 | #ifdef CONFIG_RELEASE_MASTER | ||
521 | if (entry->cpu != gsnedf.release_master) { | 524 | if (entry->cpu != gsnedf.release_master) { |
525 | #endif | ||
522 | entry->scheduled = t; | 526 | entry->scheduled = t; |
523 | tsk_rt(t)->scheduled_on = task_cpu(t); | 527 | tsk_rt(t)->scheduled_on = task_cpu(t); |
528 | #ifdef CONFIG_RELEASE_MASTER | ||
524 | } else { | 529 | } else { |
525 | /* do not schedule on release master */ | 530 | /* do not schedule on release master */ |
526 | preempt(entry); /* force resched */ | 531 | preempt(entry); /* force resched */ |
527 | tsk_rt(t)->scheduled_on = NO_CPU; | 532 | tsk_rt(t)->scheduled_on = NO_CPU; |
528 | } | 533 | } |
534 | #endif | ||
529 | } else { | 535 | } else { |
530 | t->rt_param.scheduled_on = NO_CPU; | 536 | t->rt_param.scheduled_on = NO_CPU; |
531 | } | 537 | } |
@@ -767,7 +773,9 @@ static long gsnedf_activate_plugin(void) | |||
767 | cpu_entry_t *entry; | 773 | cpu_entry_t *entry; |
768 | 774 | ||
769 | bheap_init(&gsnedf_cpu_heap); | 775 | bheap_init(&gsnedf_cpu_heap); |
776 | #ifdef CONFIG_RELEASE_MASTER | ||
770 | gsnedf.release_master = atomic_read(&release_master_cpu); | 777 | gsnedf.release_master = atomic_read(&release_master_cpu); |
778 | #endif | ||
771 | 779 | ||
772 | for_each_online_cpu(cpu) { | 780 | for_each_online_cpu(cpu) { |
773 | entry = &per_cpu(gsnedf_cpu_entries, cpu); | 781 | entry = &per_cpu(gsnedf_cpu_entries, cpu); |
@@ -775,12 +783,16 @@ static long gsnedf_activate_plugin(void) | |||
775 | atomic_set(&entry->will_schedule, 0); | 783 | atomic_set(&entry->will_schedule, 0); |
776 | entry->linked = NULL; | 784 | entry->linked = NULL; |
777 | entry->scheduled = NULL; | 785 | entry->scheduled = NULL; |
786 | #ifdef CONFIG_RELEASE_MASTER | ||
778 | if (cpu != gsnedf.release_master) { | 787 | if (cpu != gsnedf.release_master) { |
788 | #endif | ||
779 | TRACE("GSN-EDF: Initializing CPU #%d.\n", cpu); | 789 | TRACE("GSN-EDF: Initializing CPU #%d.\n", cpu); |
780 | update_cpu_position(entry); | 790 | update_cpu_position(entry); |
791 | #ifdef CONFIG_RELEASE_MASTER | ||
781 | } else { | 792 | } else { |
782 | TRACE("GSN-EDF: CPU %d is release master.\n", cpu); | 793 | TRACE("GSN-EDF: CPU %d is release master.\n", cpu); |
783 | } | 794 | } |
795 | #endif | ||
784 | } | 796 | } |
785 | return 0; | 797 | return 0; |
786 | } | 798 | } |