@@ -47,42 +47,73 @@ enum bson_memory_order {
47
47
#define MSVC_MEMORDER_SUFFIX (X )
48
48
#endif
49
49
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
50
69
51
- #define DEF_ATOMIC_OP (MSVC_Intrinsic , GNU_Intrinsic , Order , ...) \
70
+ #define DEF_ATOMIC_OP (MSVC_Intrinsic , GNU_Intrinsic , GNU_Legacy_Intrinsic , Order , ...) \
52
71
do { \
53
72
switch (Order) { \
54
73
case bson_memory_order_acq_rel: \
55
74
BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
56
75
BSON_IF_GNU_LIKE ( \
57
76
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQ_REL);) \
77
+ BSON_IF_GNU_LEGACY_ATOMICS ( \
78
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
58
79
case bson_memory_order_seq_cst: \
59
80
BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \
60
81
BSON_IF_GNU_LIKE ( \
61
82
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_SEQ_CST);) \
83
+ BSON_IF_GNU_LEGACY_ATOMICS ( \
84
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
62
85
case bson_memory_order_acquire: \
63
86
BSON_IF_MSVC ( \
64
87
return BSON_CONCAT (MSVC_Intrinsic, \
65
88
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
66
89
BSON_IF_GNU_LIKE ( \
67
90
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQUIRE);) \
91
+ BSON_IF_GNU_LEGACY_ATOMICS ( \
92
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
68
93
case bson_memory_order_consume: \
69
94
BSON_IF_MSVC ( \
70
95
return BSON_CONCAT (MSVC_Intrinsic, \
71
96
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
72
97
BSON_IF_GNU_LIKE ( \
73
98
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_CONSUME);) \
99
+ BSON_IF_GNU_LEGACY_ATOMICS ( \
100
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
74
101
case bson_memory_order_release: \
75
102
BSON_IF_MSVC ( \
76
103
return BSON_CONCAT (MSVC_Intrinsic, \
77
104
MSVC_MEMORDER_SUFFIX (_rel)) (__VA_ARGS__);) \
78
105
BSON_IF_GNU_LIKE ( \
79
106
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELEASE);) \
107
+ BSON_IF_GNU_LEGACY_ATOMICS ( \
108
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
80
109
case bson_memory_order_relaxed: \
81
110
BSON_IF_MSVC ( \
82
111
return BSON_CONCAT (MSVC_Intrinsic, \
83
112
MSVC_MEMORDER_SUFFIX (_nf)) (__VA_ARGS__);) \
84
113
BSON_IF_GNU_LIKE ( \
85
114
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELAXED);) \
115
+ BSON_IF_GNU_LEGACY_ATOMICS ( \
116
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
86
117
default: \
87
118
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
88
119
} \
@@ -102,6 +133,12 @@ enum bson_memory_order {
102
133
false, /* Not weak */ \
103
134
GNU_MemOrder , \
104
135
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 ;) \
105
142
} while (0 )
106
143
107
144
@@ -118,6 +155,12 @@ enum bson_memory_order {
118
155
true, /* Yes weak */ \
119
156
GNU_MemOrder , \
120
157
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 ;) \
121
164
} while (0 )
122
165
123
166
@@ -127,6 +170,7 @@ enum bson_memory_order {
127
170
{ \
128
171
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchangeAdd, VCIntrinSuffix), \
129
172
__atomic_fetch_add, \
173
+ __sync_fetch_and_add, \
130
174
ord, \
131
175
a, \
132
176
addend); \
@@ -139,7 +183,9 @@ enum bson_memory_order {
139
183
BSON_IF_MSVC ( \
140
184
return bson_atomic_ ##NamePart ##_fetch_add (a, -subtrahend, ord);) \
141
185
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);) \
143
189
} \
144
190
\
145
191
static BSON_INLINE Type bson_atomic_##NamePart##_fetch ( \
@@ -164,13 +210,15 @@ enum bson_memory_order {
164
210
default : \
165
211
BSON_UNREACHABLE ("Invalid bson_memory_order value" ); \
166
212
}) \
213
+ BSON_IF_GNU_LEGACY_ATOMICS ({ __sync_synchronize (); return * a ; }) \
167
214
} \
168
215
\
169
216
static BSON_INLINE Type bson_atomic_ ##NamePart ##_exchange ( \
170
217
Type volatile *a, Type value, enum bson_memory_order ord) \
171
218
{ \
172
219
BSON_IF_MSVC ( \
173
220
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchange, VCIntrinSuffix), \
221
+ ~, \
174
222
~, \
175
223
ord, \
176
224
a, \
@@ -192,6 +240,8 @@ enum bson_memory_order {
192
240
default : \
193
241
BSON_UNREACHABLE ("Invalid bson_memory_order value" ); \
194
242
}) \
243
+ BSON_IF_GNU_LEGACY_ATOMICS ( \
244
+ return __sync_val_compare_and_swap (a , * a , value );) \
195
245
} \
196
246
\
197
247
static BSON_INLINE Type bson_atomic_ ##NamePart ##_compare_exchange_strong ( \
@@ -285,7 +335,7 @@ enum bson_memory_order {
285
335
#define DECL_ATOMIC_STDINT (Name , VCSuffix ) \
286
336
DECL_ATOMIC_INTEGRAL (Name, Name##_t, VCSuffix)
287
337
288
- #ifdef _MSC_VER
338
+ #if defined( _MSC_VER ) || defined ( BSON_USE_LEGACY_GCC_ATOMICS )
289
339
/* MSVC expects precise types for their atomic intrinsics. */
290
340
DECL_ATOMIC_INTEGRAL (int8 , char , 8 );
291
341
DECL_ATOMIC_INTEGRAL (int16 , short , 16 )
@@ -388,8 +438,23 @@ bson_atomic_ptr_exchange (void *volatile *ptr,
388
438
void * new_value ,
389
439
enum bson_memory_order ord )
390
440
{
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
393
458
}
394
459
395
460
static BSON_INLINE void *
@@ -500,8 +565,16 @@ bson_atomic_thread_fence ()
500
565
{
501
566
BSON_IF_MSVC (MemoryBarrier ();)
502
567
BSON_IF_GNU_LIKE (__sync_synchronize ();)
568
+ BSON_IF_GNU_LEGACY_ATOMICS (__sync_synchronize ();)
503
569
}
504
570
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
+
505
578
BSON_GNUC_DEPRECATED_FOR ("bson_atomic_thread_fence" )
506
579
BSON_EXPORT (void ) bson_memory_barrier (void );
507
580
0 commit comments