summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Ylavic <ylavic@apache.org>2017-07-20 23:34:47 +0000
committerYann Ylavic <ylavic@apache.org>2017-07-20 23:34:47 +0000
commit7ea6d8b113bc4e3e02c982ce2ad77249beada007 (patch)
treed815af62b3e7520df64a495e07aae0d10c93def5
parent7157b8a35eb64a659ad6a44feec824af2155f05f (diff)
downloadhttpd-7ea6d8b113bc4e3e02c982ce2ad77249beada007.tar.gz
mpm_event: ap_queue_info_try_get_idler() may atomically decrement and then
re-increment the number idlers if it went under or to zero. We can avoid this by switching to a compare-and-swap scheme. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1802535 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--server/mpm/event/fdqueue.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/server/mpm/event/fdqueue.c b/server/mpm/event/fdqueue.c
index 7775a157d0..5b0192b2ee 100644
--- a/server/mpm/event/fdqueue.c
+++ b/server/mpm/event/fdqueue.c
@@ -27,18 +27,18 @@ struct recycled_pool
struct fd_queue_info_t
{
- apr_uint32_t idlers; /**
- * >= zero_pt: number of idle worker threads
- * < zero_pt: number of threads blocked waiting
- * for an idle worker
- */
+ apr_uint32_t volatile idlers; /**
+ * >= zero_pt: number of idle worker threads
+ * < zero_pt: number of threads blocked,
+ * waiting for an idle worker
+ */
apr_thread_mutex_t *idlers_mutex;
apr_thread_cond_t *wait_for_idler;
int terminated;
int max_idlers;
int max_recycled_pools;
apr_uint32_t recycled_pools_count;
- struct recycled_pool *recycled_pools;
+ struct recycled_pool *volatile recycled_pools;
};
static apr_status_t queue_info_cleanup(void *data_)
@@ -123,17 +123,17 @@ apr_status_t ap_queue_info_set_idle(fd_queue_info_t * queue_info,
apr_status_t ap_queue_info_try_get_idler(fd_queue_info_t * queue_info)
{
- /* Don't block if there isn't any idle worker.
- * apr_atomic_add32(x, -1) does the same as dec32(x), except
- * that it returns the previous value (unlike dec32's bool).
- *
- * XXX: why don't we consume the last idler?
- */
- if (apr_atomic_add32(&(queue_info->idlers), -1) <= zero_pt + 1) {
- apr_atomic_inc32(&(queue_info->idlers)); /* back out dec */
- return APR_EAGAIN;
+ /* Don't block if there isn't any idle worker. */
+ for (;;) {
+ apr_uint32_t idlers = queue_info->idlers;
+ if (idlers <= zero_pt) {
+ return APR_EAGAIN;
+ }
+ if (apr_atomic_cas32(&queue_info->idlers, idlers - 1,
+ idlers) == idlers) {
+ return APR_SUCCESS;
+ }
}
- return APR_SUCCESS;
}
apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t * queue_info,