@@ -48,41 +48,53 @@ enum bson_memory_order {
48
48
#endif
49
49
50
50
51
- #define DEF_ATOMIC_OP (MSVC_Intrinsic , GNU_Intrinsic , Order , ...) \
51
+ #define DEF_ATOMIC_OP (MSVC_Intrinsic , GNU_Intrinsic , GNU_Legacy_Intrinsic , Order , ...) \
52
52
do { \
53
53
switch (Order) { \
54
54
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 ( \
57
57
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQ_REL);) \
58
+ BSON_ATOMIC_IF_GNU_LEGACY ( \
59
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
58
60
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 ( \
61
63
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_SEQ_CST);) \
64
+ BSON_ATOMIC_IF_GNU_LEGACY ( \
65
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
62
66
case bson_memory_order_acquire: \
63
- BSON_IF_MSVC ( \
67
+ BSON_ATOMIC_IF_MSVC ( \
64
68
return BSON_CONCAT (MSVC_Intrinsic, \
65
69
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
66
- BSON_IF_GNU_LIKE ( \
70
+ BSON_ATOMIC_IF_GNU_LIKE ( \
67
71
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQUIRE);) \
72
+ BSON_ATOMIC_IF_GNU_LEGACY ( \
73
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
68
74
case bson_memory_order_consume: \
69
- BSON_IF_MSVC ( \
75
+ BSON_ATOMIC_IF_MSVC ( \
70
76
return BSON_CONCAT (MSVC_Intrinsic, \
71
77
MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \
72
- BSON_IF_GNU_LIKE ( \
78
+ BSON_ATOMIC_IF_GNU_LIKE ( \
73
79
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_CONSUME);) \
80
+ BSON_ATOMIC_IF_GNU_LEGACY ( \
81
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
74
82
case bson_memory_order_release: \
75
- BSON_IF_MSVC ( \
83
+ BSON_ATOMIC_IF_MSVC ( \
76
84
return BSON_CONCAT (MSVC_Intrinsic, \
77
85
MSVC_MEMORDER_SUFFIX (_rel)) (__VA_ARGS__);) \
78
- BSON_IF_GNU_LIKE ( \
86
+ BSON_ATOMIC_IF_GNU_LIKE ( \
79
87
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELEASE);) \
88
+ BSON_ATOMIC_IF_GNU_LEGACY ( \
89
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
80
90
case bson_memory_order_relaxed: \
81
- BSON_IF_MSVC ( \
91
+ BSON_ATOMIC_IF_MSVC ( \
82
92
return BSON_CONCAT (MSVC_Intrinsic, \
83
93
MSVC_MEMORDER_SUFFIX (_nf)) (__VA_ARGS__);) \
84
- BSON_IF_GNU_LIKE ( \
94
+ BSON_ATOMIC_IF_GNU_LIKE ( \
85
95
return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELAXED);) \
96
+ BSON_ATOMIC_IF_GNU_LEGACY ( \
97
+ return GNU_Legacy_Intrinsic (__VA_ARGS__);) \
86
98
default: \
87
99
BSON_UNREACHABLE ("Invalid bson_memory_order value"); \
88
100
} \
@@ -92,32 +104,44 @@ enum bson_memory_order {
92
104
#define DEF_ATOMIC_CMPEXCH_STRONG ( \
93
105
VCSuffix1 , VCSuffix2 , GNU_MemOrder , Ptr , ExpectActualVar , NewValue ) \
94
106
do { \
95
- BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
107
+ BSON_ATOMIC_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
96
108
_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \
97
109
Ptr, NewValue, ExpectActualVar);) \
98
- BSON_IF_GNU_LIKE ( \
110
+ BSON_ATOMIC_IF_GNU_LIKE ( \
99
111
(void) __atomic_compare_exchange_n (Ptr, \
100
112
&ExpectActualVar, \
101
113
NewValue, \
102
114
false, /* Not weak */ \
103
115
GNU_MemOrder , \
104
116
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 ;) \
105
123
} while (0 )
106
124
107
125
108
126
#define DEF_ATOMIC_CMPEXCH_WEAK ( \
109
127
VCSuffix1 , VCSuffix2 , GNU_MemOrder , Ptr , ExpectActualVar , NewValue ) \
110
128
do { \
111
- BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
129
+ BSON_ATOMIC_IF_MSVC (ExpectActualVar = BSON_CONCAT3 ( \
112
130
_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \
113
131
Ptr, NewValue, ExpectActualVar);) \
114
- BSON_IF_GNU_LIKE ( \
132
+ BSON_ATOMIC_IF_GNU_LIKE ( \
115
133
(void) __atomic_compare_exchange_n (Ptr, \
116
134
&ExpectActualVar, \
117
135
NewValue, \
118
136
true, /* Yes weak */ \
119
137
GNU_MemOrder , \
120
138
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 ;) \
121
145
} while (0 )
122
146
123
147
@@ -127,6 +151,7 @@ enum bson_memory_order {
127
151
{ \
128
152
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchangeAdd, VCIntrinSuffix), \
129
153
__atomic_fetch_add, \
154
+ __sync_fetch_and_add, \
130
155
ord, \
131
156
a, \
132
157
addend); \
@@ -136,21 +161,23 @@ enum bson_memory_order {
136
161
Type volatile *a, Type subtrahend, enum bson_memory_order ord) \
137
162
{ \
138
163
/* MSVC doesn't have a subtract intrinsic, so just reuse addition */ \
139
- BSON_IF_MSVC ( \
164
+ BSON_ATOMIC_IF_MSVC ( \
140
165
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);) \
143
170
} \
144
171
\
145
172
static BSON_INLINE Type bson_atomic_##NamePart##_fetch ( \
146
173
Type volatile const *a, enum bson_memory_order order) \
147
174
{ \
148
175
/* 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 ( \
150
177
(Type volatile *) a, 0, order);) \
151
178
/* GNU doesn't want RELEASE order for the fetch operation, so we can't \
152
179
* just use DEF_ATOMIC_OP. */ \
153
- BSON_IF_GNU_LIKE (switch (order ) { \
180
+ BSON_ATOMIC_IF_GNU_LIKE (switch (order ) { \
154
181
case bson_memory_order_release : /* Fall back to seqcst */ \
155
182
case bson_memory_order_acq_rel : /* Fall back to seqcst */ \
156
183
case bson_memory_order_seq_cst : \
@@ -164,20 +191,22 @@ enum bson_memory_order {
164
191
default : \
165
192
BSON_UNREACHABLE ("Invalid bson_memory_order value" ); \
166
193
}) \
194
+ BSON_ATOMIC_IF_GNU_LEGACY ({ __sync_synchronize (); return * a ; }) \
167
195
} \
168
196
\
169
197
static BSON_INLINE Type bson_atomic_ ##NamePart ##_exchange ( \
170
198
Type volatile *a, Type value, enum bson_memory_order ord) \
171
199
{ \
172
- BSON_IF_MSVC ( \
200
+ BSON_ATOMIC_IF_MSVC ( \
173
201
DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchange, VCIntrinSuffix), \
202
+ ~, \
174
203
~, \
175
204
ord, \
176
205
a, \
177
206
value);) \
178
207
/* GNU doesn't want CONSUME order for the exchange operation, so we \
179
208
* cannot use DEF_ATOMIC_OP. */ \
180
- BSON_IF_GNU_LIKE (switch (ord ) { \
209
+ BSON_ATOMIC_IF_GNU_LIKE (switch (ord ) { \
181
210
case bson_memory_order_acq_rel : \
182
211
return __atomic_exchange_n (a , value , __ATOMIC_ACQ_REL ); \
183
212
case bson_memory_order_release : \
@@ -192,6 +221,8 @@ enum bson_memory_order {
192
221
default : \
193
222
BSON_UNREACHABLE ("Invalid bson_memory_order value" ); \
194
223
}) \
224
+ BSON_ATOMIC_IF_GNU_LEGACY ( \
225
+ return __sync_val_compare_and_swap (a , * a , value );) \
195
226
} \
196
227
\
197
228
static BSON_INLINE Type bson_atomic_ ##NamePart ##_compare_exchange_strong ( \
@@ -285,7 +316,7 @@ enum bson_memory_order {
285
316
#define DECL_ATOMIC_STDINT (Name , VCSuffix ) \
286
317
DECL_ATOMIC_INTEGRAL (Name, Name##_t, VCSuffix)
287
318
288
- #ifdef _MSC_VER
319
+ #if defined( _MSC_VER ) || defined ( BSON_USE_LEGACY_GCC_ATOMICS )
289
320
/* MSVC expects precise types for their atomic intrinsics. */
290
321
DECL_ATOMIC_INTEGRAL (int8 , char , 8 );
291
322
DECL_ATOMIC_INTEGRAL (int16 , short , 16 )
@@ -386,8 +417,23 @@ bson_atomic_ptr_exchange (void *volatile *ptr,
386
417
void * new_value ,
387
418
enum bson_memory_order ord )
388
419
{
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
391
437
}
392
438
393
439
static BSON_INLINE void *
@@ -496,8 +542,9 @@ bson_atomic_ptr_fetch (void *volatile const *ptr, enum bson_memory_order ord)
496
542
static BSON_INLINE void
497
543
bson_atomic_thread_fence ()
498
544
{
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 ();)
501
548
}
502
549
503
550
BSON_GNUC_DEPRECATED_FOR ("bson_atomic_thread_fence" )
0 commit comments