[PATCH] Fix a pthreadpool race
Ralph Wuerthner
ralphw at de.ibm.com
Mon Dec 18 13:39:09 UTC 2017
On 15.12.2017 12:54, Volker Lendecke wrote:
> On Fri, Dec 15, 2017 at 12:17:07PM +0100, Ralph Wuerthner wrote:
>
> That is of course a lot more elegant. Looking through the code I have
> one concern: The threads are kept busy throughout the fork, which is
> good. I would like to see a good argument why the while(num_idle!=0)
> loop in pthreadpool_prepare_pool deterministically terminates. It's
> probably not really supported right now, but what if a helper thread
> creates new jobs? This might keep the helper threads busy, and they
> might re-enter idle state over and over again when prepare_pool checks
> for idle threads. More parallelism is good, your patch is of course
> simpler and thus preferrable, but I would feel better if we had a
> "proof" that prepare_pool never runs into an endless loop. Keep in
> mind that every single small race we open will eventually be hit at a
> customer installation :-)
I looked at my patch again and identified a deadlock when
pthread_cond_timedwait() in pthreadpool_server() exits with ETIMEDOUT,
no jobs are pending and a fork is in progress. With my original patch
the thread would exit without signaling pool->prefork_cond which would
result in a deadlock. Please see my updated patch with a fix for this.
Other than that I checked the code and from my perspective all idle
threads deterministically terminate:
Assume the following start condition: pthreadpool_prepare_pool() has
been entered and we are in the while (pool->num_idle != 0) loop
resulting in pool->prefork_cond is not NULL. I can see the following
states for worker threads:
1) a new worker thread has been created
The new thread will enter the while(1) loop in pthreadpool_server(). If
no new jobs are outstanding the thread will terminate immediately
because pool->prefork_cond != NULL without calling
pthread_cond_timedwait() and without becoming an idle thread.
If jobs are outstanding a job will be pulled from the job list and the
job function will be called and we continue as described in state 2).
The thread will not become an idle thread.
2) a worker threads just completed the job function
If no more jobs are outstanding and the shutdown flag is set the thread
will terminate. If not the thread will jump back to the beginning of the
while(1) loop. If no jobs are outstanding the thread will terminate
immediately because pool->prefork_cond != NULL without becoming an idle
thread. Otherwise the thread will pull a job from the job list, the job
function will be called and we continue as described in state 2).
3) an idle thread is waiting on the conditional variable pool->condvar
The thread will wakeup. We signal pthreadpool_prepare_pool() that the
number of idle threads has been decreased. If no more jobs are
outstanding the thread terminates immediately. If a timeout occurred and
no more jobs are outstanding the thread terminates immediately too.
From now on the thread is only running if jobs are outstanding: the job
function will be called and the thread will continue as described in
state 2).
Overall: threads can become idle only when no fork is in progress.
Already idle threads will wakeup and terminate if no jobs are present or
process the next jobs.
--
Regards
Ralph Wuerthner
-------------- next part --------------
A non-text attachment was scrubbed...
Name: fix-job-starvation-after-fork-race-v2.patch
Type: text/x-patch
Size: 11832 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20171218/46dce6a5/fix-job-starvation-after-fork-race-v2.bin>
More information about the samba-technical
mailing list