From 39d902832855cbd2baf45ac8943879be3ad8ca5a Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Sat, 8 Jun 2013 21:56:13 +0200 Subject: 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. --- litmus/jobs.c | 1 + litmus/sync.c | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'litmus') 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) (long long)t->rt_param.job_params.deadline; setup_release(t, get_release(t) + get_rt_period(t)); + tsk_rt(t)->dont_requeue = 0; } 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) if (!ret) { /* Setting this flag before releasing ensures that this CPU * will be the next CPU to requeue the task on a ready or - * release queue. + * release queue. Cleared by prepare_for_next_period() */ - tsk_rt(current)->completed = 1; - mb(); + tsk_rt(current)->dont_requeue = 1; - /* Completion succeeded, setup release. */ + /* Completion succeeded, setup release time. complete_job() + * will indirectly cause the period to be added to the next + * release time, so subtract it here. */ litmus->release_at(current, wait.ts_release_time + current->rt_param.task_params.phase - current->rt_param.task_params.period); - schedule(); - ret = 0; + /* Advance to next job --- when complete_job() returns, the + * first job has been released. Since we patched up the release + * time, this occurs when all tasks synchronously release their + * first job.*/ + ret = complete_job(); } else { /* We were interrupted, must cleanup list. */ mutex_lock(&task_release_lock); -- cgit v1.2.2