From c58a74c8ad2d2b1b01be12afb9bac58dfef0d16a Mon Sep 17 00:00:00 2001 From: Glenn Elliott Date: Sun, 16 Sep 2012 18:29:36 -0400 Subject: Added CONFIG_REALTIME_AUX_TASKS option Auxillary task features were enabled by CONFIG_LITMUS_LOCKING. Made auxillary tasks a seperate feature that depends upon CONFIG_LITMUS_LOCKING. --- litmus/Kconfig | 31 +++++++++++++++++++++++++++++++ litmus/Makefile | 3 ++- litmus/aux_tasks.c | 23 ++++++++++------------- litmus/edf_common.c | 29 ++++++++++++++++++----------- litmus/litmus.c | 8 ++------ litmus/sched_gsn_edf.c | 26 ++++++++++++++++++-------- 6 files changed, 81 insertions(+), 39 deletions(-) (limited to 'litmus') diff --git a/litmus/Kconfig b/litmus/Kconfig index 95e0671e2aec..c5dbc4a176ae 100644 --- a/litmus/Kconfig +++ b/litmus/Kconfig @@ -34,6 +34,37 @@ config RELEASE_MASTER (http://www.cs.unc.edu/~anderson/papers.html). Currently only supported by GSN-EDF. +config REALTIME_AUX_TASKS + bool "Real-Time Auxillary Tasks" + depends on LITMUS_LOCKING + default n + help + Adds a system call that forces all non-real-time threads in a process + to become auxillary real-time tasks. These tasks inherit the priority of + the highest-prio *BLOCKED* real-time task (non-auxillary) in the process. + This allows the integration of COTS code that has background helper threads + used primarily for message passing and synchronization. If these + background threads are NOT real-time scheduled, then unbounded priority + inversions may occur if a real-time task blocks on a non-real-time thread. + + Beware of the following pitfalls: + 1) Auxillary threads should not be CPU intensive. They should mostly + block on mutexes and condition variables. Violating this will + likely prevent meaningful analysis. + 2) Since there may be more than one auxillary thread per process, + priority inversions may occur with respect to single-threaded + task models if/when one of threads are scheduled simultanously + with another of the same identity. + 3) Busy-wait deadlock is likely between normal real-time tasks and + auxillary tasks synchronize using _preemptive_ spinlocks that do + not use priority inheritance. + + These pitfalls are mitgated by the fact that auxillary tasks only + inherit priorities from blocked tasks (Blocking signifies that the + blocked task _may_ be waiting on an auxillary task to perform some + work.). Futher, auxillary tasks without an inherited priority are + _always_ scheduled with a priority less than any normal real-time task!! + endmenu menu "Real-Time Synchronization" diff --git a/litmus/Makefile b/litmus/Makefile index f2dd7be7ae4a..67d8b8ee72bc 100644 --- a/litmus/Makefile +++ b/litmus/Makefile @@ -18,6 +18,7 @@ obj-y = sched_plugin.o litmus.o \ bheap.o \ binheap.o \ ctrldev.o \ + aux_tasks.o \ sched_gsn_edf.o \ sched_psn_edf.o \ sched_pfp.o @@ -31,7 +32,7 @@ obj-$(CONFIG_SCHED_TASK_TRACE) += sched_task_trace.o obj-$(CONFIG_SCHED_DEBUG_TRACE) += sched_trace.o obj-$(CONFIG_SCHED_OVERHEAD_TRACE) += trace.o -obj-$(CONFIG_LITMUS_LOCKING) += aux_tasks.o kfmlp_lock.o +obj-$(CONFIG_LITMUS_LOCKING) += kfmlp_lock.o obj-$(CONFIG_LITMUS_NESTED_LOCKING) += rsm_lock.o ikglp_lock.o obj-$(CONFIG_LITMUS_SOFTIRQD) += litmus_softirq.o obj-$(CONFIG_LITMUS_PAI_SOFTIRQD) += litmus_pai_softirq.o diff --git a/litmus/aux_tasks.c b/litmus/aux_tasks.c index 5057137bbbea..b0617accdf7f 100644 --- a/litmus/aux_tasks.c +++ b/litmus/aux_tasks.c @@ -1,8 +1,8 @@ -#ifdef CONFIG_LITMUS_LOCKING - #include #include #include + +#ifdef CONFIG_REALTIME_AUX_TASKS #include #include @@ -23,14 +23,11 @@ static int admit_aux_task(struct task_struct *t) * fail-safe. */ struct rt_task tp = { - //.period = MAGIC_AUX_TASK_PERIOD, - //.relative_deadline = MAGIC_AUX_TASK_PERIOD, - .period = 1000000, /* has to wait 1 ms before it can run again once it has exhausted budget */ + .period = 1000000, /* 1ms */ .relative_deadline = 1000000, .exec_cost = 1000000, /* allow full utilization */ .phase = 0, .cpu = task_cpu(leader), /* take CPU of group leader */ - //.budget_policy = NO_ENFORCEMENT, .budget_policy = QUANTUM_ENFORCEMENT, .budget_signal_policy = NO_SIGNALS, .cls = RT_CLASS_BEST_EFFORT @@ -280,7 +277,7 @@ static int aux_task_owner_max_priority_order(struct binheap_node *a, } -static long __do_enable_slave_non_rt_threads(void) +static long __do_enable_aux_tasks(void) { long retval = 0; struct task_struct *leader; @@ -344,7 +341,7 @@ static long __do_enable_slave_non_rt_threads(void) return retval; } -static long __do_disable_slave_non_rt_threads(void) +static long __do_disable_aux_tasks(void) { long retval = 0; struct task_struct *leader; @@ -385,17 +382,17 @@ static long __do_disable_slave_non_rt_threads(void) return retval; } -asmlinkage long sys_slave_non_rt_threads(int enable) +asmlinkage long sys_set_aux_tasks(int enable) { long retval; read_lock_irq(&tasklist_lock); if (enable) { - retval = __do_enable_slave_non_rt_threads(); + retval = __do_enable_aux_tasks(); } else { - retval = __do_disable_slave_non_rt_threads(); + retval = __do_disable_aux_tasks(); } read_unlock_irq(&tasklist_lock); @@ -405,9 +402,9 @@ asmlinkage long sys_slave_non_rt_threads(int enable) #else -asmlinkage long sys_slave_non_rt_tasks(int enable) +asmlinkage long sys_set_aux_tasks(int enable) { - printk("Unsupported. Recompile with CONFIG_LITMUS_LOCKING.\n"); + printk("Unsupported. Recompile with CONFIG_REALTIME_AUX_TASKS.\n"); return -EINVAL; } diff --git a/litmus/edf_common.c b/litmus/edf_common.c index ca06f6ec103e..7e0d3a5d0c4d 100644 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c @@ -22,7 +22,7 @@ #include #endif -//#ifdef CONFIG_EDF_TIE_BREAK_HASH +#if defined(CONFIG_EDF_TIE_BREAK_HASH) || defined(CONFIG_REALTIME_AUX_TASKS) #include static inline long edf_hash(struct task_struct *t) { @@ -41,8 +41,9 @@ static inline long edf_hash(struct task_struct *t) */ return hash_32(hash_32((u32)tsk_rt(t)->job_params.job_no, 32) ^ t->pid, 32); } -//#endif +#endif +#ifdef CONFIG_REALTIME_AUX_TASKS int aux_tie_break(struct task_struct *first, struct task_struct *second) { long fhash = edf_hash(first); @@ -57,6 +58,7 @@ int aux_tie_break(struct task_struct *first, struct task_struct *second) } return 0; } +#endif /* edf_higher_prio - returns true if first has a higher EDF priority @@ -75,11 +77,6 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second) struct task_struct *first_task = first; struct task_struct *second_task = second; - int first_lo_aux; - int second_lo_aux; - int first_hi_aux; - int second_hi_aux; - /* There is no point in comparing a task to itself. */ if (first && first == second) { TRACE_CUR("WARNING: pointless edf priority comparison: %s/%d\n", first->comm, first->pid); @@ -93,8 +90,14 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second) return first && !second; } -#ifdef CONFIG_LITMUS_LOCKING +#ifdef CONFIG_REALTIME_AUX_TASKS + { + /* statically prioritize all auxillary tasks that have no inheritance + * below all other regular real-time tasks. + */ + int first_lo_aux, second_lo_aux; + int first_hi_aux, second_hi_aux; first_lo_aux = first->rt_param.is_aux_task && !first->rt_param.inh_task; second_lo_aux = second->rt_param.is_aux_task && !second->rt_param.inh_task; @@ -120,8 +123,10 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second) TRACE_CUR("hi aux tie break: %s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, aux_hi_tie_break); return aux_hi_tie_break; } + } +#endif - +#ifdef CONFIG_LITMUS_LOCKING /* Check for EFFECTIVE priorities. Change task * used for comparison in such a case. */ @@ -233,11 +238,13 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second) return 1; } #endif + +#ifdef CONFIG_REALTIME_AUX_TASKS + /* is this dead code? */ if (tsk_rt(first)->is_aux_task < tsk_rt(second)->is_aux_task) { - TRACE_CUR("AUX BREAK!\n"); return 1; } - +#endif /* Something could be wrong if you get this far. */ if (unlikely(first->rt_param.inh_task == diff --git a/litmus/litmus.c b/litmus/litmus.c index e2bf2a7ad01b..d368202ab8c3 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c @@ -25,7 +25,7 @@ #include #endif -#ifdef CONFIG_LITMUS_LOCKING +#ifdef CONFIG_REALTIME_AUX_TASKS #include #endif @@ -413,7 +413,7 @@ static void reinit_litmus_state(struct task_struct* p, int restore) /* Cleanup everything else. */ memset(&p->rt_param, 0, sizeof(p->rt_param)); -#ifdef CONFIG_LITMUS_LOCKING +#ifdef CONFIG_REALTIME_AUX_TASKS /* also clear out the aux_data. the !restore case is only called on * fork (initial thread creation). */ if (!restore) @@ -623,10 +623,6 @@ void litmus_fork(struct task_struct* p) tsk_rt(p)->ctrl_page = NULL; reinit_litmus_state(p, 0); - - /* still don't inherit any parental parameters */ - //memset(&p->rt_param, 0, sizeof(p->rt_param)); - //memset(&p->aux_data, 0, sizeof(p->aux_data)); } /* od tables are never inherited across a fork */ diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 270e06c20bbf..5fc330f14a0e 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c @@ -29,7 +29,6 @@ #ifdef CONFIG_LITMUS_LOCKING #include -#include #endif #ifdef CONFIG_LITMUS_NESTED_LOCKING @@ -41,6 +40,10 @@ #include #endif +#ifdef CONFIG_REALTIME_AUX_TASKS +#include +#endif + #ifdef CONFIG_LITMUS_SOFTIRQD #include #endif @@ -313,15 +316,15 @@ static noinline void requeue(struct task_struct* task) BUG_ON(is_queued(task)); if (is_released(task, litmus_clock())) { - +#ifdef CONFIG_REALTIME_AUX_TASKS if (unlikely(tsk_rt(task)->is_aux_task && !is_running(task))) { /* aux_task probably transitioned to real-time while it was blocked */ TRACE_CUR("aux task %s/%d is not ready!\n", task->comm, task->pid); unlink(task); /* really needed? */ } - else { + else +#endif __add_ready(&gsnedf, task); - } } else { /* it has got to wait */ @@ -1046,11 +1049,12 @@ static void gsnedf_task_wake_up(struct task_struct *task) set_rt_flags(task, RT_F_RUNNING); #endif +#ifdef CONFIG_REALTIME_AUX_TASKS if (tsk_rt(task)->has_aux_tasks) { - TRACE_CUR("%s/%d is ready so aux tasks may not inherit.\n", task->comm, task->pid); disable_aux_task_owner(task); } +#endif gsnedf_job_arrival(task); raw_spin_unlock_irqrestore(&gsnedf_lock, flags); @@ -1067,11 +1071,13 @@ static void gsnedf_task_block(struct task_struct *t) unlink(t); +#ifdef CONFIG_REALTIME_AUX_TASKS if (tsk_rt(t)->has_aux_tasks) { TRACE_CUR("%s/%d is blocked so aux tasks may inherit.\n", t->comm, t->pid); enable_aux_task_owner(t); } +#endif raw_spin_unlock_irqrestore(&gsnedf_lock, flags); @@ -1087,7 +1093,7 @@ static void gsnedf_task_exit(struct task_struct * t) gsnedf_change_prio_pai_tasklet(t, NULL); #endif -#ifdef CONFIG_LITMUS_LOCKING +#ifdef CONFIG_REALTIME_AUX_TASKS if (tsk_rt(t)->is_aux_task) { exit_aux_task(t); /* cannot be called with gsnedf_lock held */ } @@ -1096,7 +1102,7 @@ static void gsnedf_task_exit(struct task_struct * t) /* unlink if necessary */ raw_spin_lock_irqsave(&gsnedf_lock, flags); -#ifdef CONFIG_LITMUS_LOCKING +#ifdef CONFIG_REALTIME_AUX_TASKS /* make sure we clean up on our way out */ if(tsk_rt(t)->has_aux_tasks) { disable_aux_task_owner(t); /* must be called witl gsnedf_lock held */ @@ -1209,11 +1215,12 @@ static int __increase_priority_inheritance(struct task_struct* t, check_for_preemptions(); } - +#ifdef CONFIG_REALTIME_AUX_TASKS /* propagate to aux tasks */ if (tsk_rt(t)->has_aux_tasks) { aux_task_owner_increase_priority(t); } +#endif } #ifdef CONFIG_LITMUS_NESTED_LOCKING } @@ -1319,10 +1326,13 @@ static int __decrease_priority_inheritance(struct task_struct* t, raw_spin_unlock(&gsnedf.release_lock); } +#ifdef CONFIG_REALTIME_AUX_TASKS /* propagate to aux tasks */ if (tsk_rt(t)->has_aux_tasks) { aux_task_owner_decrease_priority(t); } +#endif + #ifdef CONFIG_LITMUS_NESTED_LOCKING } else { -- cgit v1.2.2