diff options
Diffstat (limited to 'server/mpm/worker')
| -rw-r--r-- | server/mpm/worker/fdqueue.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/server/mpm/worker/fdqueue.c b/server/mpm/worker/fdqueue.c index 8be7c9fa..d46dd536 100644 --- a/server/mpm/worker/fdqueue.c +++ b/server/mpm/worker/fdqueue.c @@ -94,10 +94,14 @@ apr_status_t ap_queue_info_set_idle(fd_queue_info_t *queue_info, sizeof(*new_recycle)); new_recycle->pool = pool_to_recycle; for (;;) { - new_recycle->next = queue_info->recycled_pools; + /* Save queue_info->recycled_pool in local variable next because + * new_recycle->next can be changed after apr_atomic_casptr + * function call. For gory details see PR 44402. + */ + struct recycled_pool *next = queue_info->recycled_pools; + new_recycle->next = next; if (apr_atomic_casptr((volatile void**)&(queue_info->recycled_pools), - new_recycle, new_recycle->next) == - new_recycle->next) { + new_recycle, next) == next) { break; } } @@ -184,6 +188,14 @@ apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t *queue_info, apr_atomic_dec32(&(queue_info->idlers)); /* Atomically pop a pool from the recycled list */ + + /* This function is safe only as long as it is single threaded because + * it reaches into the queue and accesses "next" which can change. + * We are OK today because it is only called from the listener thread. + * cas-based pushes do not have the same limitation - any number can + * happen concurrently with a single cas-based pop. + */ + for (;;) { struct recycled_pool *first_pool = queue_info->recycled_pools; if (first_pool == NULL) { |
