From: Willy Tarreau Date: Thu, 4 Jan 2018 17:49:31 +0000 (+0100) Subject: MINOR: hathreads: add support for gcc < 4.7 X-Git-Tag: v1.9-dev1~521 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a69af6d3892fe1946bb8babb3044d2d26afd46e;p=thirdparty%2Fhaproxy.git MINOR: hathreads: add support for gcc < 4.7 Till now the use of __atomic_* gcc builtins required gcc >= 4.7. Since some supported and quite common operating systems like CentOS 6 still come with older versions (4.4) and the mapping to the older builtins is reasonably simple, let's implement it. This code is only used for gcc < 4.7. It has been quickly tested on a machine using gcc 4.4.4 and provided expected results. This patch should be backported to 1.8. --- diff --git a/include/common/hathreads.h b/include/common/hathreads.h index 9782ca9a07..503abbec31 100644 --- a/include/common/hathreads.h +++ b/include/common/hathreads.h @@ -99,6 +99,58 @@ extern THREAD_LOCAL unsigned long tid_bit; /* The bit corresponding to the threa /* TODO: thread: For now, we rely on GCC builtins but it could be a good idea to * have a header file regrouping all functions dealing with threads. */ + +#if defined(__GNUC__) && (__GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ < 7) +/* gcc < 4.7 */ + +#define HA_ATOMIC_ADD(val, i) __sync_add_and_fetch(val, i) +#define HA_ATOMIC_SUB(val, i) __sync_sub_and_fetch(val, i) +#define HA_ATOMIC_AND(val, flags) __sync_and_and_fetch(val, flags) +#define HA_ATOMIC_OR(val, flags) __sync_or_and_fetch(val, flags) + +/* the CAS is a bit complicated. The older API doesn't support returning the + * value and the swap's result at the same time. So here we take what looks + * like the safest route, consisting in using the boolean version guaranteeing + * that the operation was performed or not, and we snoop a previous value. If + * the compare succeeds, we return. If it fails, we return the previous value, + * but only if it differs from the expected one. If it's the same it's a race + * thus we try again to avoid confusing a possibly sensitive caller. + */ +#define HA_ATOMIC_CAS(val, old, new) \ + ({ \ + typeof((val)) __val = (val); \ + typeof((old)) __oldp = (old); \ + typeof(*(old)) __oldv; \ + typeof((new)) __new = (new); \ + int __ret; \ + do { \ + __oldv = *__val; \ + __ret = __sync_bool_compare_and_swap(__val, *__oldp, __new); \ + } while (!__ret && *__oldp == __oldv); \ + if (!__ret) \ + *__oldp = __oldv; \ + __ret; \ + }) + +#define HA_ATOMIC_XCHG(val, new) \ + ({ \ + typeof((val)) __val = (val); \ + typeof(*(val)) __old; \ + typeof((new)) __new = (new); \ + do { __old = *__val; \ + } while (!__sync_bool_compare_and_swap(__val, __old, __new)); \ + __old; \ + }) +#define HA_ATOMIC_STORE(val, new) \ + ({ \ + typeof((val)) __val = (val); \ + typeof(*(val)) __old; \ + typeof((new)) __new = (new); \ + do { __old = *__val; \ + } while (!__sync_bool_compare_and_swap(__val, __old, __new)); \ + }) +#else +/* gcc >= 4.7 */ #define HA_ATOMIC_CAS(val, old, new) __atomic_compare_exchange_n(val, old, new, 0, 0, 0) #define HA_ATOMIC_ADD(val, i) __atomic_add_fetch(val, i, 0) #define HA_ATOMIC_SUB(val, i) __atomic_sub_fetch(val, i, 0) @@ -106,6 +158,8 @@ extern THREAD_LOCAL unsigned long tid_bit; /* The bit corresponding to the threa #define HA_ATOMIC_OR(val, flags) __atomic_or_fetch(val, flags, 0) #define HA_ATOMIC_XCHG(val, new) __atomic_exchange_n(val, new, 0) #define HA_ATOMIC_STORE(val, new) __atomic_store_n(val, new, 0) +#endif + #define HA_ATOMIC_UPDATE_MAX(val, new) \ ({ \ typeof(*(val)) __old = *(val); \