diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2013-06-08 15:56:13 -0400 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2013-06-08 16:06:56 -0400 |
commit | 39d902832855cbd2baf45ac8943879be3ad8ca5a (patch) | |
tree | 2aa3b4f70c1253bece9f85f7eba1203f188970ac | |
parent | 8319864c96a4b2cd519c2183f61dedc39e3d13a4 (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.h | 3 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 4 | ||||
-rw-r--r-- | litmus/jobs.c | 1 | ||||
-rw-r--r-- | litmus/sync.c | 16 |
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 | ||
37 | void release_at(struct task_struct *t, lt_t start) | 38 | void 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); |