1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
|
#ifndef RUBY_ATOMIC_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_ATOMIC_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Atomic operations
*
* Basically, if we could assume either C11 or C++11, these macros are just
* redundant. Sadly we cannot. We have to do them ourselves.
*/
/*
* - RUBY_ATOMIC_CAS, RUBY_ATOMIC_EXCHANGE, RUBY_ATOMIC_FETCH_*:
* return the old value.
* - RUBY_ATOMIC_ADD, RUBY_ATOMIC_SUB, RUBY_ATOMIC_INC, RUBY_ATOMIC_DEC, RUBY_ATOMIC_OR, RUBY_ATOMIC_SET:
* may be void.
*/
#if 0
#elif defined HAVE_GCC_ATOMIC_BUILTINS
typedef unsigned int rb_atomic_t;
# define RUBY_ATOMIC_FETCH_ADD(var, val) __atomic_fetch_add(&(var), (val), __ATOMIC_SEQ_CST)
# define RUBY_ATOMIC_FETCH_SUB(var, val) __atomic_fetch_sub(&(var), (val), __ATOMIC_SEQ_CST)
# define RUBY_ATOMIC_OR(var, val) __atomic_fetch_or(&(var), (val), __ATOMIC_SEQ_CST)
# define RUBY_ATOMIC_EXCHANGE(var, val) __atomic_exchange_n(&(var), (val), __ATOMIC_SEQ_CST)
# define RUBY_ATOMIC_CAS(var, oldval, newval) RB_GNUC_EXTENSION_BLOCK( \
__typeof__(var) oldvaldup = (oldval); /* oldval should not be modified */ \
__atomic_compare_exchange_n(&(var), &oldvaldup, (newval), 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); \
oldvaldup )
# define RUBY_ATOMIC_GENERIC_MACRO 1
#elif defined HAVE_GCC_SYNC_BUILTINS
/* @shyouhei hack to support atomic operations in case of gcc. Gcc
* has its own pseudo-insns to support them. See info, or
* http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html */
typedef unsigned int rb_atomic_t; /* Anything OK */
# define RUBY_ATOMIC_FETCH_ADD(var, val) __sync_fetch_and_add(&(var), (val))
# define RUBY_ATOMIC_FETCH_SUB(var, val) __sync_fetch_and_sub(&(var), (val))
# define RUBY_ATOMIC_OR(var, val) __sync_fetch_and_or(&(var), (val))
# define RUBY_ATOMIC_EXCHANGE(var, val) __sync_lock_test_and_set(&(var), (val))
# define RUBY_ATOMIC_CAS(var, oldval, newval) __sync_val_compare_and_swap(&(var), (oldval), (newval))
# define RUBY_ATOMIC_GENERIC_MACRO 1
#elif defined _WIN32
#if RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
#pragma intrinsic(_InterlockedOr)
#endif
typedef LONG rb_atomic_t;
# define RUBY_ATOMIC_SET(var, val) InterlockedExchange(&(var), (val))
# define RUBY_ATOMIC_INC(var) InterlockedIncrement(&(var))
# define RUBY_ATOMIC_DEC(var) InterlockedDecrement(&(var))
# define RUBY_ATOMIC_FETCH_ADD(var, val) InterlockedExchangeAdd(&(var), (val))
# define RUBY_ATOMIC_FETCH_SUB(var, val) InterlockedExchangeAdd(&(var), -(LONG)(val))
#if defined __GNUC__
# define RUBY_ATOMIC_OR(var, val) __asm__("lock\n\t" "orl\t%1, %0" : "=m"(var) : "Ir"(val))
#elif RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
# define RUBY_ATOMIC_OR(var, val) rb_w32_atomic_or(&(var), (val))
static inline void
rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val)
{
#ifdef _M_IX86
__asm mov eax, var;
__asm mov ecx, val;
__asm lock or [eax], ecx;
#else
#error unsupported architecture
#endif
}
#else
# define RUBY_ATOMIC_OR(var, val) _InterlockedOr(&(var), (val))
#endif
# define RUBY_ATOMIC_EXCHANGE(var, val) InterlockedExchange(&(var), (val))
# define RUBY_ATOMIC_CAS(var, oldval, newval) InterlockedCompareExchange(&(var), (newval), (oldval))
# if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
static inline rb_atomic_t
rb_w32_atomic_cas(volatile rb_atomic_t *var, rb_atomic_t oldval, rb_atomic_t newval)
{
return (rb_atomic_t)InterlockedCompareExchange((PVOID *)var, (PVOID)newval, (PVOID)oldval);
}
# undef RUBY_ATOMIC_CAS
# define RUBY_ATOMIC_CAS(var, oldval, newval) rb_w32_atomic_cas(&(var), (oldval), (newval))
# endif
# ifdef _M_AMD64
# define RUBY_ATOMIC_SIZE_ADD(var, val) InterlockedExchangeAdd64((LONG_LONG *)&(var), (val))
# define RUBY_ATOMIC_SIZE_SUB(var, val) InterlockedExchangeAdd64((LONG_LONG *)&(var), -(LONG)(val))
# define RUBY_ATOMIC_SIZE_INC(var) InterlockedIncrement64(&(var))
# define RUBY_ATOMIC_SIZE_DEC(var) InterlockedDecrement64(&(var))
# define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) InterlockedExchange64(&(var), (val))
# define RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) InterlockedCompareExchange64(&(var), (newval), (oldval))
# else
# define RUBY_ATOMIC_SIZE_ADD(var, val) InterlockedExchangeAdd((LONG *)&(var), (val))
# define RUBY_ATOMIC_SIZE_SUB(var, val) InterlockedExchangeAdd((LONG *)&(var), -(LONG)(val))
# define RUBY_ATOMIC_SIZE_INC(var) InterlockedIncrement((LONG *)&(var))
# define RUBY_ATOMIC_SIZE_DEC(var) InterlockedDecrement((LONG *)&(var))
# define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) InterlockedExchange((LONG *)&(var), (val))
# endif
# ifdef InterlockedExchangePointer
# define RUBY_ATOMIC_PTR_EXCHANGE(var, val) InterlockedExchangePointer((PVOID volatile *)&(var), (PVOID)(val))
# endif /* See below for definitions of other situations */
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
#include <atomic.h>
typedef unsigned int rb_atomic_t;
# define RUBY_ATOMIC_INC(var) atomic_inc_uint(&(var))
# define RUBY_ATOMIC_DEC(var) atomic_dec_uint(&(var))
# define RUBY_ATOMIC_FETCH_ADD(var, val) rb_atomic_fetch_add(&(var), (val))
# define RUBY_ATOMIC_FETCH_SUB(var, val) rb_atomic_fetch_sub(&(var), (val))
# define RUBY_ATOMIC_ADD(var, val) atomic_add_uint(&(var), (val))
# define RUBY_ATOMIC_SUB(var, val) atomic_sub_uint(&(var), (val))
# define RUBY_ATOMIC_OR(var, val) atomic_or_uint(&(var), (val))
# define RUBY_ATOMIC_EXCHANGE(var, val) atomic_swap_uint(&(var), (val))
# define RUBY_ATOMIC_CAS(var, oldval, newval) atomic_cas_uint(&(var), (oldval), (newval))
static inline rb_atomic_t
rb_atomic_fetch_add(volatile rb_atomic_t *var, rb_atomic_t val)
{
return atomic_add_int_nv(var, val) - val;
}
static inline rb_atomic_t
rb_atomic_fetch_sub(volatile rb_atomic_t *var, rb_atomic_t val)
{
return atomic_add_int_nv(var, (rb_atomic_t)(-(int)val)) + val;
}
# if defined(_LP64) || defined(_I32LPx)
# define RUBY_ATOMIC_SIZE_ADD(var, val) atomic_add_long(&(var), (val))
# define RUBY_ATOMIC_SIZE_SUB(var, val) atomic_add_long(&(var), -(val))
# define RUBY_ATOMIC_SIZE_INC(var) atomic_inc_ulong(&(var))
# define RUBY_ATOMIC_SIZE_DEC(var) atomic_dec_ulong(&(var))
# define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) atomic_swap_ulong(&(var), (val))
# define RUBY_ATOMIC_SIZE_CAS(var, oldval, val) atomic_cas_ulong(&(var), (oldval), (val))
# else
# define RUBY_ATOMIC_SIZE_ADD(var, val) atomic_add_int(&(var), (val))
# define RUBY_ATOMIC_SIZE_SUB(var, val) atomic_add_int(&(var), -(val))
# define RUBY_ATOMIC_SIZE_INC(var) atomic_inc_uint(&(var))
# define RUBY_ATOMIC_SIZE_DEC(var) atomic_dec_uint(&(var))
# define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) atomic_swap_uint(&(var), (val))
# endif
#elif defined(__DOXYGEN__)
/**
* Asserts that your environment supports more than one atomic types. These
* days systems tend to have such property (C11 was a standard of decades ago,
* right?) but we still support older ones.
*/
# define RUBY_ATOMIC_GENERIC_MACRO 1
/**
* Type that is eligible for atomic operations. Depending on your host
* platform you might have more than one such type, but we choose one of them
* anyways.
*/
using rb_atomic_t = std::atomic<std::uintptr_t>;
/**
* Atomically replaces the value pointed by `var` with the result of addition
* of `val` to the old value of `var`. In case #RUBY_ATOMIC_GENERIC_MACRO is
* set, this operation could be applied to a signed integer type. However
* there is no portabe way to know what happens on integer overflow on such
* situations. You might better stick to unsigned types.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to add.
* @return What was stored in `var` before the addition.
* @post `var` holds `var + val`.
*/
# define RUBY_ATOMIC_FETCH_ADD(var, val) std::atomic_fetch_add(&(var), val)
/**
* Atomically replaces the value pointed by `var` with the result of addition
* of `val` to the old value of `var`. In case #RUBY_ATOMIC_GENERIC_MACRO is
* set, this operation could be applied to a signed integer type. However
* there is no portabe way to know what happens on integer overflow on such
* situations. You might better stick to unsigned types.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to subtract.
* @return What was stored in `var` before the suntraction.
* @post `var` holds `var - val`.
*/
# define RUBY_ATOMIC_FETCH_SUB(var, val) std::atomic_fetch_sub(&(var), val)
/**
* Atomically replaces the value pointed by `var` with the result of
* bitwise OR between `val` and the old value of `var`.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to mix.
* @return void
* @post `var` holds `var | val`.
* @note For portability, this macro can return void.
*/
# define RUBY_ATOMIC_OR(var, val) (void)std::atomic_fetch_or(&(var), val)
/**
* Atomically replaces the value pointed by `var` with `val`. This is just an
* assignment, but you can additionally know the previous value.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
# define RUBY_ATOMIC_EXCHANGE(var, val) std::atomic_exchange(&(var), (val))
/**
* Atomic compare-and-swap. This stores `val` to `var` if and only if the
* assignment changes the value of `var` from `oldval` to `newval`. You can
* detect whether the assignment happened or not using the return value.
*
* @param var A variable of ::rb_atomic_t.
* @param oldval Expected value of `var` before the assignment.
* @param newval What you want to store at `var`.
* @retval 1 Successful assignment.
* @retval 0 Something different from `oldval` resides at `var`.
*/
# define RUBY_ATOMIC_CAS(var, oldval, newval) \
std::atomic_compare_exchange_strong(&(var), (newval), (oldval))
#else
# error No atomic operation found
#endif
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to set.
* @return void
* @post `var` holds `val`.
*/
#ifndef RUBY_ATOMIC_SET
# define RUBY_ATOMIC_SET(var, val) (void)RUBY_ATOMIC_EXCHANGE(var, val)
#endif
/**
* Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to add.
* @return void
* @post `var` holds `var + val`.
*/
#ifndef RUBY_ATOMIC_ADD
# define RUBY_ATOMIC_ADD(var, val) (void)RUBY_ATOMIC_FETCH_ADD(var, val)
#endif
/**
* Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to subtract.
* @return void
* @post `var` holds `var - val`.
*/
#ifndef RUBY_ATOMIC_SUB
# define RUBY_ATOMIC_SUB(var, val) (void)RUBY_ATOMIC_FETCH_SUB(var, val)
#endif
/**
* Atomically increments the value pointed by `var`.
*
* @param var A variable of ::rb_atomic_t.
* @return void
* @post `var` holds `var + 1`.
*/
#ifndef RUBY_ATOMIC_INC
# define RUBY_ATOMIC_INC(var) RUBY_ATOMIC_ADD(var, 1)
#endif
/**
* Atomically decrements the value pointed by `var`.
*
* @param var A variable of ::rb_atomic_t.
* @return void
* @post `var` holds `var - 1`.
*/
#ifndef RUBY_ATOMIC_DEC
# define RUBY_ATOMIC_DEC(var) RUBY_ATOMIC_SUB(var, 1)
#endif
/**
* Identical to #RUBY_ATOMIC_INC, except it expects its argument is an
* (possibly `_Atomic` qualified) unsigned integer of the same width of
* `size_t`. There are cases where ::rb_atomic_t is 32bit while `size_t` is
* 64bit. This should be used for size related operations to support such
* platforms.
*
* @param var A variable of (possibly _Atomic qualified) `size_t`.
* @return void
* @post `var` holds `var + 1`.
*/
#ifndef RUBY_ATOMIC_SIZE_INC
# define RUBY_ATOMIC_SIZE_INC(var) RUBY_ATOMIC_INC(var)
#endif
/**
* Identical to #RUBY_ATOMIC_DEC, except it expects its argument is an
* (possibly `_Atomic` qualified) unsigned integer of the same width of
* `size_t`. There are cases where ::rb_atomic_t is 32bit while `size_t` is
* 64bit. This should be used for size related operations to support such
* platforms.
*
* @param var A variable of (possibly _Atomic qualified) `size_t`.
* @return void
* @post `var` holds `var - 1`.
*/
#ifndef RUBY_ATOMIC_SIZE_DEC
# define RUBY_ATOMIC_SIZE_DEC(var) RUBY_ATOMIC_DEC(var)
#endif
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
* (possibly `_Atomic` qualified) unsigned integers of the same width of
* `size_t`. There are cases where ::rb_atomic_t is 32bit while `size_t` is
* 64bit. This should be used for size related operations to support such
* platforms.
*
* @param var A variable of (possibly _Atomic qualified) `size_t`.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
#ifndef RUBY_ATOMIC_SIZE_EXCHANGE
# define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) RUBY_ATOMIC_EXCHANGE(var, val)
#endif
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are (possibly
* `_Atomic` qualified) unsigned integers of the same width of `size_t`. There
* are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This should
* be used for size related operations to support such platforms.
*
* @param var A variable of (possibly _Atomic qualified) `size_t`.
* @param oldval Expected value of `var` before the assignment.
* @param val What you want to store at `var`.
* @retval 1 Successful assignment.
* @retval 0 Something different from `oldval` resides at `var`.
*/
#ifndef RUBY_ATOMIC_SIZE_CAS
# define RUBY_ATOMIC_SIZE_CAS(var, oldval, val) RUBY_ATOMIC_CAS(var, oldval, val)
#endif
/**
* Identical to #RUBY_ATOMIC_ADD, except it expects its arguments are (possibly
* `_Atomic` qualified) unsigned integers of the same width of `size_t`. There
* are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This should
* be used for size related operations to support such platforms.
*
* @param var A variable of (possibly _Atomic qualified) `size_t`.
* @param val Value to add.
* @return void
* @post `var` holds `var + val`.
*/
#ifndef RUBY_ATOMIC_SIZE_ADD
# define RUBY_ATOMIC_SIZE_ADD(var, val) RUBY_ATOMIC_ADD(var, val)
#endif
/**
* Identical to #RUBY_ATOMIC_SUB, except it expects its arguments are (possibly
* `_Atomic` qualified) unsigned integers of the same width of `size_t`. There
* are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This should
* be used for size related operations to support such platforms.
*
* @param var A variable of (possibly _Atomic qualified) `size_t`.
* @param val Value to subtract.
* @return void
* @post `var` holds `var - val`.
*/
#ifndef RUBY_ATOMIC_SIZE_SUB
# define RUBY_ATOMIC_SIZE_SUB(var, val) RUBY_ATOMIC_SUB(var, val)
#endif
#if RUBY_ATOMIC_GENERIC_MACRO
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
* (possibly `_Atomic` qualified) unsigned integers of the same width of
* `void*`. There are cases where ::rb_atomic_t is 32bit while `void*` is
* 64bit. This should be used for pointer related operations to support such
* platforms.
*
* @param var A variable of (possibly _Atomic qualified) `void *`.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
# ifndef RUBY_ATOMIC_PTR_EXCHANGE
# define RUBY_ATOMIC_PTR_EXCHANGE(var, val) RUBY_ATOMIC_EXCHANGE(var, val)
# endif
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are (possibly
* `_Atomic` qualified) unsigned integers of the same width of `void*`. There
* are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This should
* be used for size related operations to support such platforms.
*
* @param var A variable of (possibly _Atomic qualified) `void*`.
* @param oldval Expected value of `var` before the assignment.
* @param newval What you want to store at `var`.
* @retval 1 Successful assignment.
* @retval 0 Something different from `oldval` resides at `var`.
*/
# ifndef RUBY_ATOMIC_PTR_CAS
# define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) RUBY_ATOMIC_CAS(var, oldval, newval)
# endif
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
* ::VALUE. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
* 64bit. This should be used for pointer related operations to support such
* platforms.
*
* @param var A variable of ::VALUE.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
# ifndef RUBY_ATOMIC_VALUE_EXCHANGE
# define RUBY_ATOMIC_VALUE_EXCHANGE(var, val) RUBY_ATOMIC_EXCHANGE(var, val)
# endif
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are (possibly
* `_Atomic` qualified) unsigned integers of the same width of `void*`. There
* are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This should
* be used for size related operations to support such platforms.
*
* @param var A variable of (possibly _Atomic qualified) `void*`.
* @param oldval Expected value of `var` before the assignment.
* @param val What you want to store at `var`.
* @retval 1 Successful assignment.
* @retval 0 Something different from `oldval` resides at `var`.
*/
# ifndef RUBY_ATOMIC_VALUE_CAS
# define RUBY_ATOMIC_VALUE_CAS(var, oldval, val) RUBY_ATOMIC_CAS(var, oldval, val)
# endif
#endif
#ifndef RUBY_ATOMIC_PTR_EXCHANGE
# if SIZEOF_VOIDP == SIZEOF_SIZE_T
# define RUBY_ATOMIC_PTR_EXCHANGE(var, val) (void *)RUBY_ATOMIC_SIZE_EXCHANGE(*(size_t *)&(var), (size_t)(val))
# else
# error No atomic exchange for void*
# endif
#endif
#ifndef RUBY_ATOMIC_PTR_CAS
# if SIZEOF_VOIDP == SIZEOF_SIZE_T
# define RUBY_ATOMIC_PTR_CAS(var, oldval, val) (void *)RUBY_ATOMIC_SIZE_CAS(*(size_t *)&(var), (size_t)(oldval), (size_t)(val))
# else
# error No atomic compare-and-set for void*
# endif
#endif
#ifndef RUBY_ATOMIC_VALUE_EXCHANGE
# if SIZEOF_VALUE == SIZEOF_SIZE_T
# define RUBY_ATOMIC_VALUE_EXCHANGE(var, val) RUBY_ATOMIC_SIZE_EXCHANGE(*(size_t *)&(var), (size_t)(val))
# else
# error No atomic exchange for VALUE
# endif
#endif
#ifndef RUBY_ATOMIC_VALUE_CAS
# if SIZEOF_VALUE == SIZEOF_SIZE_T
# define RUBY_ATOMIC_VALUE_CAS(var, oldval, val) RUBY_ATOMIC_SIZE_CAS(*(size_t *)&(var), (size_t)(oldval), (size_t)(val))
# else
# error No atomic compare-and-set for VALUE
# endif
#endif
#endif /* RUBY_ATOMIC_H */
|