43
43
typedef struct zend_atomic_bool_s {
44
44
volatile char value ;
45
45
} zend_atomic_bool ;
46
+ typedef struct zend_atomic_int_s {
47
+ # ifdef ZEND_WIN32
48
+ volatile long value ;
49
+ # else
50
+ volatile int value ;
51
+ # endif
52
+ } zend_atomic_int ;
46
53
#elif defined(HAVE_C11_ATOMICS )
47
54
typedef struct zend_atomic_bool_s {
48
55
_Atomic (bool ) value ;
49
56
} zend_atomic_bool ;
57
+ typedef struct zend_atomic_int_s {
58
+ _Atomic (int ) value ;
59
+ } zend_atomic_int ;
50
60
#else
51
61
typedef struct zend_atomic_bool_s {
52
62
volatile bool value ;
53
63
} zend_atomic_bool ;
64
+ typedef struct zend_atomic_int_s {
65
+ volatile int value ;
66
+ } zend_atomic_int ;
54
67
#endif
55
68
56
69
BEGIN_EXTERN_C ()
@@ -63,62 +76,169 @@ BEGIN_EXTERN_C()
63
76
#ifndef InterlockedOr8
64
77
#define InterlockedOr8 _InterlockedOr8
65
78
#endif
79
+ #ifndef InterlockedCompareExchange8
80
+ #define InterlockedCompareExchange8 _InterlockedCompareExchange8
81
+ #endif
82
+ #ifndef InterlockedExchange
83
+ #define InterlockedExchange _InterlockedExchange
84
+ #endif
85
+ #ifndef InterlockedOr
86
+ #define InterlockedOr _InterlockedOr
87
+ #endif
88
+ #ifndef InterlockedCompareExchange
89
+ #define InterlockedCompareExchange _InterlockedCompareExchange
90
+ #endif
66
91
67
92
#define ZEND_ATOMIC_BOOL_INIT (obj , desired ) ((obj)->value = (desired))
93
+ #define ZEND_ATOMIC_INT_INIT (obj , desired ) ((obj)->value = (desired))
94
+
95
+ #define ZEND_ATOMIC_BOOL_INITIALIZER (desired ) {.value = (desired)}
96
+ #define ZEND_ATOMIC_INT_INITIALIZER (desired ) {.value = (desired)}
68
97
69
98
static zend_always_inline bool zend_atomic_bool_exchange_ex (zend_atomic_bool * obj , bool desired ) {
70
99
return InterlockedExchange8 (& obj -> value , desired );
71
100
}
72
101
102
+ static zend_always_inline int zend_atomic_int_exchange_ex (zend_atomic_int * obj , int desired ) {
103
+ return (int ) InterlockedExchange (& obj -> value , desired );
104
+ }
105
+
106
+ static zend_always_inline bool zend_atomic_bool_compare_exchange_ex (zend_atomic_bool * obj , bool * expected , bool desired ) {
107
+ bool prev = (bool ) InterlockedCompareExchange8 (& obj -> value , * expected , desired );
108
+ if (prev == * expected ) {
109
+ return true;
110
+ } else {
111
+ * expected = prev ;
112
+ return false;
113
+ }
114
+ }
115
+
116
+ static zend_always_inline bool zend_atomic_int_compare_exchange_ex (zend_atomic_int * obj , int * expected , int desired ) {
117
+ int prev = (int ) InterlockedCompareExchange (& obj -> value , * expected , desired );
118
+ if (prev == * expected ) {
119
+ return true;
120
+ } else {
121
+ * expected = prev ;
122
+ return false;
123
+ }
124
+ }
125
+
73
126
/* On this platform it is non-const due to Iterlocked API*/
74
127
static zend_always_inline bool zend_atomic_bool_load_ex (zend_atomic_bool * obj ) {
75
128
/* Or'ing with false won't change the value. */
76
129
return InterlockedOr8 (& obj -> value , false);
77
130
}
78
131
132
+ static zend_always_inline int zend_atomic_int_load_ex (zend_atomic_int * obj ) {
133
+ /* Or'ing with 0 won't change the value. */
134
+ return (int ) InterlockedOr (& obj -> value , 0 );
135
+ }
136
+
79
137
static zend_always_inline void zend_atomic_bool_store_ex (zend_atomic_bool * obj , bool desired ) {
80
138
(void )InterlockedExchange8 (& obj -> value , desired );
81
139
}
82
140
141
+ static zend_always_inline void zend_atomic_int_store_ex (zend_atomic_int * obj , int desired ) {
142
+ (void )InterlockedExchange (& obj -> value , desired );
143
+ }
144
+
83
145
#elif defined(HAVE_C11_ATOMICS )
84
146
85
147
#define ZEND_ATOMIC_BOOL_INIT (obj , desired ) __c11_atomic_init(&(obj)->value, (desired))
148
+ #define ZEND_ATOMIC_INT_INIT (obj , desired ) __c11_atomic_init(&(obj)->value, (desired))
149
+
150
+ #define ZEND_ATOMIC_BOOL_INITIALIZER (desired ) {.value = (desired)}
151
+ #define ZEND_ATOMIC_INT_INITIALIZER (desired ) {.value = (desired)}
86
152
87
153
static zend_always_inline bool zend_atomic_bool_exchange_ex (zend_atomic_bool * obj , bool desired ) {
88
154
return __c11_atomic_exchange (& obj -> value , desired , __ATOMIC_SEQ_CST );
89
155
}
90
156
157
+ static zend_always_inline int zend_atomic_int_exchange_ex (zend_atomic_int * obj , int desired ) {
158
+ return __c11_atomic_exchange (& obj -> value , desired , __ATOMIC_SEQ_CST );
159
+ }
160
+
161
+ static zend_always_inline bool zend_atomic_bool_compare_exchange_ex (zend_atomic_bool * obj , bool * expected , bool desired ) {
162
+ return __c11_atomic_compare_exchange_strong (& obj -> value , expected , desired , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST );
163
+ }
164
+
165
+ static zend_always_inline bool zend_atomic_int_compare_exchange_ex (zend_atomic_int * obj , int * expected , int desired ) {
166
+ return __c11_atomic_compare_exchange_strong (& obj -> value , expected , desired , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST );
167
+ }
168
+
91
169
static zend_always_inline bool zend_atomic_bool_load_ex (const zend_atomic_bool * obj ) {
92
170
return __c11_atomic_load (& obj -> value , __ATOMIC_SEQ_CST );
93
171
}
94
172
173
+ static zend_always_inline int zend_atomic_int_load_ex (const zend_atomic_int * obj ) {
174
+ return __c11_atomic_load (& obj -> value , __ATOMIC_SEQ_CST );
175
+ }
176
+
95
177
static zend_always_inline void zend_atomic_bool_store_ex (zend_atomic_bool * obj , bool desired ) {
96
178
__c11_atomic_store (& obj -> value , desired , __ATOMIC_SEQ_CST );
97
179
}
98
180
181
+ static zend_always_inline void zend_atomic_int_store_ex (zend_atomic_int * obj , int desired ) {
182
+ __c11_atomic_store (& obj -> value , desired , __ATOMIC_SEQ_CST );
183
+ }
184
+
99
185
#elif defined(HAVE_GNUC_ATOMICS )
100
186
187
+ /* bool */
188
+
101
189
#define ZEND_ATOMIC_BOOL_INIT (obj , desired ) ((obj)->value = (desired))
190
+ #define ZEND_ATOMIC_INT_INIT (obj , desired ) ((obj)->value = (desired))
191
+
192
+ #define ZEND_ATOMIC_BOOL_INITIALIZER (desired ) {.value = (desired)}
193
+ #define ZEND_ATOMIC_INT_INITIALIZER (desired ) {.value = (desired)}
102
194
103
195
static zend_always_inline bool zend_atomic_bool_exchange_ex (zend_atomic_bool * obj , bool desired ) {
104
196
bool prev = false;
105
197
__atomic_exchange (& obj -> value , & desired , & prev , __ATOMIC_SEQ_CST );
106
198
return prev ;
107
199
}
108
200
201
+ static zend_always_inline int zend_atomic_int_exchange_ex (zend_atomic_int * obj , int desired ) {
202
+ int prev = false;
203
+ __atomic_exchange (& obj -> value , & desired , & prev , __ATOMIC_SEQ_CST );
204
+ return prev ;
205
+ }
206
+
207
+ static zend_always_inline bool zend_atomic_bool_compare_exchange_ex (zend_atomic_bool * obj , bool * expected , bool desired ) {
208
+ return __atomic_compare_exchange (& obj -> value , expected , & desired , /* weak */ false, __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST );
209
+ }
210
+
211
+ static zend_always_inline bool zend_atomic_int_compare_exchange_ex (zend_atomic_int * obj , int * expected , int desired ) {
212
+ return __atomic_compare_exchange (& obj -> value , expected , & desired , /* weak */ false, __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST );
213
+ }
214
+
109
215
static zend_always_inline bool zend_atomic_bool_load_ex (const zend_atomic_bool * obj ) {
110
216
bool prev = false;
111
217
__atomic_load (& obj -> value , & prev , __ATOMIC_SEQ_CST );
112
218
return prev ;
113
219
}
114
220
221
+ static zend_always_inline int zend_atomic_int_load_ex (const zend_atomic_int * obj ) {
222
+ int prev = false;
223
+ __atomic_load (& obj -> value , & prev , __ATOMIC_SEQ_CST );
224
+ return prev ;
225
+ }
226
+
115
227
static zend_always_inline void zend_atomic_bool_store_ex (zend_atomic_bool * obj , bool desired ) {
116
228
__atomic_store (& obj -> value , & desired , __ATOMIC_SEQ_CST );
117
229
}
118
230
231
+ static zend_always_inline void zend_atomic_int_store_ex (zend_atomic_int * obj , int desired ) {
232
+ __atomic_store (& obj -> value , & desired , __ATOMIC_SEQ_CST );
233
+ }
234
+
119
235
#elif defined(HAVE_SYNC_ATOMICS )
120
236
121
237
#define ZEND_ATOMIC_BOOL_INIT (obj , desired ) ((obj)->value = (desired))
238
+ #define ZEND_ATOMIC_INT_INIT (obj , desired ) ((obj)->value = (desired))
239
+
240
+ #define ZEND_ATOMIC_BOOL_INITIALIZER (desired ) {.value = (desired)}
241
+ #define ZEND_ATOMIC_INT_INITIALIZER (desired ) {.value = (desired)}
122
242
123
243
static zend_always_inline bool zend_atomic_bool_exchange_ex (zend_atomic_bool * obj , bool desired ) {
124
244
bool prev = __sync_lock_test_and_set (& obj -> value , desired );
@@ -130,48 +250,139 @@ static zend_always_inline bool zend_atomic_bool_exchange_ex(zend_atomic_bool *ob
130
250
return prev ;
131
251
}
132
252
253
+ static zend_always_inline int zend_atomic_int_exchange_ex (zend_atomic_int * obj , int desired ) {
254
+ int prev = __sync_lock_test_and_set (& obj -> value , desired );
255
+
256
+ /* __sync_lock_test_and_set only does an acquire barrier, so sync
257
+ * immediately after.
258
+ */
259
+ __sync_synchronize ();
260
+ return prev ;
261
+ }
262
+
263
+ static zend_always_inline bool zend_atomic_bool_compare_exchange_ex (zend_atomic_bool * obj , bool * expected , bool desired ) {
264
+ bool prev = __sync_val_compare_and_swap (& obj -> value , * expected , desired );
265
+ if (prev == * expected ) {
266
+ return true;
267
+ } else {
268
+ * expected = prev ;
269
+ return false;
270
+ }
271
+ }
272
+
273
+ static zend_always_inline bool zend_atomic_int_compare_exchange_ex (zend_atomic_int * obj , int * expected , int desired ) {
274
+ int prev = __sync_val_compare_and_swap (& obj -> value , * expected , desired );
275
+ if (prev == * expected ) {
276
+ return true;
277
+ } else {
278
+ * expected = prev ;
279
+ return false;
280
+ }
281
+ }
282
+
133
283
static zend_always_inline bool zend_atomic_bool_load_ex (zend_atomic_bool * obj ) {
134
284
/* Or'ing false won't change the value */
135
285
return __sync_fetch_and_or (& obj -> value , false);
136
286
}
137
287
288
+ static zend_always_inline int zend_atomic_int_load_ex (zend_atomic_int * obj ) {
289
+ /* Or'ing 0 won't change the value */
290
+ return __sync_fetch_and_or (& obj -> value , 0 );
291
+ }
292
+
138
293
static zend_always_inline void zend_atomic_bool_store_ex (zend_atomic_bool * obj , bool desired ) {
139
294
__sync_synchronize ();
140
295
obj -> value = desired ;
141
296
__sync_synchronize ();
142
297
}
143
298
299
+ static zend_always_inline void zend_atomic_int_store_ex (zend_atomic_int * obj , int desired ) {
300
+ __sync_synchronize ();
301
+ obj -> value = desired ;
302
+ __sync_synchronize ();
303
+ }
304
+
144
305
#elif defined(HAVE_NO_ATOMICS )
145
306
146
307
#warning No atomics support detected. Please open an issue with platform details.
147
308
148
309
#define ZEND_ATOMIC_BOOL_INIT (obj , desired ) ((obj)->value = (desired))
310
+ #define ZEND_ATOMIC_INT_INIT (obj , desired ) ((obj)->value = (desired))
311
+
312
+ #define ZEND_ATOMIC_BOOL_INITIALIZER (desired ) {.value = (desired)}
313
+ #define ZEND_ATOMIC_INT_INITIALIZER (desired ) {.value = (desired)}
149
314
150
315
static zend_always_inline void zend_atomic_bool_store_ex (zend_atomic_bool * obj , bool desired ) {
151
316
obj -> value = desired ;
152
317
}
153
318
319
+ static zend_always_inline void zend_atomic_int_store_ex (zend_atomic_int * obj , int desired ) {
320
+ obj -> value = desired ;
321
+ }
322
+
323
+ static zend_always_inline bool zend_atomic_bool_compare_exchange_ex (zend_atomic_int * obj , bool * expected , bool desired ) {
324
+ bool prev = obj -> value ;
325
+ if (prev == * expected ) {
326
+ obj -> value = desired ;
327
+ return true;
328
+ } else {
329
+ * expected = prev ;
330
+ return false;
331
+ }
332
+ }
333
+
334
+ static zend_always_inline bool zend_atomic_int_compare_exchange_ex (zend_atomic_int * obj , int * expected , int desired ) {
335
+ int prev = obj -> value ;
336
+ if (prev == * expected ) {
337
+ obj -> value = desired ;
338
+ return true;
339
+ } else {
340
+ * expected = prev ;
341
+ return false;
342
+ }
343
+ }
344
+
154
345
static zend_always_inline bool zend_atomic_bool_load_ex (const zend_atomic_bool * obj ) {
155
346
return obj -> value ;
156
347
}
157
348
349
+ static zend_always_inline int zend_atomic_int_load_ex (const zend_atomic_int * obj ) {
350
+ return obj -> value ;
351
+ }
352
+
158
353
static zend_always_inline bool zend_atomic_bool_exchange_ex (zend_atomic_bool * obj , bool desired ) {
159
354
bool prev = obj -> value ;
160
355
obj -> value = desired ;
161
356
return prev ;
162
357
}
163
358
359
+ static zend_always_inline int zend_atomic_int_exchange_ex (zend_atomic_int * obj , int desired ) {
360
+ int prev = obj -> value ;
361
+ obj -> value = desired ;
362
+ return prev ;
363
+ }
364
+
164
365
#endif
165
366
166
367
ZEND_API void zend_atomic_bool_init (zend_atomic_bool * obj , bool desired );
368
+ ZEND_API void zend_atomic_int_init (zend_atomic_int * obj , int desired );
369
+
167
370
ZEND_API bool zend_atomic_bool_exchange (zend_atomic_bool * obj , bool desired );
371
+ ZEND_API int zend_atomic_int_exchange (zend_atomic_int * obj , int desired );
372
+
373
+ ZEND_API bool zend_atomic_bool_compare_exchange (zend_atomic_bool * obj , bool * expected , bool desired );
374
+ ZEND_API bool zend_atomic_int_compare_exchange (zend_atomic_int * obj , int * expected , int desired );
375
+
168
376
ZEND_API void zend_atomic_bool_store (zend_atomic_bool * obj , bool desired );
377
+ ZEND_API void zend_atomic_int_store (zend_atomic_int * obj , int desired );
169
378
170
379
#if defined(ZEND_WIN32 ) || defined(HAVE_SYNC_ATOMICS )
171
380
/* On these platforms it is non-const due to underlying APIs. */
172
381
ZEND_API bool zend_atomic_bool_load (zend_atomic_bool * obj );
382
+ ZEND_API int zend_atomic_int_load (zend_atomic_int * obj );
173
383
#else
174
384
ZEND_API bool zend_atomic_bool_load (const zend_atomic_bool * obj );
385
+ ZEND_API int zend_atomic_int_load (const zend_atomic_int * obj );
175
386
#endif
176
387
177
388
END_EXTERN_C ()
0 commit comments