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 09:26:16 +01:00
parent 3e35a6e7a1
commit 608af0a445
+7 -3
View File
@@ -182,7 +182,7 @@ static void cancel(private_callback_job_t *this)
*/ */
static void execute(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); thread_cleanup_push((thread_cleanup_t)destroy, this);
@@ -206,8 +206,7 @@ static void execute(private_callback_job_t *this)
continue; continue;
case JOB_REQUEUE_FAIR: case JOB_REQUEUE_FAIR:
{ {
charon->processor->queue_job(charon->processor, requeue = TRUE;
&this->public.job_interface);
break; break;
} }
case JOB_REQUEUE_NONE: 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 /* manually create a cancellation point to avoid that a cancelled thread
* goes back into the thread pool */ * goes back into the thread pool */
thread_cancellation_point(); thread_cancellation_point();
if (requeue)
{
charon->processor->queue_job(charon->processor,
&this->public.job_interface);
}
thread_cleanup_pop(cleanup); thread_cleanup_pop(cleanup);
} }