summaryrefslogtreecommitdiff
path: root/server/mpm/worker
diff options
context:
space:
mode:
Diffstat (limited to 'server/mpm/worker')
-rw-r--r--server/mpm/worker/fdqueue.c18
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) {