Public headers: use SPDX identifiers
[urcu.git] / include / urcu / uatomic / generic.h
... / ...
CommitLineData
1// SPDX-FileCopyrightText: 1991-1994 by Xerox Corporation. All rights reserved.
2// SPDX-FileCopyrightText: 1996-1999 by Silicon Graphics. All rights reserved.
3// SPDX-FileCopyrightText: 1999-2004 Hewlett-Packard Development Company, L.P.
4// SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5// SPDX-FileCopyrightText: 2010 Paolo Bonzini
6//
7// SPDX-License-Identifier: LicenseRef-Boehm-GC
8
9#ifndef _URCU_UATOMIC_GENERIC_H
10#define _URCU_UATOMIC_GENERIC_H
11
12/*
13 * Code inspired from libuatomic_ops-1.2, inherited in part from the
14 * Boehm-Demers-Weiser conservative garbage collector.
15 */
16
17#include <stdint.h>
18#include <urcu/compiler.h>
19#include <urcu/system.h>
20
21#ifdef __cplusplus
22extern "C" {
23#endif
24
25#ifndef uatomic_set
26#define uatomic_set(addr, v) ((void) CMM_STORE_SHARED(*(addr), (v)))
27#endif
28
29#ifndef uatomic_read
30#define uatomic_read(addr) CMM_LOAD_SHARED(*(addr))
31#endif
32
33#if !defined __OPTIMIZE__ || defined UATOMIC_NO_LINK_ERROR
34#ifdef ILLEGAL_INSTR
35static inline __attribute__((always_inline))
36void _uatomic_link_error(void)
37{
38 /*
39 * generate an illegal instruction. Cannot catch this with
40 * linker tricks when optimizations are disabled.
41 */
42 __asm__ __volatile__(ILLEGAL_INSTR);
43}
44#else
45static inline __attribute__((always_inline, __noreturn__))
46void _uatomic_link_error(void)
47{
48 __builtin_trap();
49}
50#endif
51
52#else /* #if !defined __OPTIMIZE__ || defined UATOMIC_NO_LINK_ERROR */
53extern void _uatomic_link_error(void);
54#endif /* #else #if !defined __OPTIMIZE__ || defined UATOMIC_NO_LINK_ERROR */
55
56/* cmpxchg */
57
58#ifndef uatomic_cmpxchg
59static inline __attribute__((always_inline))
60unsigned long _uatomic_cmpxchg(void *addr, unsigned long old,
61 unsigned long _new, int len)
62{
63 switch (len) {
64#ifdef UATOMIC_HAS_ATOMIC_BYTE
65 case 1:
66 return __sync_val_compare_and_swap_1((uint8_t *) addr, old,
67 _new);
68#endif
69#ifdef UATOMIC_HAS_ATOMIC_SHORT
70 case 2:
71 return __sync_val_compare_and_swap_2((uint16_t *) addr, old,
72 _new);
73#endif
74 case 4:
75 return __sync_val_compare_and_swap_4((uint32_t *) addr, old,
76 _new);
77#if (CAA_BITS_PER_LONG == 64)
78 case 8:
79 return __sync_val_compare_and_swap_8((uint64_t *) addr, old,
80 _new);
81#endif
82 }
83 _uatomic_link_error();
84 return 0;
85}
86
87
88#define uatomic_cmpxchg(addr, old, _new) \
89 ((__typeof__(*(addr))) _uatomic_cmpxchg((addr), \
90 caa_cast_long_keep_sign(old), \
91 caa_cast_long_keep_sign(_new),\
92 sizeof(*(addr))))
93
94
95/* uatomic_and */
96
97#ifndef uatomic_and
98static inline __attribute__((always_inline))
99void _uatomic_and(void *addr, unsigned long val,
100 int len)
101{
102 switch (len) {
103#ifdef UATOMIC_HAS_ATOMIC_BYTE
104 case 1:
105 __sync_and_and_fetch_1((uint8_t *) addr, val);
106 return;
107#endif
108#ifdef UATOMIC_HAS_ATOMIC_SHORT
109 case 2:
110 __sync_and_and_fetch_2((uint16_t *) addr, val);
111 return;
112#endif
113 case 4:
114 __sync_and_and_fetch_4((uint32_t *) addr, val);
115 return;
116#if (CAA_BITS_PER_LONG == 64)
117 case 8:
118 __sync_and_and_fetch_8((uint64_t *) addr, val);
119 return;
120#endif
121 }
122 _uatomic_link_error();
123}
124
125#define uatomic_and(addr, v) \
126 (_uatomic_and((addr), \
127 caa_cast_long_keep_sign(v), \
128 sizeof(*(addr))))
129#define cmm_smp_mb__before_uatomic_and() cmm_barrier()
130#define cmm_smp_mb__after_uatomic_and() cmm_barrier()
131
132#endif
133
134/* uatomic_or */
135
136#ifndef uatomic_or
137static inline __attribute__((always_inline))
138void _uatomic_or(void *addr, unsigned long val,
139 int len)
140{
141 switch (len) {
142#ifdef UATOMIC_HAS_ATOMIC_BYTE
143 case 1:
144 __sync_or_and_fetch_1((uint8_t *) addr, val);
145 return;
146#endif
147#ifdef UATOMIC_HAS_ATOMIC_SHORT
148 case 2:
149 __sync_or_and_fetch_2((uint16_t *) addr, val);
150 return;
151#endif
152 case 4:
153 __sync_or_and_fetch_4((uint32_t *) addr, val);
154 return;
155#if (CAA_BITS_PER_LONG == 64)
156 case 8:
157 __sync_or_and_fetch_8((uint64_t *) addr, val);
158 return;
159#endif
160 }
161 _uatomic_link_error();
162 return;
163}
164
165#define uatomic_or(addr, v) \
166 (_uatomic_or((addr), \
167 caa_cast_long_keep_sign(v), \
168 sizeof(*(addr))))
169#define cmm_smp_mb__before_uatomic_or() cmm_barrier()
170#define cmm_smp_mb__after_uatomic_or() cmm_barrier()
171
172#endif
173
174
175/* uatomic_add_return */
176
177#ifndef uatomic_add_return
178static inline __attribute__((always_inline))
179unsigned long _uatomic_add_return(void *addr, unsigned long val,
180 int len)
181{
182 switch (len) {
183#ifdef UATOMIC_HAS_ATOMIC_BYTE
184 case 1:
185 return __sync_add_and_fetch_1((uint8_t *) addr, val);
186#endif
187#ifdef UATOMIC_HAS_ATOMIC_SHORT
188 case 2:
189 return __sync_add_and_fetch_2((uint16_t *) addr, val);
190#endif
191 case 4:
192 return __sync_add_and_fetch_4((uint32_t *) addr, val);
193#if (CAA_BITS_PER_LONG == 64)
194 case 8:
195 return __sync_add_and_fetch_8((uint64_t *) addr, val);
196#endif
197 }
198 _uatomic_link_error();
199 return 0;
200}
201
202
203#define uatomic_add_return(addr, v) \
204 ((__typeof__(*(addr))) _uatomic_add_return((addr), \
205 caa_cast_long_keep_sign(v), \
206 sizeof(*(addr))))
207#endif /* #ifndef uatomic_add_return */
208
209#ifndef uatomic_xchg
210/* xchg */
211
212static inline __attribute__((always_inline))
213unsigned long _uatomic_exchange(void *addr, unsigned long val, int len)
214{
215 switch (len) {
216#ifdef UATOMIC_HAS_ATOMIC_BYTE
217 case 1:
218 {
219 uint8_t old;
220
221 do {
222 old = uatomic_read((uint8_t *) addr);
223 } while (!__sync_bool_compare_and_swap_1((uint8_t *) addr,
224 old, val));
225
226 return old;
227 }
228#endif
229#ifdef UATOMIC_HAS_ATOMIC_SHORT
230 case 2:
231 {
232 uint16_t old;
233
234 do {
235 old = uatomic_read((uint16_t *) addr);
236 } while (!__sync_bool_compare_and_swap_2((uint16_t *) addr,
237 old, val));
238
239 return old;
240 }
241#endif
242 case 4:
243 {
244 uint32_t old;
245
246 do {
247 old = uatomic_read((uint32_t *) addr);
248 } while (!__sync_bool_compare_and_swap_4((uint32_t *) addr,
249 old, val));
250
251 return old;
252 }
253#if (CAA_BITS_PER_LONG == 64)
254 case 8:
255 {
256 uint64_t old;
257
258 do {
259 old = uatomic_read((uint64_t *) addr);
260 } while (!__sync_bool_compare_and_swap_8((uint64_t *) addr,
261 old, val));
262
263 return old;
264 }
265#endif
266 }
267 _uatomic_link_error();
268 return 0;
269}
270
271#define uatomic_xchg(addr, v) \
272 ((__typeof__(*(addr))) _uatomic_exchange((addr), \
273 caa_cast_long_keep_sign(v), \
274 sizeof(*(addr))))
275#endif /* #ifndef uatomic_xchg */
276
277#else /* #ifndef uatomic_cmpxchg */
278
279#ifndef uatomic_and
280/* uatomic_and */
281
282static inline __attribute__((always_inline))
283void _uatomic_and(void *addr, unsigned long val, int len)
284{
285 switch (len) {
286#ifdef UATOMIC_HAS_ATOMIC_BYTE
287 case 1:
288 {
289 uint8_t old, oldt;
290
291 oldt = uatomic_read((uint8_t *) addr);
292 do {
293 old = oldt;
294 oldt = _uatomic_cmpxchg(addr, old, old & val, 1);
295 } while (oldt != old);
296
297 return;
298 }
299#endif
300#ifdef UATOMIC_HAS_ATOMIC_SHORT
301 case 2:
302 {
303 uint16_t old, oldt;
304
305 oldt = uatomic_read((uint16_t *) addr);
306 do {
307 old = oldt;
308 oldt = _uatomic_cmpxchg(addr, old, old & val, 2);
309 } while (oldt != old);
310 }
311#endif
312 case 4:
313 {
314 uint32_t old, oldt;
315
316 oldt = uatomic_read((uint32_t *) addr);
317 do {
318 old = oldt;
319 oldt = _uatomic_cmpxchg(addr, old, old & val, 4);
320 } while (oldt != old);
321
322 return;
323 }
324#if (CAA_BITS_PER_LONG == 64)
325 case 8:
326 {
327 uint64_t old, oldt;
328
329 oldt = uatomic_read((uint64_t *) addr);
330 do {
331 old = oldt;
332 oldt = _uatomic_cmpxchg(addr, old, old & val, 8);
333 } while (oldt != old);
334
335 return;
336 }
337#endif
338 }
339 _uatomic_link_error();
340}
341
342#define uatomic_and(addr, v) \
343 (_uatomic_and((addr), \
344 caa_cast_long_keep_sign(v), \
345 sizeof(*(addr))))
346#define cmm_smp_mb__before_uatomic_and() cmm_barrier()
347#define cmm_smp_mb__after_uatomic_and() cmm_barrier()
348
349#endif /* #ifndef uatomic_and */
350
351#ifndef uatomic_or
352/* uatomic_or */
353
354static inline __attribute__((always_inline))
355void _uatomic_or(void *addr, unsigned long val, int len)
356{
357 switch (len) {
358#ifdef UATOMIC_HAS_ATOMIC_BYTE
359 case 1:
360 {
361 uint8_t old, oldt;
362
363 oldt = uatomic_read((uint8_t *) addr);
364 do {
365 old = oldt;
366 oldt = _uatomic_cmpxchg(addr, old, old | val, 1);
367 } while (oldt != old);
368
369 return;
370 }
371#endif
372#ifdef UATOMIC_HAS_ATOMIC_SHORT
373 case 2:
374 {
375 uint16_t old, oldt;
376
377 oldt = uatomic_read((uint16_t *) addr);
378 do {
379 old = oldt;
380 oldt = _uatomic_cmpxchg(addr, old, old | val, 2);
381 } while (oldt != old);
382
383 return;
384 }
385#endif
386 case 4:
387 {
388 uint32_t old, oldt;
389
390 oldt = uatomic_read((uint32_t *) addr);
391 do {
392 old = oldt;
393 oldt = _uatomic_cmpxchg(addr, old, old | val, 4);
394 } while (oldt != old);
395
396 return;
397 }
398#if (CAA_BITS_PER_LONG == 64)
399 case 8:
400 {
401 uint64_t old, oldt;
402
403 oldt = uatomic_read((uint64_t *) addr);
404 do {
405 old = oldt;
406 oldt = _uatomic_cmpxchg(addr, old, old | val, 8);
407 } while (oldt != old);
408
409 return;
410 }
411#endif
412 }
413 _uatomic_link_error();
414}
415
416#define uatomic_or(addr, v) \
417 (_uatomic_or((addr), \
418 caa_cast_long_keep_sign(v), \
419 sizeof(*(addr))))
420#define cmm_smp_mb__before_uatomic_or() cmm_barrier()
421#define cmm_smp_mb__after_uatomic_or() cmm_barrier()
422
423#endif /* #ifndef uatomic_or */
424
425#ifndef uatomic_add_return
426/* uatomic_add_return */
427
428static inline __attribute__((always_inline))
429unsigned long _uatomic_add_return(void *addr, unsigned long val, int len)
430{
431 switch (len) {
432#ifdef UATOMIC_HAS_ATOMIC_BYTE
433 case 1:
434 {
435 uint8_t old, oldt;
436
437 oldt = uatomic_read((uint8_t *) addr);
438 do {
439 old = oldt;
440 oldt = uatomic_cmpxchg((uint8_t *) addr,
441 old, old + val);
442 } while (oldt != old);
443
444 return old + val;
445 }
446#endif
447#ifdef UATOMIC_HAS_ATOMIC_SHORT
448 case 2:
449 {
450 uint16_t old, oldt;
451
452 oldt = uatomic_read((uint16_t *) addr);
453 do {
454 old = oldt;
455 oldt = uatomic_cmpxchg((uint16_t *) addr,
456 old, old + val);
457 } while (oldt != old);
458
459 return old + val;
460 }
461#endif
462 case 4:
463 {
464 uint32_t old, oldt;
465
466 oldt = uatomic_read((uint32_t *) addr);
467 do {
468 old = oldt;
469 oldt = uatomic_cmpxchg((uint32_t *) addr,
470 old, old + val);
471 } while (oldt != old);
472
473 return old + val;
474 }
475#if (CAA_BITS_PER_LONG == 64)
476 case 8:
477 {
478 uint64_t old, oldt;
479
480 oldt = uatomic_read((uint64_t *) addr);
481 do {
482 old = oldt;
483 oldt = uatomic_cmpxchg((uint64_t *) addr,
484 old, old + val);
485 } while (oldt != old);
486
487 return old + val;
488 }
489#endif
490 }
491 _uatomic_link_error();
492 return 0;
493}
494
495#define uatomic_add_return(addr, v) \
496 ((__typeof__(*(addr))) _uatomic_add_return((addr), \
497 caa_cast_long_keep_sign(v), \
498 sizeof(*(addr))))
499#endif /* #ifndef uatomic_add_return */
500
501#ifndef uatomic_xchg
502/* xchg */
503
504static inline __attribute__((always_inline))
505unsigned long _uatomic_exchange(void *addr, unsigned long val, int len)
506{
507 switch (len) {
508#ifdef UATOMIC_HAS_ATOMIC_BYTE
509 case 1:
510 {
511 uint8_t old, oldt;
512
513 oldt = uatomic_read((uint8_t *) addr);
514 do {
515 old = oldt;
516 oldt = uatomic_cmpxchg((uint8_t *) addr,
517 old, val);
518 } while (oldt != old);
519
520 return old;
521 }
522#endif
523#ifdef UATOMIC_HAS_ATOMIC_SHORT
524 case 2:
525 {
526 uint16_t old, oldt;
527
528 oldt = uatomic_read((uint16_t *) addr);
529 do {
530 old = oldt;
531 oldt = uatomic_cmpxchg((uint16_t *) addr,
532 old, val);
533 } while (oldt != old);
534
535 return old;
536 }
537#endif
538 case 4:
539 {
540 uint32_t old, oldt;
541
542 oldt = uatomic_read((uint32_t *) addr);
543 do {
544 old = oldt;
545 oldt = uatomic_cmpxchg((uint32_t *) addr,
546 old, val);
547 } while (oldt != old);
548
549 return old;
550 }
551#if (CAA_BITS_PER_LONG == 64)
552 case 8:
553 {
554 uint64_t old, oldt;
555
556 oldt = uatomic_read((uint64_t *) addr);
557 do {
558 old = oldt;
559 oldt = uatomic_cmpxchg((uint64_t *) addr,
560 old, val);
561 } while (oldt != old);
562
563 return old;
564 }
565#endif
566 }
567 _uatomic_link_error();
568 return 0;
569}
570
571#define uatomic_xchg(addr, v) \
572 ((__typeof__(*(addr))) _uatomic_exchange((addr), \
573 caa_cast_long_keep_sign(v), \
574 sizeof(*(addr))))
575#endif /* #ifndef uatomic_xchg */
576
577#endif /* #else #ifndef uatomic_cmpxchg */
578
579/* uatomic_sub_return, uatomic_add, uatomic_sub, uatomic_inc, uatomic_dec */
580
581#ifndef uatomic_add
582#define uatomic_add(addr, v) (void)uatomic_add_return((addr), (v))
583#define cmm_smp_mb__before_uatomic_add() cmm_barrier()
584#define cmm_smp_mb__after_uatomic_add() cmm_barrier()
585#endif
586
587#define uatomic_sub_return(addr, v) \
588 uatomic_add_return((addr), -(caa_cast_long_keep_sign(v)))
589#define uatomic_sub(addr, v) \
590 uatomic_add((addr), -(caa_cast_long_keep_sign(v)))
591#define cmm_smp_mb__before_uatomic_sub() cmm_smp_mb__before_uatomic_add()
592#define cmm_smp_mb__after_uatomic_sub() cmm_smp_mb__after_uatomic_add()
593
594#ifndef uatomic_inc
595#define uatomic_inc(addr) uatomic_add((addr), 1)
596#define cmm_smp_mb__before_uatomic_inc() cmm_smp_mb__before_uatomic_add()
597#define cmm_smp_mb__after_uatomic_inc() cmm_smp_mb__after_uatomic_add()
598#endif
599
600#ifndef uatomic_dec
601#define uatomic_dec(addr) uatomic_add((addr), -1)
602#define cmm_smp_mb__before_uatomic_dec() cmm_smp_mb__before_uatomic_add()
603#define cmm_smp_mb__after_uatomic_dec() cmm_smp_mb__after_uatomic_add()
604#endif
605
606#ifdef __cplusplus
607}
608#endif
609
610#endif /* _URCU_UATOMIC_GENERIC_H */
This page took 0.023404 seconds and 4 git commands to generate.