Skip to content

Commit b8ce3a9

Browse files
committed
CDRIVER-4215 use legacy atomic built-ins on gcc (>= 4.1, < 4.7)
1 parent bebe063 commit b8ce3a9

File tree

2 files changed

+99
-34
lines changed

2 files changed

+99
-34
lines changed

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

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,41 +48,53 @@ enum bson_memory_order {
4848
#endif
4949

5050

51-
#define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, Order, ...) \
51+
#define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, GNU_Legacy_Intrinsic, Order, ...) \
5252
do { \
5353
switch (Order) { \
5454
case bson_memory_order_acq_rel: \
55-
BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
56-
BSON_IF_GNU_LIKE ( \
55+
BSON_ATOMIC_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
56+
BSON_ATOMIC_IF_GNU_LIKE ( \
5757
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQ_REL);) \
58+
BSON_ATOMIC_IF_GNU_LEGACY ( \
59+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
5860
case bson_memory_order_seq_cst: \
59-
BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
60-
BSON_IF_GNU_LIKE ( \
61+
BSON_ATOMIC_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
62+
BSON_ATOMIC_IF_GNU_LIKE ( \
6163
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_SEQ_CST);) \
64+
BSON_ATOMIC_IF_GNU_LEGACY ( \
65+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
6266
case bson_memory_order_acquire: \
63-
BSON_IF_MSVC ( \
67+
BSON_ATOMIC_IF_MSVC ( \
6468
return BSON_CONCAT (MSVC_Intrinsic, \
6569
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
66-
BSON_IF_GNU_LIKE ( \
70+
BSON_ATOMIC_IF_GNU_LIKE ( \
6771
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQUIRE);) \
72+
BSON_ATOMIC_IF_GNU_LEGACY ( \
73+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
6874
case bson_memory_order_consume: \
69-
BSON_IF_MSVC ( \
75+
BSON_ATOMIC_IF_MSVC ( \
7076
return BSON_CONCAT (MSVC_Intrinsic, \
7177
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
72-
BSON_IF_GNU_LIKE ( \
78+
BSON_ATOMIC_IF_GNU_LIKE ( \
7379
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_CONSUME);) \
80+
BSON_ATOMIC_IF_GNU_LEGACY ( \
81+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
7482
case bson_memory_order_release: \
75-
BSON_IF_MSVC ( \
83+
BSON_ATOMIC_IF_MSVC ( \
7684
return BSON_CONCAT (MSVC_Intrinsic, \
7785
MSVC_MEMORDER_SUFFIX (_rel)) (__VA_ARGS__);) \
78-
BSON_IF_GNU_LIKE ( \
86+
BSON_ATOMIC_IF_GNU_LIKE ( \
7987
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELEASE);) \
88+
BSON_ATOMIC_IF_GNU_LEGACY ( \
89+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
8090
case bson_memory_order_relaxed: \
81-
BSON_IF_MSVC ( \
91+
BSON_ATOMIC_IF_MSVC ( \
8292
return BSON_CONCAT (MSVC_Intrinsic, \
8393
MSVC_MEMORDER_SUFFIX (_nf)) (__VA_ARGS__);) \
84-
BSON_IF_GNU_LIKE ( \
94+
BSON_ATOMIC_IF_GNU_LIKE ( \
8595
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELAXED);) \
96+
BSON_ATOMIC_IF_GNU_LEGACY ( \
97+
return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
8698
default: \
8799
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
88100
} \
@@ -92,32 +104,44 @@ enum bson_memory_order {
92104
#define DEF_ATOMIC_CMPEXCH_STRONG( \
93105
VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \
94106
do { \
95-
BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
107+
BSON_ATOMIC_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
96108
_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \
97109
Ptr, NewValue, ExpectActualVar);) \
98-
BSON_IF_GNU_LIKE ( \
110+
BSON_ATOMIC_IF_GNU_LIKE ( \
99111
(void) __atomic_compare_exchange_n (Ptr, \
100112
&ExpectActualVar, \
101113
NewValue, \
102114
false, /* Not weak */ \
103115
GNU_MemOrder, \
104116
GNU_MemOrder);) \
117+
BSON_ATOMIC_IF_GNU_LEGACY ( \
118+
__typeof__ (ExpectActualVar) _val; \
119+
_val = __sync_val_compare_and_swap (Ptr, \
120+
ExpectActualVar, \
121+
NewValue); \
122+
ExpectActualVar = _val;) \
105123
} while (0)
106124

107125

108126
#define DEF_ATOMIC_CMPEXCH_WEAK( \
109127
VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \
110128
do { \
111-
BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
129+
BSON_ATOMIC_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
112130
_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \
113131
Ptr, NewValue, ExpectActualVar);) \
114-
BSON_IF_GNU_LIKE ( \
132+
BSON_ATOMIC_IF_GNU_LIKE ( \
115133
(void) __atomic_compare_exchange_n (Ptr, \
116134
&ExpectActualVar, \
117135
NewValue, \
118136
true, /* Yes weak */ \
119137
GNU_MemOrder, \
120138
GNU_MemOrder);) \
139+
BSON_ATOMIC_IF_GNU_LEGACY ( \
140+
__typeof__ (ExpectActualVar) _val; \
141+
_val = __sync_val_compare_and_swap (Ptr, \
142+
ExpectActualVar, \
143+
NewValue); \
144+
ExpectActualVar = _val;) \
121145
} while (0)
122146

123147

@@ -127,6 +151,7 @@ enum bson_memory_order {
127151
{ \
128152
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchangeAdd, VCIntrinSuffix), \
129153
__atomic_fetch_add, \
154+
__sync_fetch_and_add, \
130155
ord, \
131156
a, \
132157
addend); \
@@ -136,21 +161,23 @@ enum bson_memory_order {
136161
Type volatile *a, Type subtrahend, enum bson_memory_order ord) \
137162
{ \
138163
/* MSVC doesn't have a subtract intrinsic, so just reuse addition */ \
139-
BSON_IF_MSVC ( \
164+
BSON_ATOMIC_IF_MSVC ( \
140165
return bson_atomic_##NamePart##_fetch_add (a, -subtrahend, ord);) \
141-
BSON_IF_GNU_LIKE ( \
142-
DEF_ATOMIC_OP (~, __atomic_fetch_sub, ord, a, subtrahend);) \
166+
BSON_ATOMIC_IF_GNU_LIKE ( \
167+
DEF_ATOMIC_OP (~, __atomic_fetch_sub, ~, ord, a, subtrahend);) \
168+
BSON_ATOMIC_IF_GNU_LEGACY ( \
169+
DEF_ATOMIC_OP (~, ~, __sync_fetch_and_sub, ord, a, subtrahend);) \
143170
} \
144171
\
145172
static BSON_INLINE Type bson_atomic_##NamePart##_fetch ( \
146173
Type volatile const *a, enum bson_memory_order order) \
147174
{ \
148175
/* MSVC doesn't have a load intrinsic, so just add zero */ \
149-
BSON_IF_MSVC (return bson_atomic_##NamePart##_fetch_add ( \
176+
BSON_ATOMIC_IF_MSVC (return bson_atomic_##NamePart##_fetch_add ( \
150177
(Type volatile *) a, 0, order);) \
151178
/* GNU doesn't want RELEASE order for the fetch operation, so we can't \
152179
* just use DEF_ATOMIC_OP. */ \
153-
BSON_IF_GNU_LIKE (switch (order) { \
180+
BSON_ATOMIC_IF_GNU_LIKE (switch (order) { \
154181
case bson_memory_order_release: /* Fall back to seqcst */ \
155182
case bson_memory_order_acq_rel: /* Fall back to seqcst */ \
156183
case bson_memory_order_seq_cst: \
@@ -164,20 +191,22 @@ enum bson_memory_order {
164191
default: \
165192
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
166193
}) \
194+
BSON_ATOMIC_IF_GNU_LEGACY ({ __sync_synchronize (); return *a; }) \
167195
} \
168196
\
169197
static BSON_INLINE Type bson_atomic_##NamePart##_exchange ( \
170198
Type volatile *a, Type value, enum bson_memory_order ord) \
171199
{ \
172-
BSON_IF_MSVC ( \
200+
BSON_ATOMIC_IF_MSVC ( \
173201
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchange, VCIntrinSuffix), \
202+
~, \
174203
~, \
175204
ord, \
176205
a, \
177206
value);) \
178207
/* GNU doesn't want CONSUME order for the exchange operation, so we \
179208
* cannot use DEF_ATOMIC_OP. */ \
180-
BSON_IF_GNU_LIKE (switch (ord) { \
209+
BSON_ATOMIC_IF_GNU_LIKE (switch (ord) { \
181210
case bson_memory_order_acq_rel: \
182211
return __atomic_exchange_n (a, value, __ATOMIC_ACQ_REL); \
183212
case bson_memory_order_release: \
@@ -192,6 +221,8 @@ enum bson_memory_order {
192221
default: \
193222
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
194223
}) \
224+
BSON_ATOMIC_IF_GNU_LEGACY ( \
225+
return __sync_val_compare_and_swap (a, *a, value);) \
195226
} \
196227
\
197228
static BSON_INLINE Type bson_atomic_##NamePart##_compare_exchange_strong ( \
@@ -285,7 +316,7 @@ enum bson_memory_order {
285316
#define DECL_ATOMIC_STDINT(Name, VCSuffix) \
286317
DECL_ATOMIC_INTEGRAL (Name, Name##_t, VCSuffix)
287318

288-
#ifdef _MSC_VER
319+
#if defined(_MSC_VER) || defined (BSON_USE_LEGACY_GCC_ATOMICS)
289320
/* MSVC expects precise types for their atomic intrinsics. */
290321
DECL_ATOMIC_INTEGRAL (int8, char, 8);
291322
DECL_ATOMIC_INTEGRAL (int16, short, 16)
@@ -386,8 +417,23 @@ bson_atomic_ptr_exchange (void *volatile *ptr,
386417
void *new_value,
387418
enum bson_memory_order ord)
388419
{
389-
DEF_ATOMIC_OP (
390-
_InterlockedExchangePointer, __atomic_exchange_n, ord, ptr, new_value);
420+
/* The older __sync_val_compare_and_swap also takes oldval */
421+
#if defined(BSON_USE_LEGACY_GCC_ATOMICS)
422+
DEF_ATOMIC_OP (_InterlockedExchangePointer,
423+
,
424+
__sync_val_compare_and_swap,
425+
ord,
426+
ptr,
427+
*ptr,
428+
new_value);
429+
#else
430+
DEF_ATOMIC_OP (_InterlockedExchangePointer,
431+
__atomic_exchange_n,
432+
,
433+
ord,
434+
ptr,
435+
new_value);
436+
#endif
391437
}
392438

393439
static BSON_INLINE void *
@@ -496,8 +542,9 @@ bson_atomic_ptr_fetch (void *volatile const *ptr, enum bson_memory_order ord)
496542
static BSON_INLINE void
497543
bson_atomic_thread_fence ()
498544
{
499-
BSON_IF_MSVC (MemoryBarrier ();)
500-
BSON_IF_GNU_LIKE (__sync_synchronize ();)
545+
BSON_ATOMIC_IF_MSVC (MemoryBarrier ();)
546+
BSON_ATOMIC_IF_GNU_LIKE (__sync_synchronize ();)
547+
BSON_ATOMIC_IF_GNU_LEGACY (__sync_synchronize ();)
501548
}
502549

503550
BSON_GNUC_DEPRECATED_FOR ("bson_atomic_thread_fence")

src/libbson/src/bson/bson-compat.h

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,34 @@ typedef signed char bool;
171171
#endif
172172

173173

174+
#if defined(USE_LEGACY_GCC_ATOMICS) || (!defined(__clang__) && \
175+
__GNUC__ == 4 && __GNUC_MINOR__ >= 1 && __GNUC_MINOR__ < 7)
176+
#define BSON_USE_LEGACY_GCC_ATOMICS
177+
#else
178+
#undef BSON_USE_LEGACY_GCC_ATOMICS
179+
#endif
180+
174181
#ifdef _MSC_VER
175182
/** Expands the arguments if compiling with MSVC, otherwise empty */
176-
#define BSON_IF_MSVC(...) __VA_ARGS__
183+
#define BSON_ATOMIC_IF_MSVC(...) __VA_ARGS__
184+
/** Expands the arguments if compiling with GCC (>= 4.7) or Clang, otherwise empty */
185+
#define BSON_ATOMIC_IF_GNU_LIKE(...)
186+
/** Expands the arguments if compiling with GCC (>= 4.1, < 4.7), otherwise empty */
187+
#define BSON_ATOMIC_IF_GNU_LEGACY(...)
188+
#elif defined(__clang__) || (defined(__GNUC__) && !defined(BSON_USE_LEGACY_GCC_ATOMICS))
189+
/** Expands the arguments if compiling with MSVC, otherwise empty */
190+
#define BSON_ATOMIC_IF_MSVC(...)
177191
/** Expands the arguments if compiling with GCC or Clang, otherwise empty */
178-
#define BSON_IF_GNU_LIKE(...)
179-
#elif defined(__GNUC__) || defined(__clang__)
192+
#define BSON_ATOMIC_IF_GNU_LIKE(...) __VA_ARGS__
193+
/** Expands the arguments if compiling with GCC (>= 4.1, < 4.7), otherwise empty */
194+
#define BSON_ATOMIC_IF_GNU_LEGACY(...)
195+
#elif defined(BSON_USE_LEGACY_GCC_ATOMICS)
180196
/** Expands the arguments if compiling with MSVC, otherwise empty */
181-
#define BSON_IF_MSVC(...)
197+
#define BSON_ATOMIC_IF_MSVC(...)
182198
/** Expands the arguments if compiling with GCC or Clang, otherwise empty */
183-
#define BSON_IF_GNU_LIKE(...) __VA_ARGS__
199+
#define BSON_ATOMIC_IF_GNU_LIKE(...)
200+
/** Expands the arguments if compiling with GCC (>= 4.1, < 4.7), otherwise empty */
201+
#define BSON_ATOMIC_IF_GNU_LEGACY(...) __VA_ARGS__
184202
#endif
185203

186204
#ifdef BSON_OS_WIN32

0 commit comments

Comments
 (0)