]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: hathreads: add support for gcc < 4.7
authorWilly Tarreau <w@1wt.eu>
Thu, 4 Jan 2018 17:49:31 +0000 (18:49 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 10 Jan 2018 06:51:56 +0000 (07:51 +0100)
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.

include/common/hathreads.h

index 9782ca9a07158d122a60ea6fe5c077660fa374ab..503abbec3185806b2ee51a17f49ba513a6f11dc3 100644 (file)
@@ -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);                          \