Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement [ap_]atomics for [u]int/[u]long/size_t and use them for (some) proxy_worker_shared fields #396

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,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
Expand Down
1 change: 1 addition & 0 deletions NWGNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions build/nw_export.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
122 changes: 122 additions & 0 deletions include/ap_atomics.h
Original file line number Diff line number Diff line change
@@ -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);
18 changes: 18 additions & 0 deletions include/ap_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
55 changes: 55 additions & 0 deletions include/httpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
#if APR_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if defined(__STDC__) || defined(_MSC_VER) /* C89 */
#include <assert.h> /* for static_assert */
#endif

/* Note: apr_uri.h is also included, see below */

Expand Down Expand Up @@ -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.
* @{
Expand Down
8 changes: 8 additions & 0 deletions libhttpd.dsp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 28 additions & 20 deletions modules/proxy/balancers/mod_lbmethod_bybusyness.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(&current->s->lbstatus, lbfactor);
if (prev_best) {
apr_size_t current_busy = ap_atomic_size_get(&current->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,
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down
Loading