On Sunday 22 May 2011, Jeff Trawick wrote:
> > Can those people who frequently hit the testreslist failures
> > please check if this commit helps? From a powerpc Debian build
> > host, it looks promising, but I don't have direct access to that
> > machine and can't do repeated tests there.
>
> no luck on Windows 7
>
> apr-util 1.3.x, gcc, still fails
> apr trunk, Visual C++ 2008 Express, still fails
>
> Seven:~/svn/apr-util-1.3.x-xx/test$ ./testall -v testreslist
> testreslist : /Line 258: expected <10>, but saw <20>
> FAILED 1 of 1
> Failed Tests Total Fail Failed %
> ===================================================
> testreslist 1 1 100.00%
Can you try the attached patch in addition? Is this failure sporadic
or always?
> > Unfortunately, there are also other thread-safety issues in
> > apr/apr- util. Using hellgrind on testreslist found these
> > issues:
> >
> > - unsafe read of pool->child in apr_pool_destroy. This one
> > worries me. If a subpool is destroyed in one thread while the
> > pool itself is destroyed in another thread, it can happen that
> > apr_pool_destroy is called again for the subpool. This would
> > likely lead to a crash. Any ideas on how to fix this without
> > sacrificing too much performance?
> >
> > - unsafe read of allocator->max_index (PR 48535, likely not
> > critical)
> >
> > - unsafe read of _myself->thd_cnt in thread_pool_cleanup()
> > (likely not critical; but there seem to be other thread-safety
> > issues in that file, at least the access of thd_high is also
> > unsafe)
The last one is fixed by the attached patch. I no longer think that it
is no problem.
diff --git a/util-misc/apr_thread_pool.c b/util-misc/apr_thread_pool.c
index 006370b..b6a5297 100644
--- a/util-misc/apr_thread_pool.c
+++ b/util-misc/apr_thread_pool.c
@@ -333,9 +333,13 @@ static apr_status_t thread_pool_cleanup(void *me)
_myself->terminated = 1;
apr_thread_pool_idle_max_set(_myself, 0);
+ apr_thread_mutex_lock(_myself->lock);
while (_myself->thd_cnt) {
+ apr_thread_mutex_unlock(_myself->lock);
apr_sleep(20 * 1000); /* spin lock with 20 ms */
+ apr_thread_mutex_lock(_myself->lock);
}
+ apr_thread_mutex_unlock(_myself->lock);
apr_thread_mutex_destroy(_myself->lock);
apr_thread_cond_destroy(_myself->cond);
return APR_SUCCESS;
@@ -367,14 +371,13 @@ APR_DECLARE(apr_status_t) apr_thread_pool_create(apr_thread_pool_t ** me,
apr_pool_cleanup_register(tp->pool, tp, thread_pool_cleanup,
apr_pool_cleanup_null);
+ apr_thread_mutex_lock(tp->lock);
while (init_threads) {
/* Grab the mutex as apr_thread_create() and thread_pool_func() will
* allocate from (*me)->pool. This is dangerous if there are multiple
* initial threads to create.
*/
- apr_thread_mutex_lock(tp->lock);
rv = apr_thread_create(&t, NULL, thread_pool_func, tp, tp->pool);
- apr_thread_mutex_unlock(tp->lock);
if (APR_SUCCESS != rv) {
break;
}
@@ -384,6 +387,7 @@ APR_DECLARE(apr_status_t) apr_thread_pool_create(apr_thread_pool_t ** me,
}
--init_threads;
}
+ apr_thread_mutex_unlock(tp->lock);
if (rv == APR_SUCCESS) {
*me = tp;