thread safety and mpm-prefork
I've written a module which I believe to be thread-safe but appears to be doing something which I have put down to a lack of thread safety in pool management (somewhere). Before I tear my hair out here, my module is running with apache 2.2.22 and mpm-prefork on Ubuntu. Do the thread primatives actually do anything in mpm-prefork? I'm using apr_thread_create to create a thread, then providing a separate allocator, mutex, pool and similar (all as recommended). But if the mutex stuff is 'optimised out' of my apr library - specifically the pool stuff - all this will be in vain. -- Alex Bligh
Re: thread safety and mpm-prefork
On 2013-06-11 21:20, Alex Bligh wrote: I've written a module which I believe to be thread-safe but appears to be doing something which I have put down to a lack of thread safety in pool management (somewhere). Before I tear my hair out here, my module is running with apache 2.2.22 and mpm-prefork on Ubuntu. Do the thread primatives actually do anything in mpm-prefork? I'm using apr_thread_create to create a thread, then providing a separate allocator, mutex, pool and similar (all as recommended). But if the mutex stuff is 'optimised out' of my apr library - specifically the pool stuff - all this will be in vain. apr_* and mpm_prefork are different software packages and ubuntu distributes them separately. So it is almost certain that you have a thread-enabled libapr (i.e. compiled with APR_HAS_THREADS). You would not be able to compile the code that uses apr_thread_create if your libapr was not compiled with thread support. mpm_prefork is like any ordinary client of libapr. Just that it does not use the threading functionality in libapr. So it cannot disable/optimise out the mutexes in libapr. Please be aware that apr_pools are not thread-safe. Only the creation of subpools is thread-safe. So you should create a subpool per thread to stay safe. Sorin
Re: thread safety and mpm-prefork
Sorin, On 11 Jun 2013, at 21:57, Sorin Manolache wrote: The threadallocatormutex is created from a child of the request pool. The request pool and its child-pools are destroyed when the request terminates. Do you use the threadpool/threadallocator/threadallocatormutex afterwards? Nope. It's one long running request, and at the end of the request handler, the thread I've created is _join'ed, and the pools are destroyed. When I torture test it, I can run 10 hours of fullscreen video through it, and every 5 or 6th such test results in a core dump (inevitably a bucket brigade pointer being unhappy). We have a customer who seems to be talented at making things go wrong and who does not get an abort/segv, but a 100% CPU live lock. gdb suggests the destruction of the bucket brigade goes around and around - again a symptom of bucket brigade linked list pointers being unhappy. -- Alex Bligh
Re: thread safety and mpm-prefork
On 11 Jun 2013, at 23:06, Sorin Manolache wrote: I'm sorry, I ran out of ideas. I suppose that the operations of the two threads on the bucket brigade are protected by mutexes... Yep. I create my own output bucket brigade too. I *presume* this uses the allocator mutex to manipulate the bucket brigade (or that it contains its own mutex) protecting its link-next pointers. /* We cannot use the same bucket allocator for the ouput bucket brigade * obb as the one associated with the connection (r-connection-bucket_alloc) * because the same bucket allocator cannot be used in two different * threads, and we use the connection bucket allocator in this * thread - see docs on apr_bucket_alloc_create(). This results in * occasional core dumps. So create our own bucket allocator and pool * for output thread bucket brigade. */ ... if ( ( apr_thread_mutex_create(oallocatormutex, APR_THREAD_MUTEX_UNNESTED, r-pool) == APR_SUCCESS) ( apr_allocator_create(oallocator) == APR_SUCCESS) ( apr_allocator_mutex_set(oallocator, oallocatormutex), 1 ) ( apr_pool_create_ex(opool, NULL, NULL, oallocator) == APR_SUCCESS) /* WARNING: pool has no parent */ ( NULL != (obucketallocator = apr_bucket_alloc_create(opool))) ( NULL != (obb = apr_brigade_create(opool, obucketallocator))) ) { -- Alex Bligh