From 6a225701acf7d79f292eeffcd99d6f00b02c180b Mon Sep 17 00:00:00 2001 From: Glenn Elliott Date: Fri, 7 Sep 2012 23:25:01 -0400 Subject: Infrastructure for Litmus signals. Added signals to Litmus. Specifcally, SIG_BUDGET signals are delivered (when requested by real-time tasks) when a budget is exceeded. Note: pfair not currently supported (but it probably could be). --- litmus/budget.c | 16 +++++++++++++-- litmus/jobs.c | 2 ++ litmus/litmus.c | 10 ++++++++++ litmus/sched_cedf.c | 47 ++++++++++++++++++++++++++++--------------- litmus/sched_gsn_edf.c | 54 ++++++++++++++++++++++++++++++++------------------ litmus/sched_pfp.c | 40 ++++++++++++++++++++++++++----------- litmus/sched_psn_edf.c | 41 ++++++++++++++++++++++++++------------ 7 files changed, 148 insertions(+), 62 deletions(-) (limited to 'litmus') diff --git a/litmus/budget.c b/litmus/budget.c index f7712be29adb..518174a37a3b 100644 --- a/litmus/budget.c +++ b/litmus/budget.c @@ -1,11 +1,13 @@ #include #include #include +#include #include #include #include +#include struct enforcement_timer { /* The enforcement timer is used to accurately police @@ -64,7 +66,7 @@ static void arm_enforcement_timer(struct enforcement_timer* et, /* Calling this when there is no budget left for the task * makes no sense, unless the task is non-preemptive. */ - BUG_ON(budget_exhausted(t) && (!is_np(t))); + BUG_ON(budget_exhausted(t) && !is_np(t)); /* __hrtimer_start_range_ns() cancels the timer * anyway, so we don't have to check whether it is still armed */ @@ -86,7 +88,7 @@ void update_enforcement_timer(struct task_struct* t) { struct enforcement_timer* et = &__get_cpu_var(budget_timer); - if (t && budget_precisely_enforced(t)) { + if (t && budget_precisely_tracked(t) && !sigbudget_sent(t)) { /* Make sure we call into the scheduler when this budget * expires. */ arm_enforcement_timer(et, t); @@ -96,6 +98,16 @@ void update_enforcement_timer(struct task_struct* t) } } +void send_sigbudget(struct task_struct* t) +{ + if (!test_and_set_bit(RT_JOB_SIG_BUDGET_SENT, &tsk_rt(t)->job_params.flags)) { + /* signal has not yet been sent and we are responsible for sending + * since we just set the sent-bit when it was previously 0. */ + + TRACE_TASK(t, "SIG_BUDGET being sent!\n"); + send_sig(SIG_BUDGET, t, 1); /* '1' denotes signal sent from kernel */ + } +} static int __init init_budget_enforcement(void) { diff --git a/litmus/jobs.c b/litmus/jobs.c index bc8246572e54..4981665a37bf 100644 --- a/litmus/jobs.c +++ b/litmus/jobs.c @@ -13,6 +13,8 @@ static inline void setup_release(struct task_struct *t, lt_t release) t->rt_param.job_params.deadline = release + get_rt_relative_deadline(t); t->rt_param.job_params.exec_time = 0; + clear_bit(RT_JOB_SIG_BUDGET_SENT, &t->rt_param.job_params.flags); + /* update job sequence number */ t->rt_param.job_params.job_no++; diff --git a/litmus/litmus.c b/litmus/litmus.c index 81384327e850..3526749852aa 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c @@ -136,6 +136,16 @@ asmlinkage long sys_set_rt_task_param(pid_t pid, struct rt_task __user * param) pid, tp.budget_policy); goto out_unlock; } + if (tp.budget_signal_policy != NO_SIGNALS && + tp.budget_signal_policy != QUANTUM_SIGNALS && + tp.budget_signal_policy != PRECISE_SIGNALS) + { + printk(KERN_INFO "litmus: real-time task %d rejected " + "because unsupported budget signalling policy " + "specified (%d)\n", + pid, tp.budget_signal_policy); + goto out_unlock; + } target->rt_param.task_params = tp; diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c index b0c16e34d2c5..208f067934fc 100644 --- a/litmus/sched_cedf.c +++ b/litmus/sched_cedf.c @@ -371,21 +371,29 @@ static noinline void job_completion(struct task_struct *t, int forced) */ static void cedf_tick(struct task_struct* t) { - if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { - if (!is_np(t)) { - /* np tasks will be preempted when they become - * preemptable again - */ - litmus_reschedule_local(); - set_will_schedule(); - TRACE("cedf_scheduler_tick: " - "%d is preemptable " - " => FORCE_RESCHED\n", t->pid); - } else if (is_user_np(t)) { - TRACE("cedf_scheduler_tick: " - "%d is non-preemptable, " - "preemption delayed.\n", t->pid); - request_exit_np(t); + if (is_realtime(t) && budget_exhausted(t)) + { + if (budget_signalled(t) && !sigbudget_sent(t)) { + /* signal exhaustion */ + send_sigbudget(t); + } + + if (budget_enforced(t)) { + if (!is_np(t)) { + /* np tasks will be preempted when they become + * preemptable again + */ + litmus_reschedule_local(); + set_will_schedule(); + TRACE("cedf_scheduler_tick: " + "%d is preemptable " + " => FORCE_RESCHED\n", t->pid); + } else if (is_user_np(t)) { + TRACE("cedf_scheduler_tick: " + "%d is non-preemptable, " + "preemption delayed.\n", t->pid); + request_exit_np(t); + } } } } @@ -415,7 +423,7 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) { cpu_entry_t* entry = &__get_cpu_var(cedf_cpu_entries); cedf_domain_t *cluster = entry->cluster; - int out_of_time, sleep, preempt, np, exists, blocks; + int out_of_time, signal_budget, sleep, preempt, np, exists, blocks; struct task_struct* next = NULL; #ifdef CONFIG_RELEASE_MASTER @@ -442,6 +450,10 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) out_of_time = exists && budget_enforced(entry->scheduled) && budget_exhausted(entry->scheduled); + signal_budget = exists && + budget_signalled(entry->scheduled) && + budget_exhausted(entry->scheduled) && + !sigbudget_sent(entry->scheduled); np = exists && is_np(entry->scheduled); sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP; preempt = entry->scheduled != entry->linked; @@ -460,6 +472,9 @@ static struct task_struct* cedf_schedule(struct task_struct * prev) TRACE_TASK(prev, "will be preempted by %s/%d\n", entry->linked->comm, entry->linked->pid); + /* Send the signal that the budget has been exhausted */ + if (signal_budget) + send_sigbudget(entry->scheduled); /* If a task blocks we have no choice but to reschedule. */ diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index c3344b9d288f..c1f25b56e51e 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c @@ -362,20 +362,28 @@ static noinline void job_completion(struct task_struct *t, int forced) */ static void gsnedf_tick(struct task_struct* t) { - if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { - if (!is_np(t)) { - /* np tasks will be preempted when they become - * preemptable again - */ - litmus_reschedule_local(); - TRACE("gsnedf_scheduler_tick: " - "%d is preemptable " - " => FORCE_RESCHED\n", t->pid); - } else if (is_user_np(t)) { - TRACE("gsnedf_scheduler_tick: " - "%d is non-preemptable, " - "preemption delayed.\n", t->pid); - request_exit_np(t); + if (is_realtime(t) && budget_exhausted(t)) + { + if (budget_signalled(t) && !sigbudget_sent(t)) { + /* signal exhaustion */ + send_sigbudget(t); + } + + if (budget_enforced(t)) { + if (!is_np(t)) { + /* np tasks will be preempted when they become + * preemptable again + */ + litmus_reschedule_local(); + TRACE("gsnedf_scheduler_tick: " + "%d is preemptable " + " => FORCE_RESCHED\n", t->pid); + } else if (is_user_np(t)) { + TRACE("gsnedf_scheduler_tick: " + "%d is non-preemptable, " + "preemption delayed.\n", t->pid); + request_exit_np(t); + } } } } @@ -404,7 +412,7 @@ static void gsnedf_tick(struct task_struct* t) static struct task_struct* gsnedf_schedule(struct task_struct * prev) { cpu_entry_t* entry = &__get_cpu_var(gsnedf_cpu_entries); - int out_of_time, sleep, preempt, np, exists, blocks; + int out_of_time, signal_budget, sleep, preempt, np, exists, blocks; struct task_struct* next = NULL; #ifdef CONFIG_RELEASE_MASTER @@ -427,8 +435,13 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) /* (0) Determine state */ exists = entry->scheduled != NULL; blocks = exists && !is_running(entry->scheduled); - out_of_time = exists && budget_enforced(entry->scheduled) - && budget_exhausted(entry->scheduled); + out_of_time = exists && + budget_enforced(entry->scheduled) && + budget_exhausted(entry->scheduled); + signal_budget = exists && + budget_signalled(entry->scheduled) && + budget_exhausted(entry->scheduled) && + !sigbudget_sent(entry->scheduled); np = exists && is_np(entry->scheduled); sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP; preempt = entry->scheduled != entry->linked; @@ -439,14 +452,17 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) if (exists) TRACE_TASK(prev, - "blocks:%d out_of_time:%d np:%d sleep:%d preempt:%d " + "blocks:%d out_of_time:%d signal_budget: %d np:%d sleep:%d preempt:%d " "state:%d sig:%d\n", - blocks, out_of_time, np, sleep, preempt, + blocks, out_of_time, signal_budget, np, sleep, preempt, prev->state, signal_pending(prev)); if (entry->linked && preempt) TRACE_TASK(prev, "will be preempted by %s/%d\n", entry->linked->comm, entry->linked->pid); + /* Send the signal that the budget has been exhausted */ + if (signal_budget) + send_sigbudget(entry->scheduled); /* If a task blocks we have no choice but to reschedule. */ diff --git a/litmus/sched_pfp.c b/litmus/sched_pfp.c index 62be699629b1..6129eb94d3ea 100644 --- a/litmus/sched_pfp.c +++ b/litmus/sched_pfp.c @@ -135,17 +135,25 @@ static void pfp_tick(struct task_struct *t) */ BUG_ON(is_realtime(t) && t != pfp->scheduled); - if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { - if (!is_np(t)) { - litmus_reschedule_local(); - TRACE("pfp_scheduler_tick: " - "%d is preemptable " - " => FORCE_RESCHED\n", t->pid); - } else if (is_user_np(t)) { - TRACE("pfp_scheduler_tick: " - "%d is non-preemptable, " - "preemption delayed.\n", t->pid); - request_exit_np(t); + if (is_realtime(t) && budget_exhausted(t)) + { + if (budget_signalled(t) && !sigbudget_sent(t)) { + /* signal exhaustion */ + send_sigbudget(t); + } + + if (budget_enforced(t)) { + if (!is_np(t)) { + litmus_reschedule_local(); + TRACE("pfp_scheduler_tick: " + "%d is preemptable " + " => FORCE_RESCHED\n", t->pid); + } else if (is_user_np(t)) { + TRACE("pfp_scheduler_tick: " + "%d is non-preemptable, " + "preemption delayed.\n", t->pid); + request_exit_np(t); + } } } } @@ -155,7 +163,7 @@ static struct task_struct* pfp_schedule(struct task_struct * prev) pfp_domain_t* pfp = local_pfp; struct task_struct* next; - int out_of_time, sleep, preempt, np, exists, blocks, resched, migrate; + int out_of_time, signal_budget, sleep, preempt, np, exists, blocks, resched, migrate; raw_spin_lock(&pfp->slock); @@ -172,6 +180,10 @@ static struct task_struct* pfp_schedule(struct task_struct * prev) out_of_time = exists && budget_enforced(pfp->scheduled) && budget_exhausted(pfp->scheduled); + signal_budget = exists && + budget_signalled(pfp->scheduled) && + budget_exhausted(pfp->scheduled) && + !sigbudget_sent(pfp->scheduled); np = exists && is_np(pfp->scheduled); sleep = exists && get_rt_flags(pfp->scheduled) == RT_F_SLEEP; migrate = exists && get_partition(pfp->scheduled) != pfp->cpu; @@ -183,6 +195,10 @@ static struct task_struct* pfp_schedule(struct task_struct * prev) */ resched = preempt; + /* Send the signal that the budget has been exhausted */ + if (signal_budget) + send_sigbudget(pfp->scheduled); + /* If a task blocks we have no choice but to reschedule. */ if (blocks) diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c index b0c8126bd44a..a5fda133bad9 100644 --- a/litmus/sched_psn_edf.c +++ b/litmus/sched_psn_edf.c @@ -169,17 +169,25 @@ static void psnedf_tick(struct task_struct *t) */ BUG_ON(is_realtime(t) && t != pedf->scheduled); - if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { - if (!is_np(t)) { - litmus_reschedule_local(); - TRACE("psnedf_scheduler_tick: " - "%d is preemptable " - " => FORCE_RESCHED\n", t->pid); - } else if (is_user_np(t)) { - TRACE("psnedf_scheduler_tick: " - "%d is non-preemptable, " - "preemption delayed.\n", t->pid); - request_exit_np(t); + if (is_realtime(t) && budget_exhausted(t)) + { + if (budget_signalled(t) && !sigbudget_sent(t)) { + /* signal exhaustion */ + send_sigbudget(t); + } + + if (budget_enforced(t)) { + if (!is_np(t)) { + litmus_reschedule_local(); + TRACE("psnedf_scheduler_tick: " + "%d is preemptable " + " => FORCE_RESCHED\n", t->pid); + } else if (is_user_np(t)) { + TRACE("psnedf_scheduler_tick: " + "%d is non-preemptable, " + "preemption delayed.\n", t->pid); + request_exit_np(t); + } } } } @@ -190,8 +198,7 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev) rt_domain_t* edf = &pedf->domain; struct task_struct* next; - int out_of_time, sleep, preempt, - np, exists, blocks, resched; + int out_of_time, signal_budget, sleep, preempt, np, exists, blocks, resched; raw_spin_lock(&pedf->slock); @@ -208,6 +215,10 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev) out_of_time = exists && budget_enforced(pedf->scheduled) && budget_exhausted(pedf->scheduled); + signal_budget = exists && + budget_signalled(pedf->scheduled) && + budget_exhausted(pedf->scheduled) && + !sigbudget_sent(pedf->scheduled); np = exists && is_np(pedf->scheduled); sleep = exists && get_rt_flags(pedf->scheduled) == RT_F_SLEEP; preempt = edf_preemption_needed(edf, prev); @@ -218,6 +229,10 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev) */ resched = preempt; + /* Send the signal that the budget has been exhausted */ + if (signal_budget) + send_sigbudget(pedf->scheduled); + /* If a task blocks we have no choice but to reschedule. */ if (blocks) -- cgit v1.2.2