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 | } |
