From 0058763aa189e216b15d86b44cb376f06698cb45 Mon Sep 17 00:00:00 2001 From: Jean-Frederic Clere Date: Wed, 6 Mar 2024 11:03:24 +0100 Subject: [PATCH] A little mor for https://github.com/apache/httpd/pull/396 Change ERROR into DAVERROR, because Windows has ERROR in assert.h... --- CMakeLists.txt | 1 + NWGNUmakefile | 1 + build/nw_export.inc | 1 + include/ap_atomics.h | 122 +++ include/ap_config.h | 18 + include/httpd.h | 55 ++ libhttpd.dsp | 8 + modules/dav/main/ms_wdv.c | 6 +- .../proxy/balancers/mod_lbmethod_bybusyness.c | 48 +- .../proxy/balancers/mod_lbmethod_byrequests.c | 31 +- .../proxy/balancers/mod_lbmethod_bytraffic.c | 15 +- modules/proxy/mod_proxy_balancer.c | 35 +- modules/proxy/proxy_util.c | 123 +-- modules/proxy/proxy_util.h | 35 - server/Makefile.in | 2 +- server/util_atomics.c | 802 ++++++++++++++++++ 16 files changed, 1095 insertions(+), 208 deletions(-) create mode 100644 include/ap_atomics.h create mode 100644 server/util_atomics.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c10b8f07ab..86d9e5c4a80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -734,6 +734,7 @@ SET(LIBHTTPD_SOURCES server/ssl.c server/scoreboard.c server/util.c + server/util_atomics.c server/util_cfgtree.c server/util_cookies.c server/util_debug.c diff --git a/NWGNUmakefile b/NWGNUmakefile index 3cea4068000..771bf5953c6 100644 --- a/NWGNUmakefile +++ b/NWGNUmakefile @@ -268,6 +268,7 @@ FILES_nlm_objs = \ $(OBJDIR)/request.o \ $(OBJDIR)/scoreboard.o \ $(OBJDIR)/util.o \ + $(OBJDIR)/util_atomics.o \ $(OBJDIR)/util_cfgtree.o \ $(OBJDIR)/util_charset.o \ $(OBJDIR)/util_cookies.o \ diff --git a/build/nw_export.inc b/build/nw_export.inc index af8d8fe80a2..e5afdfa63d7 100644 --- a/build/nw_export.inc +++ b/build/nw_export.inc @@ -34,6 +34,7 @@ #include "httpd.h" /* Preprocess all of the standard HTTPD headers. */ +#include "ap_atomics.h" #include "ap_compat.h" #include "ap_listen.h" #include "ap_mmn.h" diff --git a/include/ap_atomics.h b/include/ap_atomics.h new file mode 100644 index 00000000000..66db6234792 --- /dev/null +++ b/include/ap_atomics.h @@ -0,0 +1,122 @@ +#include "ap_config.h" + +#include "apr.h" + + +/* Atomics for int (uses int32_t's on all platforms we care about) */ + +AP_DECLARE(int) ap_atomic_int_get(int volatile *val); + +AP_DECLARE(void) ap_atomic_int_set(int volatile *val, int to); + +AP_DECLARE(int) ap_atomic_int_xchg(int volatile *val, int with); + +AP_DECLARE(int) ap_atomic_int_cas(int volatile *val, int with, int cmp); + +AP_DECLARE(int) ap_atomic_int_add(int volatile *val, int add); + +AP_DECLARE(int) ap_atomic_int_add_sat(int volatile *val, int add); + +AP_DECLARE(int) ap_atomic_int_sub(int volatile *val, int sub); + +AP_DECLARE(int) ap_atomic_int_sub_sat(int volatile *val, int sub); + + +/* Atomics for unsigned int (uses uint32_t's on all platforms we care about) */ + +AP_DECLARE(unsigned int) ap_atomic_uint_get(unsigned int volatile *val); + +AP_DECLARE(void) ap_atomic_uint_set(unsigned int volatile *val, + unsigned int to); + +AP_DECLARE(unsigned int) ap_atomic_uint_xchg(unsigned int volatile *val, + unsigned int with); + +AP_DECLARE(unsigned int) ap_atomic_uint_cas(unsigned int volatile *val, + unsigned int with, + unsigned int cmp); + +AP_DECLARE(unsigned int) ap_atomic_uint_add(unsigned int volatile *val, + unsigned int add); + +AP_DECLARE(unsigned int) ap_atomic_uint_add_sat(unsigned int volatile *val, + unsigned int add); + +AP_DECLARE(unsigned int) ap_atomic_uint_sub(unsigned int volatile *val, + unsigned int sub); + +AP_DECLARE(unsigned int) ap_atomic_uint_sub_sat(unsigned int volatile *val, + unsigned int sub); + + +/* Atomics for long (uses int32_t's or int64_t's depending on LONG_MAX) */ + +AP_DECLARE(long) ap_atomic_long_get(long volatile *val); + +AP_DECLARE(void) ap_atomic_long_set(long volatile *val, long to); + +AP_DECLARE(long) ap_atomic_long_xchg(long volatile *val, long with); + +AP_DECLARE(long) ap_atomic_long_cas(long volatile *val, long with, long cmp); + +AP_DECLARE(long) ap_atomic_long_add(long volatile *val, long add); + +AP_DECLARE(long) ap_atomic_long_add_sat(long volatile *val, long add); + +AP_DECLARE(long) ap_atomic_long_sub(long volatile *val, long sub); + +AP_DECLARE(long) ap_atomic_long_sub_sat(long volatile *val, long sub); + + +/* Atomics for unsigned long (uses uint32_t's or uint64_t's depending on ULONG_MAX) */ + +AP_DECLARE(unsigned long) ap_atomic_ulong_get(unsigned long volatile *val); + +AP_DECLARE(void) ap_atomic_ulong_set(unsigned long volatile *val, + unsigned long to); + +AP_DECLARE(unsigned long) ap_atomic_ulong_xchg(unsigned long volatile *val, + unsigned long with); + +AP_DECLARE(unsigned long) ap_atomic_ulong_cas(unsigned long volatile *val, + unsigned long with, + unsigned long cmp); + +AP_DECLARE(unsigned long) ap_atomic_ulong_add(unsigned long volatile *val, + unsigned long add); + +AP_DECLARE(unsigned long) ap_atomic_ulong_add_sat(unsigned long volatile *val, + unsigned long add); + +AP_DECLARE(unsigned long) ap_atomic_ulong_sub(unsigned long volatile *val, + unsigned long sub); + +AP_DECLARE(unsigned long) ap_atomic_ulong_sub_sat(unsigned long volatile *val, + unsigned long sub); + + +/* Atomics for size_t (uses uint32_t's or uint64_t's depending on sizeof(void*)) */ + +AP_DECLARE(apr_size_t) ap_atomic_size_get(apr_size_t volatile *val); + +AP_DECLARE(void) ap_atomic_size_set(apr_size_t volatile *val, + apr_size_t to); + +AP_DECLARE(apr_size_t) ap_atomic_size_xchg(apr_size_t volatile *val, + apr_size_t with); + +AP_DECLARE(apr_size_t) ap_atomic_size_cas(apr_size_t volatile *val, + apr_size_t with, + apr_size_t cmp); + +AP_DECLARE(apr_size_t) ap_atomic_size_add(apr_size_t volatile *val, + apr_size_t add); + +AP_DECLARE(apr_size_t) ap_atomic_size_add_sat(apr_size_t volatile *val, + apr_size_t add); + +AP_DECLARE(apr_size_t) ap_atomic_size_sub(apr_size_t volatile *val, + apr_size_t sub); + +AP_DECLARE(apr_size_t) ap_atomic_size_sub_sat(apr_size_t volatile *val, + apr_size_t sub); diff --git a/include/ap_config.h b/include/ap_config.h index 41f0caf174b..588334b4c9e 100644 --- a/include/ap_config.h +++ b/include/ap_config.h @@ -222,9 +222,19 @@ #define AP_HAVE_DESIGNATED_INITIALIZER #endif +#ifndef __has_builtin /* check for supported builtin on clang */ +#define __has_builtin(x) 0 +#endif +#ifndef __has_feature /* check for supported feature on clang */ +#define __has_feature(x) 0 +#endif +#ifndef __has_extension /* check for supported extension on clang */ +#define __has_extension __has_feature +#endif #ifndef __has_attribute /* check for supported attributes on clang */ #define __has_attribute(x) 0 #endif + #if (defined(__GNUC__) && __GNUC__ >= 4) || __has_attribute(sentinel) #define AP_FN_ATTR_SENTINEL __attribute__((sentinel)) #else @@ -261,5 +271,13 @@ #define AP_FN_ATTR_NONNULL(x) #endif +/** Try harder to inline */ +#if __has_attribute(always_inline) +#define AP_FORCE_INLINE APR_INLINE __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define AP_FORCE_INLINE APR_INLINE __forceinline +#else +#define AP_FORCE_INLINE APR_INLINE +#endif #endif /* AP_CONFIG_H */ diff --git a/include/httpd.h b/include/httpd.h index ccbe417328a..602bd037a38 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -65,6 +65,9 @@ #if APR_HAVE_STDLIB_H #include #endif +#if defined(__STDC__) || defined(_MSC_VER) /* C89 */ +#include /* for static_assert */ +#endif /* Note: apr_uri.h is also included, see below */ @@ -2423,6 +2426,58 @@ AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile, int nLine) #define AP_DEBUG_ASSERT(exp) ((void)0) #endif +/** + * Compile time assertion with custom error message. + * @param exp static expression/condition + * @param msg error message (string literal) + */ +#if (defined(static_assert) \ + || (defined(__cplusplus) && __cplusplus >= 201103L) \ + || (defined(__has_feature) && __has_feature(cxx_static_assert)) \ + || (defined(_MSC_VER ) && _MSC_VER >= 1600)) + +#define AP_STATIC_ASSERT(exp, msg) static_assert(exp, msg) + +#elif (defined(_Static_assert) \ + || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \ + || (defined(__has_feature) && __has_feature(c_static_assert)) \ + || (defined(__GNUC__) && __GNUC_PREREQ (4, 6))) + +#define AP_STATIC_ASSERT(exp, msg) _Static_assert(exp, msg) + +#else /* Fail compilation using bit-field with negative width */ + +#ifdef __COUNTER__ + +#define AP_STATIC_ASSERT(exp, msg) \ + typedef __attribute__((unused)) struct { \ + int static_assertion_failed: !!(exp) * 2 - 1; \ + } AP_CONCATIFY(ap__static_assert_t_, __COUNTER__) + +#else /* __COUNTER__ */ + +#define AP_STATIC_ASSERT(exp, msg) \ + typedef __attribute__((unused)) struct { \ + int static_assertion_failed: !!(exp) * 2 - 1; \ + } AP_CONCATIFY(ap__static_assert_t_, __LINE__) + +#endif /* __COUNTER__ */ + +#endif /* AP_STATIC_ASSERT */ + +/** + * Compile time assertion with the expression as error message. + * @param exp static expression/condition + */ +#define AP_BUILD_ASSERT(exp) \ + AP_STATIC_ASSERT(exp, "static assertion failed at " \ + __FILE__ ":" APR_STRINGIFY(__LINE__) ": " \ + APR_STRINGIFY(exp)) + +/** Properly concatenate two values in the C preprocessor */ +#define AP_CONCATIFY(x, y) AP__CONCATIFY(x, y) +#define AP__CONCATIFY(x, y) x ## y + /** * @defgroup stopsignal Flags which indicate places where the server should stop for debugging. * @{ diff --git a/libhttpd.dsp b/libhttpd.dsp index 6467f8b8401..b81659841f5 100644 --- a/libhttpd.dsp +++ b/libhttpd.dsp @@ -533,6 +533,14 @@ SOURCE=.\server\util.c # End Source File # Begin Source File +SOURCE=.\server\util_atomics.c +# End Source File +# Begin Source File + +SOURCE=.\include\ap_atomics.h +# End Source File +# Begin Source File + SOURCE=.\server\util_cfgtree.c # End Source File # Begin Source File diff --git a/modules/dav/main/ms_wdv.c b/modules/dav/main/ms_wdv.c index 33787f977ae..1f3e56d5e44 100644 --- a/modules/dav/main/ms_wdv.c +++ b/modules/dav/main/ms_wdv.c @@ -182,7 +182,7 @@ static dav_error *mswdv_combined_lock(request_rec *r) /* action */ const char *failmsg = NULL; int http_error = HTTP_BAD_REQUEST; - enum { ERROR, LOCK, UNLOCK, REFRESH, PASS } action = ERROR; + enum { DAVERROR, LOCK, UNLOCK, REFRESH, PASS } action = DAVERROR; lock_token_hdr = apr_table_get(r->headers_in, "Lock-Token"); lock_timeout_hdr = apr_table_get(r->headers_in, "X-MSDAVEXTLockTimeout"); @@ -413,7 +413,7 @@ static dav_error *mswdv_combined_lock(request_rec *r) action == LOCK ? "LOCK" : "", action == UNLOCK ? "UNLOCK" : "", action == REFRESH ? "REFRESH" : "", - action == ERROR ? "ERROR" : "", + action == DAVERROR ? "ERROR" : "", action == PASS ? "PASS" : ""); if (failmsg) { @@ -471,7 +471,7 @@ static dav_error *mswdv_combined_lock(request_rec *r) break; } - case ERROR: /* FALLTHROUGH */ + case DAVERROR: /* FALLTHROUGH */ default: /* NOTREACHED */ err = dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0, diff --git a/modules/proxy/balancers/mod_lbmethod_bybusyness.c b/modules/proxy/balancers/mod_lbmethod_bybusyness.c index c2efa2f9a9d..edd6a8d27f0 100644 --- a/modules/proxy/balancers/mod_lbmethod_bybusyness.c +++ b/modules/proxy/balancers/mod_lbmethod_bybusyness.c @@ -19,6 +19,7 @@ #include "scoreboard.h" #include "ap_mpm.h" #include "apr_version.h" +#include "ap_atomics.h" #include "ap_hooks.h" module AP_MODULE_DECLARE_DATA lbmethod_bybusyness_module; @@ -30,23 +31,30 @@ static APR_OPTIONAL_FN_TYPE(proxy_balancer_get_best_worker) static int is_best_bybusyness(proxy_worker *current, proxy_worker *prev_best, void *baton) { int *total_factor = (int *)baton; - apr_size_t current_busy = ap_proxy_get_busy_count(current); - apr_size_t prev_best_busy = 0; - - current->s->lbstatus += current->s->lbfactor; - *total_factor += current->s->lbfactor; - if (prev_best) - prev_best_busy = ap_proxy_get_busy_count(prev_best); - - - return ( - !prev_best - || (current_busy < prev_best_busy) - || ( - (current_busy == prev_best_busy) - && (current->s->lbstatus > prev_best->s->lbstatus) - ) - ); + int lbfactor = current->s->lbfactor, lbstatus; + + *total_factor += lbfactor; + lbstatus = ap_atomic_int_add_sat(¤t->s->lbstatus, lbfactor); + if (prev_best) { + apr_size_t current_busy = ap_atomic_size_get(¤t->s->busy); + apr_size_t prev_busy = ap_atomic_size_get(&prev_best->s->busy); + if (current_busy > prev_busy) { + return 0; + } + if (current_busy == prev_busy) { + /* lbstatus is the value before atomic add */ + if (lbstatus < APR_INT32_MAX - lbfactor) { + lbstatus += lbfactor; + } + else { + lbstatus = APR_INT32_MAX; + } + if (lbstatus <= ap_atomic_int_get(&prev_best->s->lbstatus)) { + return 0; + } + } + } + return 1; } static proxy_worker *find_best_bybusyness(proxy_balancer *balancer, @@ -58,7 +66,7 @@ static proxy_worker *find_best_bybusyness(proxy_balancer *balancer, &total_factor); if (worker) { - worker->s->lbstatus -= total_factor; + ap_atomic_int_sub_sat(&worker->s->lbstatus, total_factor); } return worker; @@ -71,8 +79,8 @@ static apr_status_t reset(proxy_balancer *balancer, server_rec *s) proxy_worker **worker; worker = (proxy_worker **)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++, worker++) { - (*worker)->s->lbstatus = 0; - ap_proxy_set_busy_count(*worker, 0); + ap_atomic_int_set(&(*worker)->s->lbstatus, 0); + ap_atomic_size_set(&(*worker)->s->busy, 0); } return APR_SUCCESS; } diff --git a/modules/proxy/balancers/mod_lbmethod_byrequests.c b/modules/proxy/balancers/mod_lbmethod_byrequests.c index b6cd8d8b8bd..cd3bf1bc0ef 100644 --- a/modules/proxy/balancers/mod_lbmethod_byrequests.c +++ b/modules/proxy/balancers/mod_lbmethod_byrequests.c @@ -18,6 +18,7 @@ #include "scoreboard.h" #include "ap_mpm.h" #include "apr_version.h" +#include "ap_atomics.h" #include "ap_hooks.h" module AP_MODULE_DECLARE_DATA lbmethod_byrequests_module; @@ -28,11 +29,23 @@ static APR_OPTIONAL_FN_TYPE(proxy_balancer_get_best_worker) static int is_best_byrequests(proxy_worker *current, proxy_worker *prev_best, void *baton) { int *total_factor = (int *)baton; - - current->s->lbstatus += current->s->lbfactor; - *total_factor += current->s->lbfactor; - - return (!prev_best || (current->s->lbstatus > prev_best->s->lbstatus)); + int lbfactor = current->s->lbfactor, lbstatus; + + *total_factor += lbfactor; + lbstatus = ap_atomic_int_add_sat(¤t->s->lbstatus, lbfactor); + if (prev_best) { + /* lbstatus is the value before atomic add */ + if (lbstatus < APR_INT32_MAX - lbfactor) { + lbstatus += lbfactor; + } + else { + lbstatus = APR_INT32_MAX; + } + if (lbstatus <= ap_atomic_int_get(&prev_best->s->lbstatus)) { + return 0; + } + } + return 1; } /* @@ -84,10 +97,12 @@ static proxy_worker *find_best_byrequests(proxy_balancer *balancer, request_rec *r) { int total_factor = 0; - proxy_worker *worker = ap_proxy_balancer_get_best_worker_fn(balancer, r, is_best_byrequests, &total_factor); + proxy_worker *worker = ap_proxy_balancer_get_best_worker_fn(balancer, r, + is_best_byrequests, + &total_factor); if (worker) { - worker->s->lbstatus -= total_factor; + ap_atomic_int_sub_sat(&worker->s->lbstatus, total_factor); } return worker; @@ -100,7 +115,7 @@ static apr_status_t reset(proxy_balancer *balancer, server_rec *s) proxy_worker **worker; worker = (proxy_worker **)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++, worker++) { - (*worker)->s->lbstatus = 0; + ap_atomic_int_set(&(*worker)->s->lbstatus, 0); } return APR_SUCCESS; } diff --git a/modules/proxy/balancers/mod_lbmethod_bytraffic.c b/modules/proxy/balancers/mod_lbmethod_bytraffic.c index 724b028260d..542997fbdd7 100644 --- a/modules/proxy/balancers/mod_lbmethod_bytraffic.c +++ b/modules/proxy/balancers/mod_lbmethod_bytraffic.c @@ -18,6 +18,7 @@ #include "scoreboard.h" #include "ap_mpm.h" #include "apr_version.h" +#include "ap_atomics.h" #include "ap_hooks.h" module AP_MODULE_DECLARE_DATA lbmethod_bytraffic_module; @@ -28,16 +29,14 @@ static APR_OPTIONAL_FN_TYPE(proxy_balancer_get_best_worker) static int is_best_bytraffic(proxy_worker *current, proxy_worker *prev_best, void *baton) { apr_off_t *min_traffic = (apr_off_t *)baton; - apr_off_t traffic = (current->s->transferred / current->s->lbfactor) - + (current->s->read / current->s->lbfactor); + apr_off_t traffic = (current->s->transferred / current->s->lbfactor + + current->s->read / current->s->lbfactor); - if (!prev_best || (traffic < *min_traffic)) { - *min_traffic = traffic; - - return TRUE; + if (prev_best && traffic >= *min_traffic) { + return 0; } - - return FALSE; + *min_traffic = traffic; + return 1; } /* diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index ea1b034d00e..e61fe1721ad 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -21,6 +21,7 @@ #include "scoreboard.h" #include "ap_mpm.h" #include "apr_version.h" +#include "ap_atomics.h" #include "ap_hooks.h" #include "apr_date.h" #include "apr_escape.h" @@ -485,6 +486,13 @@ static void force_recovery(proxy_balancer *balancer, server_rec *s) } } +static apr_status_t proxy_worker_decrement_busy(void *arg) +{ + proxy_worker *worker = arg; + ap_atomic_size_sub_sat(&worker->s->busy, 1); + return APR_SUCCESS; +} + static int proxy_balancer_pre_request(proxy_worker **worker, proxy_balancer **balancer, request_rec *r, @@ -545,12 +553,12 @@ static int proxy_balancer_pre_request(proxy_worker **worker, * not in error state or not disabled. */ if (PROXY_WORKER_IS_USABLE(*workers)) { - (*workers)->s->lbstatus += (*workers)->s->lbfactor; + ap_atomic_int_add_sat(&(*workers)->s->lbstatus, (*workers)->s->lbfactor); total_factor += (*workers)->s->lbfactor; } workers++; } - runtime->s->lbstatus -= total_factor; + ap_atomic_int_sub_sat(&runtime->s->lbstatus, total_factor); } runtime->s->elected++; @@ -623,8 +631,8 @@ static int proxy_balancer_pre_request(proxy_worker **worker, *worker = runtime; } - ap_proxy_increment_busy_count(*worker); - apr_pool_cleanup_register(r->pool, *worker, ap_proxy_decrement_busy_count, + ap_atomic_size_add_sat(&(*worker)->s->busy, 1); + apr_pool_cleanup_register(r->pool, *worker, proxy_worker_decrement_busy, apr_pool_cleanup_null); /* Add balancer/worker info to env. */ @@ -726,16 +734,15 @@ static void recalc_factors(proxy_balancer *balancer) /* Recalculate lbfactors */ workers = (proxy_worker **)balancer->workers->elts; - /* Special case if there is only one worker its - * load factor will always be 100 - */ if (balancer->workers->nelts == 1) { - (*workers)->s->lbstatus = (*workers)->s->lbfactor = 100; - return; + /* Special case if there is only one worker its + * load factor will always be 100 + */ + workers[0]->s->lbfactor = 100; } for (i = 0; i < balancer->workers->nelts; i++) { /* Update the status entries */ - workers[i]->s->lbstatus = workers[i]->s->lbfactor; + ap_atomic_int_set(&workers[i]->s->lbstatus, workers[i]->s->lbfactor); } } @@ -1542,7 +1549,7 @@ static void balancer_display_page(request_rec *r, proxy_server_conf *conf, worker->s->retries); ap_rprintf(r, " %d\n", - worker->s->lbstatus); + ap_atomic_int_get(&worker->s->lbstatus)); ap_rprintf(r, " %.2f\n", (float)(worker->s->lbfactor)/100.0); @@ -1563,7 +1570,7 @@ static void balancer_display_page(request_rec *r, proxy_server_conf *conf, "\n", NULL); ap_rprintf(r, " %" APR_SIZE_T_FMT "\n", - ap_proxy_get_busy_count(worker)); + ap_atomic_size_get(&worker->s->busy)); ap_rprintf(r, " %d\n", worker->s->lbset); /* End proxy_worker_stat */ @@ -1736,8 +1743,8 @@ static void balancer_display_page(request_rec *r, proxy_server_conf *conf, ap_rvputs(r, ap_proxy_parse_wstatus(r->pool, worker), NULL); ap_rputs("", r); ap_rprintf(r, "%" APR_SIZE_T_FMT "", worker->s->elected); - ap_rprintf(r, "%" APR_SIZE_T_FMT "", ap_proxy_get_busy_count(worker)); - ap_rprintf(r, "%d", worker->s->lbstatus); + ap_rprintf(r, "%" APR_SIZE_T_FMT "", ap_atomic_size_get(&worker->s->busy)); + ap_rprintf(r, "%d", ap_atomic_int_get(&worker->s->lbstatus)); ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r); ap_rputs("", r); ap_rputs(apr_strfsize(worker->s->read, fbuf), r); diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 38ba647791d..cd37580f223 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -22,6 +22,7 @@ #include "apr_strings.h" #include "apr_hash.h" #include "apr_atomic.h" +#include "ap_atomics.h" #include "http_core.h" #include "proxy_util.h" #include "ajp.h" @@ -1486,7 +1487,9 @@ static proxy_worker *proxy_balancer_get_best_worker(proxy_balancer *balancer, if (best_worker) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(10123) "proxy: %s selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d", - balancer->lbmethod->name, best_worker->s->name, best_worker->s->busy, best_worker->s->lbstatus); + balancer->lbmethod->name, best_worker->s->name, + ap_atomic_size_get(&best_worker->s->busy), + ap_atomic_int_get(&best_worker->s->lbstatus)); } return best_worker; @@ -5390,124 +5393,6 @@ PROXY_DECLARE(apr_status_t) ap_proxy_tunnel_create(proxy_tunnel_rec **ptunnel, return APR_SUCCESS; } -PROXY_DECLARE(apr_status_t) ap_proxy_decrement_busy_count(void *worker_) -{ - apr_size_t val; - proxy_worker *worker = worker_; - -#if APR_SIZEOF_VOIDP == 4 - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint32_t)); - val = apr_atomic_read32(&worker->s->busy); - while (val > 0) { - apr_size_t old = val; - val = apr_atomic_cas32(&worker->s->busy, val - 1, old); - if (val == old) { - break; - } - } -#elif APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint64_t)); - val = apr_atomic_read64(&worker->s->busy); - while (val > 0) { - apr_size_t old = val; - val = apr_atomic_cas64(&worker->s->busy, val - 1, old); - if (val == old) { - break; - } - } -#else /* Use atomics for (64bit) pointers */ - void *volatile *busy_p = (void *)&worker->s->busy; - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(void*)); - AP_DEBUG_ASSERT((apr_uintptr_t)busy_p % sizeof(void*) == 0); - val = (apr_uintptr_t)apr_atomic_casptr((void *)busy_p, NULL, NULL); - while (val > 0) { - apr_size_t old = val; - val = (apr_uintptr_t)apr_atomic_casptr((void *)busy_p, - (void *)(apr_uintptr_t)(val - 1), - (void *)(apr_uintptr_t)old); - if (val == old) { - break; - } - } -#endif - return APR_SUCCESS; -} - -PROXY_DECLARE(void) ap_proxy_increment_busy_count(proxy_worker *worker) -{ - apr_size_t val; -#if APR_SIZEOF_VOIDP == 4 - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint32_t)); - val = apr_atomic_read32(&worker->s->busy); - while (val < APR_INT32_MAX) { - apr_size_t old = val; - val = apr_atomic_cas32(&worker->s->busy, val + 1, old); - if (val == old) { - break; - } - } -#elif APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint64_t)); - val = apr_atomic_read64(&worker->s->busy); - while (val < APR_INT64_MAX) { - apr_size_t old = val; - val = apr_atomic_cas64(&worker->s->busy, val + 1, old); - if (val == old) { - break; - } - } -#else /* Use atomics for (64bit) pointers */ - void *volatile *busy_p = (void *)&worker->s->busy; - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(void*)); - AP_DEBUG_ASSERT((apr_uintptr_t)busy_p % sizeof(void*) == 0); - val = (apr_uintptr_t)apr_atomic_casptr((void *)busy_p, NULL, NULL); - while (val < APR_INT64_MAX) { - apr_size_t old = val; - val = (apr_uintptr_t)apr_atomic_casptr((void *)busy_p, - (void *)(apr_uintptr_t)(val + 1), - (void *)(apr_uintptr_t)old); - if (val == old) { - break; - } - } -#endif -} - -PROXY_DECLARE(apr_size_t) ap_proxy_get_busy_count(proxy_worker *worker) -{ - apr_size_t val; -#if APR_SIZEOF_VOIDP == 4 - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint32_t)); - val = apr_atomic_read32(&worker->s->busy); -#elif APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint64_t)); - val = apr_atomic_read64(&worker->s->busy); -#else /* Use atomics for (64bit) pointers */ - void *volatile *busy_p = (void *)&worker->s->busy; - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(void*)); - AP_DEBUG_ASSERT((apr_uintptr_t)busy_p % sizeof(void*) == 0); - val = (apr_uintptr_t)apr_atomic_casptr((void *)busy_p, NULL, NULL); -#endif - - return val; -} - -PROXY_DECLARE(void) ap_proxy_set_busy_count(proxy_worker *worker, apr_size_t to) -{ -#if APR_SIZEOF_VOIDP == 4 - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint32_t)); - apr_atomic_set32(&worker->s->busy, to); -#elif APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint64_t)); - apr_atomic_set64(&worker->s->busy, to); -#else /* Use atomics for (64bit) pointers */ - void *volatile *busy_p = (void *)&worker->s->busy; - AP_DEBUG_ASSERT(sizeof(apr_size_t) == sizeof(void*)); - AP_DEBUG_ASSERT((apr_uintptr_t)busy_p % sizeof(void*) == 0); - apr_atomic_xchgptr((void *)busy_p, (void *)(apr_uintptr_t)to); -#endif -} - static void add_pollset(apr_pollset_t *pollset, apr_pollfd_t *pfd, apr_int16_t events) { diff --git a/modules/proxy/proxy_util.h b/modules/proxy/proxy_util.h index 42d0f89811a..bc131da0f0f 100644 --- a/modules/proxy/proxy_util.h +++ b/modules/proxy/proxy_util.h @@ -40,41 +40,6 @@ extern PROXY_DECLARE_DATA const apr_strmatch_pattern *ap_proxy_strmatch_domain; */ void proxy_util_register_hooks(apr_pool_t *p); -/* - * Get the busy counter from the shared worker memory - * - * @param worker Pointer to the worker structure. - * @return apr_size_t value atomically read for the worker. - */ -PROXY_DECLARE(apr_size_t) ap_proxy_get_busy_count(proxy_worker *worker); - -/* - * Set the busy counter from the shared worker memory - * - * @param worker Pointer to the worker structure. - * @param to value to set the busy counter. - * @return void - */ -PROXY_DECLARE(void) ap_proxy_set_busy_count(proxy_worker *worker, apr_size_t to); - -/* - * decrement the busy counter from the shared worker memory - * note it is called by apr_pool_cleanup_register() - * therfore the void * and apr_status_t. - * - * @param worker_ Pointer to the worker structure. - * @return apr_status_t returns APR_SUCCESS. - */ -PROXY_DECLARE(apr_status_t) ap_proxy_decrement_busy_count(void *worker_); - -/* - * increment the busy counter from the shared worker memory - * - * @param worker Pointer to the worker structure. - * @return void - */ -PROXY_DECLARE(void) ap_proxy_increment_busy_count(proxy_worker *worker); - /** @} */ #endif /* PROXY_UTIL_H_ */ diff --git a/server/Makefile.in b/server/Makefile.in index 3b25ebcafda..e7c187436f4 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -9,7 +9,7 @@ LTLIBRARY_NAME = libmain.la LTLIBRARY_SOURCES = \ config.c log.c main.c vhost.c util.c util_etag.c util_fcgi.c \ util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \ - connection.c listen.c util_mutex.c \ + connection.c listen.c util_mutex.c util_atomics.c \ mpm_common.c mpm_unix.c mpm_fdqueue.c \ util_charset.c util_cookies.c util_debug.c util_xml.c \ util_filter.c util_pcre.c util_regex.c $(EXPORTS_DOT_C) \ diff --git a/server/util_atomics.c b/server/util_atomics.c new file mode 100644 index 00000000000..bca518c86d0 --- /dev/null +++ b/server/util_atomics.c @@ -0,0 +1,802 @@ +#include "ap_atomics.h" +#include "httpd.h" + +#include "apr.h" +#include "apr_atomic.h" + + +/* Platform checks */ +#if APR_HAVE_LIMITS_H +#include /* for INT/LONG_MAX */ +#else +#error " required" +#endif +#if INT_MAX == APR_INT32_MAX && UINT_MAX == APR_UINT32_MAX +AP_BUILD_ASSERT(sizeof(int) == sizeof(apr_int32_t)); +AP_BUILD_ASSERT(sizeof(unsigned int) == sizeof(apr_uint32_t)); +#else +#error "[U]INT_MAX not supported" +#endif +#if LONG_MAX == APR_INT32_MAX && ULONG_MAX == APR_UINT32_MAX +AP_BUILD_ASSERT(sizeof(long) == sizeof(apr_int32_t)); +AP_BUILD_ASSERT(sizeof(unsigned long) == sizeof(apr_uint32_t)); +#elif LONG_MAX == APR_INT64_MAX && ULONG_MAX == APR_UINT64_MAX +AP_BUILD_ASSERT(sizeof(long) == sizeof(apr_int64_t)); +AP_BUILD_ASSERT(sizeof(unsigned long) == sizeof(apr_uint64_t)); +#else +#error "[U]LONG_MAX not supported" +#endif +#if APR_SIZEOF_VOIDP == 4 +AP_BUILD_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint32_t)); +#elif APR_SIZEOF_VOIDP == 8 +AP_BUILD_ASSERT(sizeof(apr_size_t) == sizeof(apr_uint64_t)); +#else +#error "sizeof(void*) not supported" +#endif +#if (~0 != -1) +#error "2's complement integer representation required" +#endif + + +/* Atomics for pointers (use APR's) */ + +static AP_FORCE_INLINE +void *atomic_ptr_xchg(void *volatile *ptr, void *with) +{ + return apr_atomic_xchgptr((void *)ptr, with); +} + +static AP_FORCE_INLINE +void *atomic_ptr_cas(void *volatile *ptr, void *with, const void *cmp) +{ + return apr_atomic_casptr((void *)ptr, with, cmp); +} + +#if 0 /* not used for now */ +static AP_FORCE_INLINE +void *atomic_ptr_get(void *volatile *ptr) +{ + return atomic_ptr_cas(ptr, NULL, NULL); +} + +static AP_FORCE_INLINE +void atomic_ptr_set(void *volatile *ptr, void *to) +{ + (void)atomic_ptr_xchg(ptr, to); +} +#endif + + +/* Atomics for uint32_t (use APR's) */ + +static AP_FORCE_INLINE +apr_uint32_t atomic_uint32_get(apr_uint32_t volatile *val) +{ + return apr_atomic_read32(val); +} + +static AP_FORCE_INLINE +void atomic_uint32_set(apr_uint32_t volatile *val, + apr_uint32_t to) +{ + apr_atomic_set32(val, to); +} + +static AP_FORCE_INLINE +apr_uint32_t atomic_uint32_xchg(apr_uint32_t volatile *val, + apr_uint32_t with) +{ + return apr_atomic_xchg32(val, with); +} + +static AP_FORCE_INLINE +apr_uint32_t atomic_uint32_cas(apr_uint32_t volatile *val, + apr_uint32_t with, apr_uint32_t cmp) +{ + return apr_atomic_cas32(val, with, cmp); +} + +static AP_FORCE_INLINE +apr_uint32_t atomic_uint32_add(apr_uint32_t volatile *val, + apr_uint32_t add) +{ + return apr_atomic_add32(val, add); +} + +static AP_FORCE_INLINE +apr_uint32_t atomic_uint32_add_sat(apr_uint32_t volatile *val, + apr_uint32_t add) +{ + apr_uint32_t old, cmp = APR_UINT32_MAX; + old = atomic_uint32_get(val); + while (old != cmp) { + cmp = old; + old = atomic_uint32_cas(val, + old < APR_UINT32_MAX - add ? old + add : APR_UINT32_MAX, + cmp); + } + return old; +} + +static AP_FORCE_INLINE +apr_uint32_t atomic_uint32_sub(apr_uint32_t volatile *val, + apr_uint32_t sub) +{ + return apr_atomic_add32(val, -sub); +} + +static AP_FORCE_INLINE +apr_uint32_t atomic_uint32_sub_sat(apr_uint32_t volatile *val, + apr_uint32_t sub) +{ + apr_uint32_t old, cmp = 0; + old = atomic_uint32_get(val); + while (old != cmp) { + cmp = old; + old = atomic_uint32_cas(val, + old > sub ? old - sub : 0, + cmp); + } + return old; +} + + +/* Atomics for int32_t (uses uint32_t's for unsigned/safe wrap semantics) */ + +static AP_FORCE_INLINE +apr_int32_t atomic_int32_get(apr_int32_t volatile *val) +{ + return (apr_int32_t)atomic_uint32_get((void *)val); +} + +static AP_FORCE_INLINE +void atomic_int32_set(apr_int32_t volatile *val, + apr_int32_t to) +{ + atomic_uint32_set((void *)val, to); +} + +static AP_FORCE_INLINE +apr_int32_t atomic_int32_xchg(apr_int32_t volatile *val, + apr_int32_t with) +{ + return (apr_int32_t)atomic_uint32_xchg((void *)val, with); +} + +static AP_FORCE_INLINE +apr_int32_t atomic_int32_cas(apr_int32_t volatile *val, + apr_int32_t with, apr_int32_t cmp) +{ + return (apr_int32_t)atomic_uint32_cas((void *)val, with, cmp); +} + +static AP_FORCE_INLINE +apr_int32_t atomic_int32_add(apr_int32_t volatile *val, + apr_int32_t add) +{ + return (apr_int32_t)atomic_uint32_add((void *)val, add); +} + +static AP_FORCE_INLINE +apr_int32_t atomic_int32_add_sat(apr_int32_t volatile *val, + apr_int32_t add) +{ + apr_int32_t old, cmp; + old = atomic_int32_get(val); + if (add < 0 && old != APR_INT32_MIN) { + do { + cmp = old; + old = atomic_int32_cas(val, + old < APR_INT32_MIN - add ? APR_INT32_MIN : old + add, + cmp); + } while (old != cmp); + } + else if (add > 0 && old != APR_INT32_MAX) { + do { + cmp = old; + old = atomic_int32_cas(val, + old > APR_INT32_MAX - add ? APR_INT32_MAX : old + add, + cmp); + } while (old != cmp); + } + return old; +} + +static AP_FORCE_INLINE +apr_int32_t atomic_int32_sub(apr_int32_t volatile *val, + apr_int32_t sub) +{ + return (apr_int32_t)atomic_uint32_sub((void *)val, sub); +} + +static AP_FORCE_INLINE +apr_int32_t atomic_int32_sub_sat(apr_int32_t volatile *val, + apr_int32_t sub) +{ + apr_int32_t old, cmp; + old = atomic_int32_get(val); + if (sub < 0 && old != APR_INT32_MAX) { + do { + cmp = old; + old = atomic_int32_cas(val, + old > APR_INT32_MAX + sub ? APR_INT32_MAX : old - sub, + cmp); + } while (old != cmp); + } + else if (sub > 0 && old != APR_INT32_MIN) { + do { + cmp = old; + old = atomic_int32_cas(val, + old < APR_INT32_MIN + sub ? APR_INT32_MIN : old - sub, + cmp); + } while (old != cmp); + } + return old; +} + + +/* Atomics for uint64_t (uses APR's) */ + +#if APR_SIZEOF_VOIDP == 8 /* not implemented/needed on 32bit platforms */ + +static AP_FORCE_INLINE +apr_uint64_t atomic_uint64_get(apr_uint64_t volatile *val) +{ +#if APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ + return apr_atomic_read64(val); +#else /* Use atomics for 64bit pointers */ + void *volatile *val_p = (void *)(apr_uintptr_t)val; + AP_DEBUG_ASSERT((apr_uintptr_t)val_p % sizeof(void*) == 0); + return (apr_uintptr_t)atomic_ptr_cas(val_p, NULL, NULL); +#endif +} + +static AP_FORCE_INLINE +void atomic_uint64_set(apr_uint64_t volatile *val, + apr_uint64_t to) +{ +#if APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ + apr_atomic_set64(val, to); +#else /* Use atomics for 64bit pointers */ + void *volatile *val_p = (void *)(apr_uintptr_t)val; + AP_DEBUG_ASSERT((apr_uintptr_t)val_p % sizeof(void*) == 0); + (void)atomic_ptr_xchg(val_p, (void *)(apr_uintptr_t)to); +#endif +} + +static AP_FORCE_INLINE +apr_uint64_t atomic_uint64_xchg(apr_uint64_t volatile *val, + apr_uint64_t with) +{ +#if APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ + return apr_atomic_xchg64(val, with); +#else /* Use atomics for 64bit pointers */ + void *volatile *val_p = (void *)(apr_uintptr_t)val; + AP_DEBUG_ASSERT((apr_uintptr_t)val_p % sizeof(void*) == 0); + return (apr_uintptr_t)atomic_ptr_xchg(val_p, (void *)(apr_uintptr_t)with); +#endif +} + +static AP_FORCE_INLINE +apr_uint64_t atomic_uint64_cas(apr_uint64_t volatile *val, + apr_uint64_t with, apr_uint64_t cmp) +{ +#if APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ + return apr_atomic_cas64(val, with, cmp); +#else /* Use atomics for 64bit pointers */ + void *volatile *val_p = (void *)(apr_uintptr_t)val; + AP_DEBUG_ASSERT((apr_uintptr_t)val_p % sizeof(void*) == 0); + return (apr_uintptr_t)atomic_ptr_cas(val_p, (void *)(apr_uintptr_t)with, + (void *)(apr_uintptr_t)cmp); +#endif +} + +static AP_FORCE_INLINE +apr_uint64_t atomic_uint64_add(apr_uint64_t volatile *val, + apr_uint64_t add) +{ +#if APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ + return apr_atomic_add64(val, add); +#else + apr_uint64_t old, cmp; + old = atomic_uint64_get(val); + do { + cmp = old; + old = (apr_uintptr_t)atomic_ptr_cas((void *volatile *)val, + (void *)(apr_uintptr_t)(old + add), + (void *)(apr_uintptr_t)cmp); + } while (old != cmp); + return old; +#endif +} + +static AP_FORCE_INLINE +apr_uint64_t atomic_uint64_add_sat(apr_uint64_t volatile *val, + apr_uint64_t add) +{ + apr_uint64_t old, cmp = APR_UINT64_MAX; + old = atomic_uint64_get(val); + while (old != cmp) { + cmp = old; + old = atomic_uint64_cas(val, + old < APR_UINT64_MAX - add ? old + add : APR_UINT64_MAX, + cmp); + } + return old; +} + +static AP_FORCE_INLINE +apr_uint64_t atomic_uint64_sub(apr_uint64_t volatile *val, + apr_uint64_t sub) +{ +#if APR_VERSION_AT_LEAST(1,7,4) /* APR 64bit atomics not safe before 1.7.4 */ + return apr_atomic_add64(val, -sub); +#else + apr_uint64_t old, cmp; + old = atomic_uint64_get(val); + do { + cmp = old; + old = (apr_uintptr_t)atomic_ptr_cas((void *volatile *)val, + (void *)(apr_uintptr_t)(old - sub), + (void *)(apr_uintptr_t)cmp); + } while (old != cmp); + return old; +#endif +} + +static AP_FORCE_INLINE +apr_uint64_t atomic_uint64_sub_sat(apr_uint64_t volatile *val, + apr_uint64_t sub) +{ + apr_uint64_t old, cmp = 0; + old = atomic_uint64_get(val); + while (old != cmp) { + cmp = old; + old = atomic_uint64_cas(val, + old > sub ? old - sub : 0, + cmp); + } + return old; +} + + +/* Atomics for int64_t (uses uint_64t's for unsigned/safe wrap semantics) */ + +static AP_FORCE_INLINE +apr_int64_t atomic_int64_get(apr_int64_t volatile *val) +{ + return (apr_int64_t)atomic_uint64_get((void *)val); +} + +static AP_FORCE_INLINE +void atomic_int64_set(apr_int64_t volatile *val, + apr_int64_t to) +{ + atomic_uint64_set((void *)val, to); +} + +static AP_FORCE_INLINE +apr_int64_t atomic_int64_xchg(apr_int64_t volatile *val, + apr_int64_t with) +{ + return (apr_int64_t)atomic_uint64_xchg((void *)val, with); +} + +static AP_FORCE_INLINE +apr_int64_t atomic_int64_cas(apr_int64_t volatile *val, + apr_int64_t with, apr_int64_t cmp) +{ + return (apr_int64_t)atomic_uint64_cas((void *)val, with, cmp); +} + +static AP_FORCE_INLINE +apr_int64_t atomic_int64_add(apr_int64_t volatile *val, + apr_int64_t add) +{ + return (apr_int64_t)atomic_uint64_add((void *)val, add); +} + +static AP_FORCE_INLINE +apr_int64_t atomic_int64_add_sat(apr_int64_t volatile *val, + apr_int64_t add) +{ + apr_int64_t old, cmp; + old = atomic_int64_get(val); + if (add < 0 && old != APR_INT64_MIN) { + do { + cmp = old; + old = atomic_int64_cas(val, + old < APR_INT64_MIN - add ? APR_INT64_MIN : old + add, + cmp); + } while (old != cmp); + } + else if (add > 0 && old != APR_INT64_MAX) { + do { + cmp = old; + old = atomic_int64_cas(val, + old > APR_INT64_MAX - add ? APR_INT64_MAX : old + add, + cmp); + } while (old != cmp); + } + return old; +} + +static AP_FORCE_INLINE +apr_int64_t atomic_int64_sub(apr_int64_t volatile *val, + apr_int64_t sub) +{ + return (apr_int64_t)atomic_uint64_sub((void *)val, sub); +} + +static AP_FORCE_INLINE +apr_int64_t atomic_int64_sub_sat(apr_int64_t volatile *val, + apr_int64_t sub) +{ + apr_int64_t old, cmp; + old = atomic_int64_get(val); + if (sub < 0 && old != APR_INT64_MAX) { + do { + cmp = old; + old = atomic_int64_cas(val, + old > APR_INT64_MAX + sub ? APR_INT64_MAX : old - sub, + cmp); + } while (old != cmp); + } + else if (sub > 0 && old != APR_INT64_MIN) { + do { + cmp = old; + old = atomic_int64_cas(val, + old < APR_INT64_MIN + sub ? APR_INT64_MIN : old - sub, + cmp); + } while (old != cmp); + } + return old; +} + +#endif /* APR_SIZEOF_VOIDP == 8 */ + + +/* Atomics for int (uses int32_t's on all platforms we care about) */ + +AP_DECLARE(int) ap_atomic_int_get(int volatile *val) +{ + return atomic_int32_get((void *)val); +} + +AP_DECLARE(void) ap_atomic_int_set(int volatile *val, + int to) +{ + atomic_int32_set((void *)val, to); +} + +AP_DECLARE(int) ap_atomic_int_xchg(int volatile *val, + int with) +{ + return atomic_int32_xchg((void *)val, with); +} + +AP_DECLARE(int) ap_atomic_int_cas(int volatile *val, + int with, int cmp) +{ + return atomic_int32_cas((void *)val, with, cmp); +} + +AP_DECLARE(int) ap_atomic_int_add(int volatile *val, + int add) +{ + return atomic_int32_add((void *)val, add); +} + +AP_DECLARE(int) ap_atomic_int_add_sat(int volatile *val, + int add) +{ + return atomic_int32_add_sat((void *)val, add); +} + +AP_DECLARE(int) ap_atomic_int_sub(int volatile *val, + int sub) +{ + return atomic_int32_sub((void *)val, sub); +} + +AP_DECLARE(int) ap_atomic_int_sub_sat(int volatile *val, + int sub) +{ + return atomic_int32_sub_sat((void *)val, sub); +} + + +/* Atomics for unsigned int (uses uint32_t's on all platforms we care about) */ + +AP_DECLARE(unsigned int) ap_atomic_uint_get(unsigned int volatile *val) +{ + return atomic_uint32_get((void *)val); +} + +AP_DECLARE(void) ap_atomic_uint_set(unsigned int volatile *val, + unsigned int to) +{ + atomic_uint32_set((void *)val, to); +} + +AP_DECLARE(unsigned int) ap_atomic_uint_xchg(unsigned int volatile *val, + unsigned int with) +{ + return atomic_uint32_xchg((void *)val, with); +} + +AP_DECLARE(unsigned int) ap_atomic_uint_cas(unsigned int volatile *val, + unsigned int with, unsigned int cmp) +{ + return atomic_uint32_cas((void *)val, with, cmp); +} + +AP_DECLARE(unsigned int) ap_atomic_uint_add(unsigned int volatile *val, + unsigned int add) +{ + return atomic_uint32_add((void *)val, add); +} + +AP_DECLARE(unsigned int) ap_atomic_uint_add_sat(unsigned int volatile *val, + unsigned int add) +{ + return atomic_uint32_add_sat((void *)val, add); +} + +AP_DECLARE(unsigned int) ap_atomic_uint_sub(unsigned int volatile *val, + unsigned int sub) +{ + return atomic_uint32_sub((void *)val, sub); +} + +AP_DECLARE(unsigned int) ap_atomic_uint_sub_sat(unsigned int volatile *val, + unsigned int sub) +{ + return atomic_uint32_sub_sat((void *)val, sub); +} + + +/* Atomics for long (uses int32_t's or int64_t's depending on LONG_MAX) */ + +AP_DECLARE(long) ap_atomic_long_get(long volatile *val) +{ +#if LONG_MAX == APR_INT32_MAX + return atomic_int32_get((void *)val); +#elif LONG_MAX == APR_INT64_MAX + return atomic_int64_get((void *)val); +#endif +} + +AP_DECLARE(void) ap_atomic_long_set(long volatile *val, + long to) +{ +#if LONG_MAX == APR_INT32_MAX + atomic_int32_set((void *)val, to); +#elif LONG_MAX == APR_INT64_MAX + atomic_int64_set((void *)val, to); +#endif +} + +AP_DECLARE(long) ap_atomic_long_xchg(long volatile *val, + long with) +{ +#if LONG_MAX == APR_INT32_MAX + return atomic_int32_xchg((void *)val, with); +#elif LONG_MAX == APR_INT64_MAX + return atomic_int64_xchg((void *)val, with); +#endif +} + +AP_DECLARE(long) ap_atomic_long_cas(long volatile *val, + long with, long cmp) +{ +#if LONG_MAX == APR_INT32_MAX + return atomic_int32_cas((void *)val, with, cmp); +#elif LONG_MAX == APR_INT64_MAX + return atomic_int64_cas((void *)val, with, cmp); +#endif +} + +AP_DECLARE(long) ap_atomic_long_add(long volatile *val, + long add) +{ +#if LONG_MAX == APR_INT32_MAX + return atomic_int32_add((void *)val, add); +#elif LONG_MAX == APR_INT64_MAX + return atomic_int64_add((void *)val, add); +#endif +} + +AP_DECLARE(long) ap_atomic_long_add_sat(long volatile *val, + long add) +{ +#if LONG_MAX == APR_INT32_MAX + return atomic_int32_add_sat((void *)val, add); +#elif LONG_MAX == APR_INT64_MAX + return atomic_int64_add_sat((void *)val, add); +#endif +} + +AP_DECLARE(long) ap_atomic_long_sub(long volatile *val, + long sub) +{ +#if LONG_MAX == APR_INT32_MAX + return atomic_int32_sub((void *)val, sub); +#elif LONG_MAX == APR_INT64_MAX + return atomic_int64_sub((void *)val, sub); +#endif +} + +AP_DECLARE(long) ap_atomic_long_sub_sat(long volatile *val, + long sub) +{ +#if LONG_MAX == APR_INT32_MAX + return atomic_int32_sub_sat((void *)val, sub); +#elif LONG_MAX == APR_INT64_MAX + return atomic_int64_sub_sat((void *)val, sub); +#endif +} + + +/* Atomics for unsigned long (uses uint32_t's or uint64_t's depending on ULONG_MAX) */ + +AP_DECLARE(unsigned long) ap_atomic_ulong_get(unsigned long volatile *val) +{ +#if ULONG_MAX == APR_UINT32_MAX + return atomic_uint32_get((void *)val); +#elif ULONG_MAX == APR_UINT64_MAX + return atomic_uint64_get((void *)val); +#endif +} + +AP_DECLARE(void) ap_atomic_ulong_set(unsigned long volatile *val, + unsigned long to) +{ +#if ULONG_MAX == APR_UINT32_MAX + atomic_uint32_set((void *)val, to); +#elif ULONG_MAX == APR_UINT64_MAX + atomic_uint64_set((void *)val, to); +#endif +} + +AP_DECLARE(unsigned long) ap_atomic_ulong_xchg(unsigned long volatile *val, + unsigned long with) +{ +#if ULONG_MAX == APR_UINT32_MAX + return atomic_uint32_xchg((void *)val, with); +#elif ULONG_MAX == APR_UINT64_MAX + return atomic_uint64_xchg((void *)val, with); +#endif +} + +AP_DECLARE(unsigned long) ap_atomic_ulong_cas(unsigned long volatile *val, + unsigned long with, unsigned long cmp) +{ +#if ULONG_MAX == APR_UINT32_MAX + return atomic_uint32_cas((void *)val, with, cmp); +#elif ULONG_MAX == APR_UINT64_MAX + return atomic_uint64_cas((void *)val, with, cmp); +#endif +} + +AP_DECLARE(unsigned long) ap_atomic_ulong_add(unsigned long volatile *val, + unsigned long add) +{ +#if ULONG_MAX == APR_UINT32_MAX + return atomic_uint32_add((void *)val, add); +#elif ULONG_MAX == APR_UINT64_MAX + return atomic_uint64_add((void *)val, add); +#endif +} + +AP_DECLARE(unsigned long) ap_atomic_ulong_add_sat(unsigned long volatile *val, + unsigned long add) +{ +#if ULONG_MAX == APR_UINT32_MAX + return atomic_uint32_add_sat((void *)val, add); +#elif ULONG_MAX == APR_UINT64_MAX + return atomic_uint64_add_sat((void *)val, add); +#endif +} + +AP_DECLARE(unsigned long) ap_atomic_ulong_sub(unsigned long volatile *val, + unsigned long sub) +{ +#if ULONG_MAX == APR_UINT32_MAX + return atomic_uint32_sub((void *)val, sub); +#elif ULONG_MAX == APR_UINT64_MAX + return atomic_uint64_sub((void *)val, sub); +#endif +} + +AP_DECLARE(unsigned long) ap_atomic_ulong_sub_sat(unsigned long volatile *val, + unsigned long sub) +{ +#if ULONG_MAX == APR_UINT32_MAX + return atomic_uint32_sub_sat((void *)val, sub); +#elif ULONG_MAX == APR_UINT64_MAX + return atomic_uint64_sub_sat((void *)val, sub); +#endif +} + + +/* Atomics for size_t (uses uint32_t's or uint64_t's depending on sizeof(void*)) */ + +AP_DECLARE(apr_size_t) ap_atomic_size_get(apr_size_t volatile *val) +{ +#if APR_SIZEOF_VOIDP == 4 + return atomic_uint32_get((void *)val); +#elif APR_SIZEOF_VOIDP == 8 + return atomic_uint64_get((void *)val); +#endif +} + +AP_DECLARE(void) ap_atomic_size_set(apr_size_t volatile *val, + apr_size_t to) +{ +#if APR_SIZEOF_VOIDP == 4 + atomic_uint32_set((void *)val, to); +#elif APR_SIZEOF_VOIDP == 8 + atomic_uint64_set((void *)val, to); +#endif +} + +AP_DECLARE(apr_size_t) ap_atomic_size_xchg(apr_size_t volatile *val, + apr_size_t with) +{ +#if APR_SIZEOF_VOIDP == 4 + return atomic_uint32_xchg((void *)val, with); +#elif APR_SIZEOF_VOIDP == 8 + return atomic_uint64_xchg((void *)val, with); +#endif +} + +AP_DECLARE(apr_size_t) ap_atomic_size_cas(apr_size_t volatile *val, + apr_size_t with, apr_size_t cmp) +{ +#if APR_SIZEOF_VOIDP == 4 + return atomic_uint32_cas((void *)val, with, cmp); +#elif APR_SIZEOF_VOIDP == 8 + return atomic_uint64_cas((void *)val, with, cmp); +#endif +} + +AP_DECLARE(apr_size_t) ap_atomic_size_add(apr_size_t volatile *val, + apr_size_t add) +{ +#if APR_SIZEOF_VOIDP == 4 + return atomic_uint32_add((void *)val, add); +#elif APR_SIZEOF_VOIDP == 8 + return atomic_uint64_add((void *)val, add); +#endif +} + +AP_DECLARE(apr_size_t) ap_atomic_size_add_sat(apr_size_t volatile *val, + apr_size_t add) +{ +#if APR_SIZEOF_VOIDP == 4 + return atomic_uint32_add_sat((void *)val, add); +#elif APR_SIZEOF_VOIDP == 8 + return atomic_uint64_add_sat((void *)val, add); +#endif +} + +AP_DECLARE(apr_size_t) ap_atomic_size_sub(apr_size_t volatile *val, + apr_size_t sub) +{ +#if APR_SIZEOF_VOIDP == 4 + return atomic_uint32_sub((void *)val, sub); +#elif APR_SIZEOF_VOIDP == 8 + return atomic_uint64_sub((void *)val, sub); +#endif +} + +AP_DECLARE(apr_size_t) ap_atomic_size_sub_sat(apr_size_t volatile *val, + apr_size_t sub) +{ +#if APR_SIZEOF_VOIDP == 4 + return atomic_uint32_sub_sat((void *)val, sub); +#elif APR_SIZEOF_VOIDP == 8 + return atomic_uint64_sub_sat((void *)val, sub); +#endif +}