--- apr-1.4.5/include/apr_pools.h 2009-09-09 19:51:09.000000000 +0100 +++ apr-1.4.5-ts/include/apr_pools.h 2011-06-17 11:07:19.000000000 +0100 @@ -199,6 +199,31 @@ apr_allocator_t *allocator); /** + * Create a new thread-safe pool. + * + * This function differs from apr_pool_create_ex in that a thread-safe + * pool is created - in other words you can call apr_pool_palloc from + * multiple threads safely on the pool created from this function. + * + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + * @param abort_fn A function to use if the pool cannot allocate more memory. + * @param allocator The allocator to use with the new pool. If NULL the + * allocator of the parent pool will be used. + * @remark This function is thread-safe, in the sense that multiple threads + * can safely create subpools of the same parent pool concurrently. + * Similarly, a subpool can be created by one thread at the same + * time that another thread accesses the parent pool. + */ +APR_DECLARE(apr_status_t) apr_pool_create_threadsafe_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator); + +/** * Create a new pool. * @deprecated @see apr_pool_create_unmanaged_ex. */ @@ -243,6 +268,11 @@ apr_abortfunc_t abort_fn, apr_allocator_t *allocator, const char *file_line); +APR_DECLARE(apr_status_t) apr_pool_create_threadsafe_ex_debug(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line); #if APR_POOL_DEBUG #define apr_pool_create_ex(newpool, parent, abort_fn, allocator) \ @@ -317,6 +347,37 @@ #endif /** + * Create a new thread-safe pool. + * + * This function differs from apr_pool_create in that a thread-safe + * pool is created - in other words you can call apr_pool_palloc from + * multiple threads safely on the pool created from this function. + * + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + * @remark This function is thread-safe, in the sense that multiple threads + * can safely create subpools of the same parent pool concurrently. + * Similarly, a subpool can be created by one thread at the same + * time that another thread accesses the parent pool. + */ +#if defined(DOXYGEN) +APR_DECLARE(apr_status_t) apr_pool_create_threadsafe(apr_pool_t **newpool, + apr_pool_t *parent); +#else +#if APR_POOL_DEBUG +#define apr_pool_create_threadsafe(newpool, parent) \ + apr_pool_create_threadsafe_ex_debug(newpool, parent, NULL, NULL, \ + APR_POOL__FILE_LINE__) +#else +#define apr_pool_create_threadsafe(newpool, parent) \ + apr_pool_create_threadsafe_ex(newpool, parent, NULL, NULL) +#endif +#endif + +/** * Create a new pool. * @param newpool The pool we have just created. */ --- apr-1.4.5/memory/unix/apr_pools.c 2011-03-21 14:58:46.000000000 +0000 +++ apr-1.4.5-ts/memory/unix/apr_pools.c 2011-06-17 10:58:42.000000000 +0100 @@ -522,6 +522,7 @@ #if APR_HAS_THREADS apr_os_thread_t owner; apr_thread_mutex_t *mutex; + int thread_safe; /* boolean */ #endif /* APR_HAS_THREADS */ #endif /* APR_POOL_DEBUG */ #ifdef NETWARE @@ -673,6 +674,11 @@ return NULL; } + +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_lock( pool->mutex ); +#endif active = pool->active; /* If the active node has enough bytes left, use it. */ @@ -680,6 +686,11 @@ mem = active->first_avail; active->first_avail += size; +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_unlock( pool->mutex ); +#endif + return mem; } @@ -689,6 +700,11 @@ } else { if ((node = allocator_alloc(pool->allocator, size)) == NULL) { +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_unlock( pool->mutex ); +#endif + if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); @@ -710,8 +726,14 @@ active->free_index = (APR_UINT32_TRUNC_CAST)free_index; node = active->next; - if (free_index >= node->free_index) + if (free_index >= node->free_index) { +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_unlock( pool->mutex ); +#endif + return mem; + } do { node = node->next; @@ -721,6 +743,11 @@ list_remove(active); list_insert(active, node); +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_unlock( pool->mutex ); +#endif + return mem; } @@ -860,6 +887,34 @@ } } +APR_DECLARE(apr_status_t) apr_pool_create_threadsafe_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) +{ + apr_status_t rv; + + rv = apr_pool_create_ex(newpool,parent,abort_fn,allocator); + if ( APR_SUCCESS == rv ) { + // create mutex for pool + if ( (*newpool)->mutex == NULL ) { + rv = apr_thread_mutex_create( + &((*newpool)->mutex), + APR_THREAD_MUTEX_NESTED, + *newpool + ); + if ( APR_SUCCESS != rv ) { + apr_pool_destroy( rv ); + return( rv ); + } + } + + (*newpool)->thread_safe = 1; + } + + return( status ); +} + APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, @@ -907,6 +962,8 @@ pool->subprocesses = NULL; pool->user_data = NULL; pool->tag = NULL; + pool->mutex = NULL; + pool->thread_safe = 0; #ifdef NETWARE pool->owner_proc = (apr_os_proc_t)getnlmhandle(); @@ -1192,7 +1249,6 @@ return strp; } - #else /* APR_POOL_DEBUG */ /* * Debug helper functions @@ -1339,6 +1395,7 @@ #if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) #if APR_HAS_THREADS + if (! pool->thread_safe) { if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) { #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) apr_pool_log_event(pool, "THREAD", @@ -1346,6 +1403,7 @@ #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ abort(); } + } #endif /* APR_HAS_THREADS */ #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */ } @@ -1462,9 +1520,19 @@ return NULL; } +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_lock( pool->mutex ); +#endif + node = pool->nodes; if (node == NULL || node->index == 64) { if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_unlock( pool->mutex ); +#endif + if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); @@ -1485,6 +1553,11 @@ pool->stat_alloc++; pool->stat_total_alloc++; +#if APR_HAS_THREADS + if ( pool->thread_safe && pool->mutex ) + apr_thread_mutex_unlock( pool->mutex ); +#endif + return mem; } @@ -1674,6 +1747,25 @@ pool_destroy_debug(pool, file_line); } +APR_DECLARE(apr_status_t) apr_pool_create_threadsafe_ex_debug( + apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line) +{ + apr_status_t status; + + status = apr_pool_create_ex_debug( + newpool,parent,abort_fn,allocator,file_line + ); + if ( APR_SUCCESS == status ) + (*newpool)->thread_safe = 1; + + return( status ); +} + + APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, @@ -1739,9 +1831,13 @@ pool->owner_proc = (apr_os_proc_t)getnlmhandle(); #endif /* defined(NETWARE) */ +#if APR_HAS_THREADS + /* Initialise thread_safe flag, this will be altered + * by creation function if a thread_safe pool is required. + */ + pool->thread_safe = 0; if (parent == NULL || parent->allocator != allocator) { -#if APR_HAS_THREADS apr_status_t rv; /* No matter what the creation flags say, always create @@ -1757,14 +1853,12 @@ free(pool); return rv; } -#endif /* APR_HAS_THREADS */ } else { -#if APR_HAS_THREADS if (parent) pool->mutex = parent->mutex; -#endif /* APR_HAS_THREADS */ } +#endif /* APR_HAS_THREADS */ *newpool = pool; @@ -1842,6 +1936,8 @@ free(pool); return rv; } + + pool->thread_safe = 0; #endif /* APR_HAS_THREADS */ } @@ -2620,6 +2716,22 @@ "undefined"); } +#undef apr_pool_create_threadsafe_ex +APR_DECLARE(apr_status_t) apr_pool_create_threadsafe_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator); + +APR_DECLARE(apr_status_t) apr_pool_create_threadsafe_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) +{ + return apr_pool_create_threadsafe_ex_debug(newpool, parent, + abort_fn, allocator, + "undefined"); +} + #undef apr_pool_create_core_ex APR_DECLARE(apr_status_t) apr_pool_create_core_ex(apr_pool_t **newpool, apr_abortfunc_t abort_fn,