Avoid a race condition that could lead to a segmentation fault.

Let's assume the callback function of a callback job returns
JOB_REQUEUE_FAIR in one call and JOB_REQUEUE_NONE in the next. Before
this fix, the thread executing the callback job would requeue the job
before unregistering itself. If there was a context switch right after
the job got requeued, and if the thread that requeued the job never got
resumed until a second thread executed the job and, due to the return
value of JOB_REQUEUE_NONE, destroyed it, then when the first thread
eventually got resumed and tried to lock the mutex to unregister itself
the pointer wouldn't be valid anymore, thus resulting in a segmentation fault.
This commit is contained in:
Tobias Brunner 2010-02-25 08:56:05 +01:00
parent 3e35a6e7a1
commit 608af0a445
1 changed files with 7 additions and 3 deletions

View File

@ -182,7 +182,7 @@ static void cancel(private_callback_job_t *this)
*/
static void execute(private_callback_job_t *this)
{
bool cleanup = FALSE;
bool cleanup = FALSE, requeue = FALSE;
thread_cleanup_push((thread_cleanup_t)destroy, this);
@ -206,8 +206,7 @@ static void execute(private_callback_job_t *this)
continue;
case JOB_REQUEUE_FAIR:
{
charon->processor->queue_job(charon->processor,
&this->public.job_interface);
requeue = TRUE;
break;
}
case JOB_REQUEUE_NONE:
@ -225,6 +224,11 @@ static void execute(private_callback_job_t *this)
/* manually create a cancellation point to avoid that a cancelled thread
* goes back into the thread pool */
thread_cancellation_point();
if (requeue)
{
charon->processor->queue_job(charon->processor,
&this->public.job_interface);
}
thread_cleanup_pop(cleanup);
}