aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2013-06-08 15:56:13 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2013-06-08 16:06:56 -0400
commit39d902832855cbd2baf45ac8943879be3ad8ca5a (patch)
tree2aa3b4f70c1253bece9f85f7eba1203f188970ac
parent8319864c96a4b2cd519c2183f61dedc39e3d13a4 (diff)
Fix synchronous task system release support
...and also finally fix the requeue() race (hopefully). Commit 4ffefb822b9d65d4efbedb60e3c9a0e76895cc5b broke the synchronous task system release code. The problem is that release_at() clears the tsk_rt(t)->completed flag. The patch thus only made the race window smaller, but didn't close it entirely. Further, it broke the synchronous task set release, which relies on schedule() being called with completed == 1. This patch fixes both problems by introducing a new flag dont_requeue, which indicates unambiguously that a task should not be requeued by other processors. This flag is cleared only when the job completion is being processed, which always happens while holding the appropriate scheduler locks, which closes the race window.
-rw-r--r--include/litmus/budget.h3
-rw-r--r--include/litmus/rt_param.h4
-rw-r--r--litmus/jobs.c1
-rw-r--r--litmus/sync.c16
4 files changed, 17 insertions, 7 deletions
diff --git a/include/litmus/budget.h b/include/litmus/budget.h
index c4e9e40a828e..a766781b87d4 100644
--- a/include/litmus/budget.h
+++ b/include/litmus/budget.h
@@ -29,7 +29,8 @@ static inline int requeue_preempted_job(struct task_struct* t)
29 /* Add task to ready queue only if not subject to budget enforcement or 29 /* Add task to ready queue only if not subject to budget enforcement or
30 * if the job has budget remaining. t may be NULL. 30 * if the job has budget remaining. t may be NULL.
31 */ 31 */
32 return t && !is_completed(t) && (!budget_exhausted(t) || !budget_enforced(t)); 32 return t && !is_completed(t) && !tsk_rt(t)->dont_requeue
33 && (!budget_exhausted(t) || !budget_enforced(t));
33} 34}
34 35
35#endif 36#endif
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
index 0b40b23a8589..bd2baf1e306c 100644
--- a/include/litmus/rt_param.h
+++ b/include/litmus/rt_param.h
@@ -182,6 +182,10 @@ struct rt_param {
182 /* has the task completed? */ 182 /* has the task completed? */
183 unsigned int completed:1; 183 unsigned int completed:1;
184 184
185 /* prevent this task from being requeued on another processor (used to
186 * coordinate GSN-EDF, C-EDF, and sync.c) */
187 unsigned int dont_requeue:1;
188
185#ifdef CONFIG_LITMUS_LOCKING 189#ifdef CONFIG_LITMUS_LOCKING
186 /* Is the task being priority-boosted by a locking protocol? */ 190 /* Is the task being priority-boosted by a locking protocol? */
187 unsigned int priority_boosted:1; 191 unsigned int priority_boosted:1;
diff --git a/litmus/jobs.c b/litmus/jobs.c
index 3edb7ab4af60..32685012503b 100644
--- a/litmus/jobs.c
+++ b/litmus/jobs.c
@@ -32,6 +32,7 @@ void prepare_for_next_period(struct task_struct *t)
32 (long long)t->rt_param.job_params.deadline; 32 (long long)t->rt_param.job_params.deadline;
33 33
34 setup_release(t, get_release(t) + get_rt_period(t)); 34 setup_release(t, get_release(t) + get_rt_period(t));
35 tsk_rt(t)->dont_requeue = 0;
35} 36}
36 37
37void release_at(struct task_struct *t, lt_t start) 38void release_at(struct task_struct *t, lt_t start)
diff --git a/litmus/sync.c b/litmus/sync.c
index 8ff5b9e298eb..61a95463e4d2 100644
--- a/litmus/sync.c
+++ b/litmus/sync.c
@@ -52,18 +52,22 @@ static long do_wait_for_ts_release(void)
52 if (!ret) { 52 if (!ret) {
53 /* Setting this flag before releasing ensures that this CPU 53 /* Setting this flag before releasing ensures that this CPU
54 * will be the next CPU to requeue the task on a ready or 54 * will be the next CPU to requeue the task on a ready or
55 * release queue. 55 * release queue. Cleared by prepare_for_next_period()
56 */ 56 */
57 tsk_rt(current)->completed = 1; 57 tsk_rt(current)->dont_requeue = 1;
58 mb();
59 58
60 /* Completion succeeded, setup release. */ 59 /* Completion succeeded, setup release time. complete_job()
60 * will indirectly cause the period to be added to the next
61 * release time, so subtract it here. */
61 litmus->release_at(current, wait.ts_release_time 62 litmus->release_at(current, wait.ts_release_time
62 + current->rt_param.task_params.phase 63 + current->rt_param.task_params.phase
63 - current->rt_param.task_params.period); 64 - current->rt_param.task_params.period);
64 65
65 schedule(); 66 /* Advance to next job --- when complete_job() returns, the
66 ret = 0; 67 * first job has been released. Since we patched up the release
68 * time, this occurs when all tasks synchronously release their
69 * first job.*/
70 ret = complete_job();
67 } else { 71 } else {
68 /* We were interrupted, must cleanup list. */ 72 /* We were interrupted, must cleanup list. */
69 mutex_lock(&task_release_lock); 73 mutex_lock(&task_release_lock);