Skip to content

Commit 3a1b04a

Browse files
committed
CDRIVER-4215 use legacy atomic built-ins on gcc (>= 4.1, < 4.9)
1 parent 04d6ac5 commit 3a1b04a

File tree

1 file changed

+78
-5
lines changed

1 file changed

+78
-5
lines changed

src/libbson/src/bson/bson-atomic.h

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,42 +47,73 @@ enum bson_memory_order {
4747
#define MSVC_MEMORDER_SUFFIX(X)
4848
#endif
4949

50+
#if defined(USE_LEGACY_GCC_ATOMICS) || (!defined(__clang__) && \
51+
__GNUC__ == 4 && __GNUC_MINOR__ >= 1 && __GNUC_MINOR__ < 9)
52+
#define BSON_USE_LEGACY_GCC_ATOMICS
53+
#else
54+
#undef BSON_USE_LEGACY_GCC_ATOMICS
55+
#endif
56+
57+
/* Not all GCC-like compilers support the current __atomic built-ins. Older
58+
* GCC (pre-4.9) used different built-ins named with the __sync prefix. When
59+
* compiling with such older GCC versions, it is necessary to use the applicable
60+
* functions, which requires redefining BSON_IF_GNU_LIKE and defining the
61+
* additional BSON_IF_GNU_LEGACY_ATOMICS macro here. */
62+
#ifdef BSON_USE_LEGACY_GCC_ATOMICS
63+
#undef BSON_IF_GNU_LIKE
64+
#define BSON_IF_GNU_LIKE(...)
65+
#define BSON_IF_GNU_LEGACY_ATOMICS(...) __VA_ARGS__
66+
#else
67+
#define BSON_IF_GNU_LEGACY_ATOMICS(...)
68+
#endif
5069

51-
#define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, Order, ...) \
70+
#define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, GNU_Legacy_Intrinsic, Order, ...) \
5271
do { \
5372
switch (Order) { \
5473
case bson_memory_order_acq_rel: \
5574
BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
5675
BSON_IF_GNU_LIKE ( \
5776
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQ_REL);) \
77+
BSON_IF_GNU_LEGACY_ATOMICS ( \
78+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
5879
case bson_memory_order_seq_cst: \
5980
BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
6081
BSON_IF_GNU_LIKE ( \
6182
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_SEQ_CST);) \
83+
BSON_IF_GNU_LEGACY_ATOMICS ( \
84+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
6285
case bson_memory_order_acquire: \
6386
BSON_IF_MSVC ( \
6487
return BSON_CONCAT (MSVC_Intrinsic, \
6588
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
6689
BSON_IF_GNU_LIKE ( \
6790
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQUIRE);) \
91+
BSON_IF_GNU_LEGACY_ATOMICS ( \
92+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
6893
case bson_memory_order_consume: \
6994
BSON_IF_MSVC ( \
7095
return BSON_CONCAT (MSVC_Intrinsic, \
7196
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
7297
BSON_IF_GNU_LIKE ( \
7398
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_CONSUME);) \
99+
BSON_IF_GNU_LEGACY_ATOMICS ( \
100+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
74101
case bson_memory_order_release: \
75102
BSON_IF_MSVC ( \
76103
return BSON_CONCAT (MSVC_Intrinsic, \
77104
MSVC_MEMORDER_SUFFIX (_rel)) (__VA_ARGS__);) \
78105
BSON_IF_GNU_LIKE ( \
79106
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELEASE);) \
107+
BSON_IF_GNU_LEGACY_ATOMICS ( \
108+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
80109
case bson_memory_order_relaxed: \
81110
BSON_IF_MSVC ( \
82111
return BSON_CONCAT (MSVC_Intrinsic, \
83112
MSVC_MEMORDER_SUFFIX (_nf)) (__VA_ARGS__);) \
84113
BSON_IF_GNU_LIKE ( \
85114
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELAXED);) \
115+
BSON_IF_GNU_LEGACY_ATOMICS ( \
116+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
86117
default: \
87118
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
88119
} \
@@ -102,6 +133,12 @@ enum bson_memory_order {
102133
false, /* Not weak */ \
103134
GNU_MemOrder, \
104135
GNU_MemOrder);) \
136+
BSON_IF_GNU_LEGACY_ATOMICS ( \
137+
__typeof__ (ExpectActualVar) _val; \
138+
_val = __sync_val_compare_and_swap (Ptr, \
139+
ExpectActualVar, \
140+
NewValue); \
141+
ExpectActualVar = _val;) \
105142
} while (0)
106143

107144

@@ -118,6 +155,12 @@ enum bson_memory_order {
118155
true, /* Yes weak */ \
119156
GNU_MemOrder, \
120157
GNU_MemOrder);) \
158+
BSON_IF_GNU_LEGACY_ATOMICS ( \
159+
__typeof__ (ExpectActualVar) _val; \
160+
_val = __sync_val_compare_and_swap (Ptr, \
161+
ExpectActualVar, \
162+
NewValue); \
163+
ExpectActualVar = _val;) \
121164
} while (0)
122165

123166

@@ -127,6 +170,7 @@ enum bson_memory_order {
127170
{ \
128171
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchangeAdd, VCIntrinSuffix), \
129172
__atomic_fetch_add, \
173+
__sync_fetch_and_add, \
130174
ord, \
131175
a, \
132176
addend); \
@@ -139,7 +183,9 @@ enum bson_memory_order {
139183
BSON_IF_MSVC ( \
140184
return bson_atomic_##NamePart##_fetch_add (a, -subtrahend, ord);) \
141185
BSON_IF_GNU_LIKE ( \
142-
DEF_ATOMIC_OP (~, __atomic_fetch_sub, ord, a, subtrahend);) \
186+
DEF_ATOMIC_OP (~, __atomic_fetch_sub, ~, ord, a, subtrahend);) \
187+
BSON_IF_GNU_LEGACY_ATOMICS ( \
188+
DEF_ATOMIC_OP (~, ~, __sync_fetch_and_sub, ord, a, subtrahend);) \
143189
} \
144190
\
145191
static BSON_INLINE Type bson_atomic_##NamePart##_fetch ( \
@@ -164,13 +210,15 @@ enum bson_memory_order {
164210
default: \
165211
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
166212
}) \
213+
BSON_IF_GNU_LEGACY_ATOMICS ({ __sync_synchronize (); return *a; }) \
167214
} \
168215
\
169216
static BSON_INLINE Type bson_atomic_##NamePart##_exchange ( \
170217
Type volatile *a, Type value, enum bson_memory_order ord) \
171218
{ \
172219
BSON_IF_MSVC ( \
173220
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchange, VCIntrinSuffix), \
221+
~, \
174222
~, \
175223
ord, \
176224
a, \
@@ -192,6 +240,8 @@ enum bson_memory_order {
192240
default: \
193241
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
194242
}) \
243+
BSON_IF_GNU_LEGACY_ATOMICS ( \
244+
return __sync_val_compare_and_swap (a, *a, value);) \
195245
} \
196246
\
197247
static BSON_INLINE Type bson_atomic_##NamePart##_compare_exchange_strong ( \
@@ -285,7 +335,7 @@ enum bson_memory_order {
285335
#define DECL_ATOMIC_STDINT(Name, VCSuffix) \
286336
DECL_ATOMIC_INTEGRAL (Name, Name##_t, VCSuffix)
287337

288-
#ifdef _MSC_VER
338+
#if defined(_MSC_VER) || defined (BSON_USE_LEGACY_GCC_ATOMICS)
289339
/* MSVC expects precise types for their atomic intrinsics. */
290340
DECL_ATOMIC_INTEGRAL (int8, char, 8);
291341
DECL_ATOMIC_INTEGRAL (int16, short, 16)
@@ -388,8 +438,23 @@ bson_atomic_ptr_exchange (void *volatile *ptr,
388438
void *new_value,
389439
enum bson_memory_order ord)
390440
{
391-
DEF_ATOMIC_OP (
392-
_InterlockedExchangePointer, __atomic_exchange_n, ord, ptr, new_value);
441+
/* The older __sync_val_compare_and_swap also takes oldval */
442+
#if defined(BSON_USE_LEGACY_GCC_ATOMICS)
443+
DEF_ATOMIC_OP (_InterlockedExchangePointer,
444+
,
445+
__sync_val_compare_and_swap,
446+
ord,
447+
ptr,
448+
*ptr,
449+
new_value);
450+
#else
451+
DEF_ATOMIC_OP (_InterlockedExchangePointer,
452+
__atomic_exchange_n,
453+
,
454+
ord,
455+
ptr,
456+
new_value);
457+
#endif
393458
}
394459

395460
static BSON_INLINE void *
@@ -500,8 +565,16 @@ bson_atomic_thread_fence ()
500565
{
501566
BSON_IF_MSVC (MemoryBarrier ();)
502567
BSON_IF_GNU_LIKE (__sync_synchronize ();)
568+
BSON_IF_GNU_LEGACY_ATOMICS (__sync_synchronize ();)
503569
}
504570

571+
#ifdef BSON_USE_LEGACY_GCC_ATOMICS
572+
#undef BSON_IF_GNU_LIKE
573+
#define BSON_IF_GNU_LIKE(...) __VA_ARGS__
574+
#endif
575+
#undef BSON_IF_GNU_LEGACY_ATOMICS
576+
#undef BSON_USE_LEGACY_GCC_ATOMICS
577+
505578
BSON_GNUC_DEPRECATED_FOR ("bson_atomic_thread_fence")
506579
BSON_EXPORT (void) bson_memory_barrier (void);
507580

0 commit comments

Comments
 (0)