diff options
| -rw-r--r-- | include/litmus/budget.h | 20 | ||||
| -rw-r--r-- | include/litmus/rt_param.h | 16 | ||||
| -rw-r--r-- | include/litmus/signal.h | 47 | ||||
| -rw-r--r-- | litmus/budget.c | 16 | ||||
| -rw-r--r-- | litmus/jobs.c | 2 | ||||
| -rw-r--r-- | litmus/litmus.c | 10 | ||||
| -rw-r--r-- | litmus/sched_cedf.c | 47 | ||||
| -rw-r--r-- | litmus/sched_gsn_edf.c | 54 | ||||
| -rw-r--r-- | litmus/sched_pfp.c | 40 | ||||
| -rw-r--r-- | litmus/sched_psn_edf.c | 41 |
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. */ |
| 6 | void update_enforcement_timer(struct task_struct* t); | 6 | void update_enforcement_timer(struct task_struct* t); |
| 7 | 7 | ||
| 8 | /* Send SIG_BUDGET to a real-time task. */ | ||
| 9 | void send_sigbudget(struct task_struct* t); | ||
| 10 | |||
| 8 | inline static int budget_exhausted(struct task_struct* t) | 11 | inline 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 | ||
| 27 | static inline int requeue_preempted_job(struct task_struct* t) | 41 | static 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 { | |||
| 30 | typedef enum { | 30 | typedef 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 | ||
| 36 | typedef 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 | ||
| 67 | union np_flag { | 74 | union 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 | |||
| 123 | struct pfair_param; | 137 | struct 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 | /* | ||
| 32 | Future 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 | ||
| 10 | struct enforcement_timer { | 12 | struct 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 | ||
| 101 | void 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 | ||
| 100 | static int __init init_budget_enforcement(void) | 112 | static 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 | */ |
| 372 | static void cedf_tick(struct task_struct* t) | 372 | static 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 | */ |
| 363 | static void gsnedf_tick(struct task_struct* t) | 363 | static 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) | |||
| 404 | static struct task_struct* gsnedf_schedule(struct task_struct * prev) | 412 | static 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) |
