aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-09-07 23:25:01 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2012-09-07 23:33:05 -0400
commit6a225701acf7d79f292eeffcd99d6f00b02c180b (patch)
tree6a7f538703a5a6460a0e53c62f0f952998840ea1
parentb53c479a0f44b8990ce106622412a3bf54809944 (diff)
Infrastructure for Litmus signals.prop/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).
-rw-r--r--include/litmus/budget.h20
-rw-r--r--include/litmus/rt_param.h16
-rw-r--r--include/litmus/signal.h47
-rw-r--r--litmus/budget.c16
-rw-r--r--litmus/jobs.c2
-rw-r--r--litmus/litmus.c10
-rw-r--r--litmus/sched_cedf.c47
-rw-r--r--litmus/sched_gsn_edf.c54
-rw-r--r--litmus/sched_pfp.c40
-rw-r--r--litmus/sched_psn_edf.c41
10 files changed, 227 insertions, 66 deletions
diff --git a/include/litmus/budget.h b/include/litmus/budget.h
index 33344ee8d5f9..763b31c0e9f6 100644
--- a/include/litmus/budget.h
+++ b/include/litmus/budget.h
@@ -5,6 +5,9 @@
5 * the next task. */ 5 * the next task. */
6void update_enforcement_timer(struct task_struct* t); 6void update_enforcement_timer(struct task_struct* t);
7 7
8/* Send SIG_BUDGET to a real-time task. */
9void send_sigbudget(struct task_struct* t);
10
8inline static int budget_exhausted(struct task_struct* t) 11inline static int budget_exhausted(struct task_struct* t)
9{ 12{
10 return get_exec_time(t) >= get_exec_cost(t); 13 return get_exec_time(t) >= get_exec_cost(t);
@@ -19,10 +22,21 @@ inline static lt_t budget_remaining(struct task_struct* t)
19 return 0; 22 return 0;
20} 23}
21 24
22#define budget_enforced(t) (tsk_rt(t)->task_params.budget_policy != NO_ENFORCEMENT) 25#define budget_enforced(t) (\
26 tsk_rt(t)->task_params.budget_policy != NO_ENFORCEMENT)
27
28#define budget_precisely_tracked(t) (\
29 tsk_rt(t)->task_params.budget_policy == PRECISE_ENFORCEMENT || \
30 tsk_rt(t)->task_params.budget_signal_policy == PRECISE_SIGNALS)
31
32#define budget_signalled(t) (\
33 tsk_rt(t)->task_params.budget_signal_policy != NO_SIGNALS)
34
35#define budget_precisely_signalled(t) (\
36 tsk_rt(t)->task_params.budget_policy == PRECISE_SIGNALS)
23 37
24#define budget_precisely_enforced(t) (tsk_rt(t)->task_params.budget_policy \ 38#define sigbudget_sent(t) (\
25 == PRECISE_ENFORCEMENT) 39 test_bit(RT_JOB_SIG_BUDGET_SENT, &tsk_rt(t)->job_params.flags))
26 40
27static inline int requeue_preempted_job(struct task_struct* t) 41static inline int requeue_preempted_job(struct task_struct* t)
28{ 42{
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
index 89ac0dda7d3d..637fe6b84f9d 100644
--- a/include/litmus/rt_param.h
+++ b/include/litmus/rt_param.h
@@ -30,9 +30,15 @@ typedef enum {
30typedef enum { 30typedef enum {
31 NO_ENFORCEMENT, /* job may overrun unhindered */ 31 NO_ENFORCEMENT, /* job may overrun unhindered */
32 QUANTUM_ENFORCEMENT, /* budgets are only checked on quantum boundaries */ 32 QUANTUM_ENFORCEMENT, /* budgets are only checked on quantum boundaries */
33 PRECISE_ENFORCEMENT /* budgets are enforced with hrtimers */ 33 PRECISE_ENFORCEMENT, /* budgets are enforced with hrtimers */
34} budget_policy_t; 34} budget_policy_t;
35 35
36typedef enum {
37 NO_SIGNALS, /* job receives no signals when it exhausts its budget */
38 QUANTUM_SIGNALS, /* budget signals are only sent on quantum boundaries */
39 PRECISE_SIGNALS, /* budget signals are triggered with hrtimers */
40} budget_signal_policy_t;
41
36/* We use the common priority interpretation "lower index == higher priority", 42/* We use the common priority interpretation "lower index == higher priority",
37 * which is commonly used in fixed-priority schedulability analysis papers. 43 * which is commonly used in fixed-priority schedulability analysis papers.
38 * So, a numerically lower priority value implies higher scheduling priority, 44 * So, a numerically lower priority value implies higher scheduling priority,
@@ -62,6 +68,7 @@ struct rt_task {
62 unsigned int priority; 68 unsigned int priority;
63 task_class_t cls; 69 task_class_t cls;
64 budget_policy_t budget_policy; /* ignored by pfair */ 70 budget_policy_t budget_policy; /* ignored by pfair */
71 budget_signal_policy_t budget_signal_policy; /* currently ignored by pfair */
65}; 72};
66 73
67union np_flag { 74union np_flag {
@@ -118,8 +125,15 @@ struct rt_job {
118 * Increase this sequence number when a job is released. 125 * Increase this sequence number when a job is released.
119 */ 126 */
120 unsigned int job_no; 127 unsigned int job_no;
128
129 /* bits:
130 * 0th: Set if a budget exhaustion signal has already been sent for
131 * the current job. */
132 unsigned long flags;
121}; 133};
122 134
135#define RT_JOB_SIG_BUDGET_SENT 0
136
123struct pfair_param; 137struct pfair_param;
124 138
125/* RT task parameters for scheduling extensions 139/* RT task parameters for scheduling extensions
diff --git a/include/litmus/signal.h b/include/litmus/signal.h
new file mode 100644
index 000000000000..b3d82b294984
--- /dev/null
+++ b/include/litmus/signal.h
@@ -0,0 +1,47 @@
1#ifndef LITMUS_SIGNAL_H
2#define LITMUS_SIGNAL_H
3
4#ifdef __KERNEL__
5#include <linux/signal.h>
6#else
7#include <signal.h>
8#endif
9
10/* Signals used by Litmus to asynchronously communicate events
11 * to real-time tasks.
12 *
13 * Signal values overlap with [SIGRTMIN, SIGRTMAX], so beware of
14 * application-level conflicts when dealing with COTS user-level
15 * code.
16 */
17
18/* Sent to a Litmus task when all of the following conditions are true:
19 * (1) The task has exhausted its budget.
20 * (2) budget_signal_policy is QUANTUM_SIGNALS or PRECISE_SIGNALS.
21 *
22 * Note: If a task does not have a registered handler for SIG_BUDGET,
23 * the signal will cause the task to terminate (default action).
24 */
25
26/* Assigned values start at SIGRTMAX and decrease, hopefully reducing
27 * likelihood of user-level conflicts.
28 */
29#define SIG_BUDGET (SIGRTMAX - 0)
30
31/*
32Future signals could include:
33
34#define SIG_DEADLINE_MISS (SIGRTMAX - 1)
35#define SIG_CRIT_LEVEL_CHANGE (SIGRTMAX - 2)
36*/
37
38#define SIGLITMUSMIN SIG_BUDGET
39
40#ifdef __KERNEL__
41#if (SIGLITMUSMIN < SIGRTMIN)
42/* no compile-time check in user-space since SIGRTMIN may be a variable. */
43#error "Too many LITMUS^RT signals!"
44#endif
45#endif
46
47#endif
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 @@
1#include <linux/sched.h> 1#include <linux/sched.h>
2#include <linux/percpu.h> 2#include <linux/percpu.h>
3#include <linux/hrtimer.h> 3#include <linux/hrtimer.h>
4#include <linux/signal.h>
4 5
5#include <litmus/litmus.h> 6#include <litmus/litmus.h>
6#include <litmus/preempt.h> 7#include <litmus/preempt.h>
7 8
8#include <litmus/budget.h> 9#include <litmus/budget.h>
10#include <litmus/signal.h>
9 11
10struct enforcement_timer { 12struct enforcement_timer {
11 /* The enforcement timer is used to accurately police 13 /* The enforcement timer is used to accurately police
@@ -64,7 +66,7 @@ static void arm_enforcement_timer(struct enforcement_timer* et,
64 66
65 /* Calling this when there is no budget left for the task 67 /* Calling this when there is no budget left for the task
66 * makes no sense, unless the task is non-preemptive. */ 68 * makes no sense, unless the task is non-preemptive. */
67 BUG_ON(budget_exhausted(t) && (!is_np(t))); 69 BUG_ON(budget_exhausted(t) && !is_np(t));
68 70
69 /* __hrtimer_start_range_ns() cancels the timer 71 /* __hrtimer_start_range_ns() cancels the timer
70 * anyway, so we don't have to check whether it is still armed */ 72 * 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)
86{ 88{
87 struct enforcement_timer* et = &__get_cpu_var(budget_timer); 89 struct enforcement_timer* et = &__get_cpu_var(budget_timer);
88 90
89 if (t && budget_precisely_enforced(t)) { 91 if (t && budget_precisely_tracked(t) && !sigbudget_sent(t)) {
90 /* Make sure we call into the scheduler when this budget 92 /* Make sure we call into the scheduler when this budget
91 * expires. */ 93 * expires. */
92 arm_enforcement_timer(et, t); 94 arm_enforcement_timer(et, t);
@@ -96,6 +98,16 @@ void update_enforcement_timer(struct task_struct* t)
96 } 98 }
97} 99}
98 100
101void send_sigbudget(struct task_struct* t)
102{
103 if (!test_and_set_bit(RT_JOB_SIG_BUDGET_SENT, &tsk_rt(t)->job_params.flags)) {
104 /* signal has not yet been sent and we are responsible for sending
105 * since we just set the sent-bit when it was previously 0. */
106
107 TRACE_TASK(t, "SIG_BUDGET being sent!\n");
108 send_sig(SIG_BUDGET, t, 1); /* '1' denotes signal sent from kernel */
109 }
110}
99 111
100static int __init init_budget_enforcement(void) 112static int __init init_budget_enforcement(void)
101{ 113{
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)
13 t->rt_param.job_params.deadline = release + get_rt_relative_deadline(t); 13 t->rt_param.job_params.deadline = release + get_rt_relative_deadline(t);
14 t->rt_param.job_params.exec_time = 0; 14 t->rt_param.job_params.exec_time = 0;
15 15
16 clear_bit(RT_JOB_SIG_BUDGET_SENT, &t->rt_param.job_params.flags);
17
16 /* update job sequence number */ 18 /* update job sequence number */
17 t->rt_param.job_params.job_no++; 19 t->rt_param.job_params.job_no++;
18 20
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)
136 pid, tp.budget_policy); 136 pid, tp.budget_policy);
137 goto out_unlock; 137 goto out_unlock;
138 } 138 }
139 if (tp.budget_signal_policy != NO_SIGNALS &&
140 tp.budget_signal_policy != QUANTUM_SIGNALS &&
141 tp.budget_signal_policy != PRECISE_SIGNALS)
142 {
143 printk(KERN_INFO "litmus: real-time task %d rejected "
144 "because unsupported budget signalling policy "
145 "specified (%d)\n",
146 pid, tp.budget_signal_policy);
147 goto out_unlock;
148 }
139 149
140 target->rt_param.task_params = tp; 150 target->rt_param.task_params = tp;
141 151
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)
371 */ 371 */
372static void cedf_tick(struct task_struct* t) 372static void cedf_tick(struct task_struct* t)
373{ 373{
374 if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { 374 if (is_realtime(t) && budget_exhausted(t))
375 if (!is_np(t)) { 375 {
376 /* np tasks will be preempted when they become 376 if (budget_signalled(t) && !sigbudget_sent(t)) {
377 * preemptable again 377 /* signal exhaustion */
378 */ 378 send_sigbudget(t);
379 litmus_reschedule_local(); 379 }
380 set_will_schedule(); 380
381 TRACE("cedf_scheduler_tick: " 381 if (budget_enforced(t)) {
382 "%d is preemptable " 382 if (!is_np(t)) {
383 " => FORCE_RESCHED\n", t->pid); 383 /* np tasks will be preempted when they become
384 } else if (is_user_np(t)) { 384 * preemptable again
385 TRACE("cedf_scheduler_tick: " 385 */
386 "%d is non-preemptable, " 386 litmus_reschedule_local();
387 "preemption delayed.\n", t->pid); 387 set_will_schedule();
388 request_exit_np(t); 388 TRACE("cedf_scheduler_tick: "
389 "%d is preemptable "
390 " => FORCE_RESCHED\n", t->pid);
391 } else if (is_user_np(t)) {
392 TRACE("cedf_scheduler_tick: "
393 "%d is non-preemptable, "
394 "preemption delayed.\n", t->pid);
395 request_exit_np(t);
396 }
389 } 397 }
390 } 398 }
391} 399}
@@ -415,7 +423,7 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
415{ 423{
416 cpu_entry_t* entry = &__get_cpu_var(cedf_cpu_entries); 424 cpu_entry_t* entry = &__get_cpu_var(cedf_cpu_entries);
417 cedf_domain_t *cluster = entry->cluster; 425 cedf_domain_t *cluster = entry->cluster;
418 int out_of_time, sleep, preempt, np, exists, blocks; 426 int out_of_time, signal_budget, sleep, preempt, np, exists, blocks;
419 struct task_struct* next = NULL; 427 struct task_struct* next = NULL;
420 428
421#ifdef CONFIG_RELEASE_MASTER 429#ifdef CONFIG_RELEASE_MASTER
@@ -442,6 +450,10 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
442 out_of_time = exists && 450 out_of_time = exists &&
443 budget_enforced(entry->scheduled) && 451 budget_enforced(entry->scheduled) &&
444 budget_exhausted(entry->scheduled); 452 budget_exhausted(entry->scheduled);
453 signal_budget = exists &&
454 budget_signalled(entry->scheduled) &&
455 budget_exhausted(entry->scheduled) &&
456 !sigbudget_sent(entry->scheduled);
445 np = exists && is_np(entry->scheduled); 457 np = exists && is_np(entry->scheduled);
446 sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP; 458 sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP;
447 preempt = entry->scheduled != entry->linked; 459 preempt = entry->scheduled != entry->linked;
@@ -460,6 +472,9 @@ static struct task_struct* cedf_schedule(struct task_struct * prev)
460 TRACE_TASK(prev, "will be preempted by %s/%d\n", 472 TRACE_TASK(prev, "will be preempted by %s/%d\n",
461 entry->linked->comm, entry->linked->pid); 473 entry->linked->comm, entry->linked->pid);
462 474
475 /* Send the signal that the budget has been exhausted */
476 if (signal_budget)
477 send_sigbudget(entry->scheduled);
463 478
464 /* If a task blocks we have no choice but to reschedule. 479 /* If a task blocks we have no choice but to reschedule.
465 */ 480 */
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)
362 */ 362 */
363static void gsnedf_tick(struct task_struct* t) 363static void gsnedf_tick(struct task_struct* t)
364{ 364{
365 if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { 365 if (is_realtime(t) && budget_exhausted(t))
366 if (!is_np(t)) { 366 {
367 /* np tasks will be preempted when they become 367 if (budget_signalled(t) && !sigbudget_sent(t)) {
368 * preemptable again 368 /* signal exhaustion */
369 */ 369 send_sigbudget(t);
370 litmus_reschedule_local(); 370 }
371 TRACE("gsnedf_scheduler_tick: " 371
372 "%d is preemptable " 372 if (budget_enforced(t)) {
373 " => FORCE_RESCHED\n", t->pid); 373 if (!is_np(t)) {
374 } else if (is_user_np(t)) { 374 /* np tasks will be preempted when they become
375 TRACE("gsnedf_scheduler_tick: " 375 * preemptable again
376 "%d is non-preemptable, " 376 */
377 "preemption delayed.\n", t->pid); 377 litmus_reschedule_local();
378 request_exit_np(t); 378 TRACE("gsnedf_scheduler_tick: "
379 "%d is preemptable "
380 " => FORCE_RESCHED\n", t->pid);
381 } else if (is_user_np(t)) {
382 TRACE("gsnedf_scheduler_tick: "
383 "%d is non-preemptable, "
384 "preemption delayed.\n", t->pid);
385 request_exit_np(t);
386 }
379 } 387 }
380 } 388 }
381} 389}
@@ -404,7 +412,7 @@ static void gsnedf_tick(struct task_struct* t)
404static struct task_struct* gsnedf_schedule(struct task_struct * prev) 412static struct task_struct* gsnedf_schedule(struct task_struct * prev)
405{ 413{
406 cpu_entry_t* entry = &__get_cpu_var(gsnedf_cpu_entries); 414 cpu_entry_t* entry = &__get_cpu_var(gsnedf_cpu_entries);
407 int out_of_time, sleep, preempt, np, exists, blocks; 415 int out_of_time, signal_budget, sleep, preempt, np, exists, blocks;
408 struct task_struct* next = NULL; 416 struct task_struct* next = NULL;
409 417
410#ifdef CONFIG_RELEASE_MASTER 418#ifdef CONFIG_RELEASE_MASTER
@@ -427,8 +435,13 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev)
427 /* (0) Determine state */ 435 /* (0) Determine state */
428 exists = entry->scheduled != NULL; 436 exists = entry->scheduled != NULL;
429 blocks = exists && !is_running(entry->scheduled); 437 blocks = exists && !is_running(entry->scheduled);
430 out_of_time = exists && budget_enforced(entry->scheduled) 438 out_of_time = exists &&
431 && budget_exhausted(entry->scheduled); 439 budget_enforced(entry->scheduled) &&
440 budget_exhausted(entry->scheduled);
441 signal_budget = exists &&
442 budget_signalled(entry->scheduled) &&
443 budget_exhausted(entry->scheduled) &&
444 !sigbudget_sent(entry->scheduled);
432 np = exists && is_np(entry->scheduled); 445 np = exists && is_np(entry->scheduled);
433 sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP; 446 sleep = exists && get_rt_flags(entry->scheduled) == RT_F_SLEEP;
434 preempt = entry->scheduled != entry->linked; 447 preempt = entry->scheduled != entry->linked;
@@ -439,14 +452,17 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev)
439 452
440 if (exists) 453 if (exists)
441 TRACE_TASK(prev, 454 TRACE_TASK(prev,
442 "blocks:%d out_of_time:%d np:%d sleep:%d preempt:%d " 455 "blocks:%d out_of_time:%d signal_budget: %d np:%d sleep:%d preempt:%d "
443 "state:%d sig:%d\n", 456 "state:%d sig:%d\n",
444 blocks, out_of_time, np, sleep, preempt, 457 blocks, out_of_time, signal_budget, np, sleep, preempt,
445 prev->state, signal_pending(prev)); 458 prev->state, signal_pending(prev));
446 if (entry->linked && preempt) 459 if (entry->linked && preempt)
447 TRACE_TASK(prev, "will be preempted by %s/%d\n", 460 TRACE_TASK(prev, "will be preempted by %s/%d\n",
448 entry->linked->comm, entry->linked->pid); 461 entry->linked->comm, entry->linked->pid);
449 462
463 /* Send the signal that the budget has been exhausted */
464 if (signal_budget)
465 send_sigbudget(entry->scheduled);
450 466
451 /* If a task blocks we have no choice but to reschedule. 467 /* If a task blocks we have no choice but to reschedule.
452 */ 468 */
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)
135 */ 135 */
136 BUG_ON(is_realtime(t) && t != pfp->scheduled); 136 BUG_ON(is_realtime(t) && t != pfp->scheduled);
137 137
138 if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { 138 if (is_realtime(t) && budget_exhausted(t))
139 if (!is_np(t)) { 139 {
140 litmus_reschedule_local(); 140 if (budget_signalled(t) && !sigbudget_sent(t)) {
141 TRACE("pfp_scheduler_tick: " 141 /* signal exhaustion */
142 "%d is preemptable " 142 send_sigbudget(t);
143 " => FORCE_RESCHED\n", t->pid); 143 }
144 } else if (is_user_np(t)) { 144
145 TRACE("pfp_scheduler_tick: " 145 if (budget_enforced(t)) {
146 "%d is non-preemptable, " 146 if (!is_np(t)) {
147 "preemption delayed.\n", t->pid); 147 litmus_reschedule_local();
148 request_exit_np(t); 148 TRACE("pfp_scheduler_tick: "
149 "%d is preemptable "
150 " => FORCE_RESCHED\n", t->pid);
151 } else if (is_user_np(t)) {
152 TRACE("pfp_scheduler_tick: "
153 "%d is non-preemptable, "
154 "preemption delayed.\n", t->pid);
155 request_exit_np(t);
156 }
149 } 157 }
150 } 158 }
151} 159}
@@ -155,7 +163,7 @@ static struct task_struct* pfp_schedule(struct task_struct * prev)
155 pfp_domain_t* pfp = local_pfp; 163 pfp_domain_t* pfp = local_pfp;
156 struct task_struct* next; 164 struct task_struct* next;
157 165
158 int out_of_time, sleep, preempt, np, exists, blocks, resched, migrate; 166 int out_of_time, signal_budget, sleep, preempt, np, exists, blocks, resched, migrate;
159 167
160 raw_spin_lock(&pfp->slock); 168 raw_spin_lock(&pfp->slock);
161 169
@@ -172,6 +180,10 @@ static struct task_struct* pfp_schedule(struct task_struct * prev)
172 out_of_time = exists && 180 out_of_time = exists &&
173 budget_enforced(pfp->scheduled) && 181 budget_enforced(pfp->scheduled) &&
174 budget_exhausted(pfp->scheduled); 182 budget_exhausted(pfp->scheduled);
183 signal_budget = exists &&
184 budget_signalled(pfp->scheduled) &&
185 budget_exhausted(pfp->scheduled) &&
186 !sigbudget_sent(pfp->scheduled);
175 np = exists && is_np(pfp->scheduled); 187 np = exists && is_np(pfp->scheduled);
176 sleep = exists && get_rt_flags(pfp->scheduled) == RT_F_SLEEP; 188 sleep = exists && get_rt_flags(pfp->scheduled) == RT_F_SLEEP;
177 migrate = exists && get_partition(pfp->scheduled) != pfp->cpu; 189 migrate = exists && get_partition(pfp->scheduled) != pfp->cpu;
@@ -183,6 +195,10 @@ static struct task_struct* pfp_schedule(struct task_struct * prev)
183 */ 195 */
184 resched = preempt; 196 resched = preempt;
185 197
198 /* Send the signal that the budget has been exhausted */
199 if (signal_budget)
200 send_sigbudget(pfp->scheduled);
201
186 /* If a task blocks we have no choice but to reschedule. 202 /* If a task blocks we have no choice but to reschedule.
187 */ 203 */
188 if (blocks) 204 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)
169 */ 169 */
170 BUG_ON(is_realtime(t) && t != pedf->scheduled); 170 BUG_ON(is_realtime(t) && t != pedf->scheduled);
171 171
172 if (is_realtime(t) && budget_enforced(t) && budget_exhausted(t)) { 172 if (is_realtime(t) && budget_exhausted(t))
173 if (!is_np(t)) { 173 {
174 litmus_reschedule_local(); 174 if (budget_signalled(t) && !sigbudget_sent(t)) {
175 TRACE("psnedf_scheduler_tick: " 175 /* signal exhaustion */
176 "%d is preemptable " 176 send_sigbudget(t);
177 " => FORCE_RESCHED\n", t->pid); 177 }
178 } else if (is_user_np(t)) { 178
179 TRACE("psnedf_scheduler_tick: " 179 if (budget_enforced(t)) {
180 "%d is non-preemptable, " 180 if (!is_np(t)) {
181 "preemption delayed.\n", t->pid); 181 litmus_reschedule_local();
182 request_exit_np(t); 182 TRACE("psnedf_scheduler_tick: "
183 "%d is preemptable "
184 " => FORCE_RESCHED\n", t->pid);
185 } else if (is_user_np(t)) {
186 TRACE("psnedf_scheduler_tick: "
187 "%d is non-preemptable, "
188 "preemption delayed.\n", t->pid);
189 request_exit_np(t);
190 }
183 } 191 }
184 } 192 }
185} 193}
@@ -190,8 +198,7 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev)
190 rt_domain_t* edf = &pedf->domain; 198 rt_domain_t* edf = &pedf->domain;
191 struct task_struct* next; 199 struct task_struct* next;
192 200
193 int out_of_time, sleep, preempt, 201 int out_of_time, signal_budget, sleep, preempt, np, exists, blocks, resched;
194 np, exists, blocks, resched;
195 202
196 raw_spin_lock(&pedf->slock); 203 raw_spin_lock(&pedf->slock);
197 204
@@ -208,6 +215,10 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev)
208 out_of_time = exists && 215 out_of_time = exists &&
209 budget_enforced(pedf->scheduled) && 216 budget_enforced(pedf->scheduled) &&
210 budget_exhausted(pedf->scheduled); 217 budget_exhausted(pedf->scheduled);
218 signal_budget = exists &&
219 budget_signalled(pedf->scheduled) &&
220 budget_exhausted(pedf->scheduled) &&
221 !sigbudget_sent(pedf->scheduled);
211 np = exists && is_np(pedf->scheduled); 222 np = exists && is_np(pedf->scheduled);
212 sleep = exists && get_rt_flags(pedf->scheduled) == RT_F_SLEEP; 223 sleep = exists && get_rt_flags(pedf->scheduled) == RT_F_SLEEP;
213 preempt = edf_preemption_needed(edf, prev); 224 preempt = edf_preemption_needed(edf, prev);
@@ -218,6 +229,10 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev)
218 */ 229 */
219 resched = preempt; 230 resched = preempt;
220 231
232 /* Send the signal that the budget has been exhausted */
233 if (signal_budget)
234 send_sigbudget(pedf->scheduled);
235
221 /* If a task blocks we have no choice but to reschedule. 236 /* If a task blocks we have no choice but to reschedule.
222 */ 237 */
223 if (blocks) 238 if (blocks)