blob: 867590391f4d403c697b53ba589a33ad4e4f286f [file] [log] [blame]
Thomas Hellstromfc1ef972009-03-16 11:40:18 +01001/**
2 * Many similar implementations exist. See for example libwsbm
3 * or the linux kernel include/atomic.h
4 *
5 * No copyright claimed on this file.
6 *
7 */
8
José Fonsecabfb4db82014-12-11 22:14:14 +00009#include "no_extern_c.h"
10
José Fonseca2aaca1d2010-02-02 15:18:01 +000011#ifndef U_ATOMIC_H
12#define U_ATOMIC_H
Thomas Hellstromfc1ef972009-03-16 11:40:18 +010013
Matt Turner41b58582014-11-21 16:44:43 -080014#include <stdbool.h>
15
Keith Whitwelleddfad32009-03-18 11:29:01 +000016/* Favor OS-provided implementations.
Keith Whitwell687f3312009-04-17 11:01:22 +010017 *
18 * Where no OS-provided implementation is available, fall back to
19 * locally coded assembly, compiler intrinsic or ultimately a
20 * mutex-based implementation.
Keith Whitwelleddfad32009-03-18 11:29:01 +000021 */
Matt Turner504062b2014-11-21 15:50:58 -080022#if defined(__sun)
Alan Coopersmith78572eb2010-02-05 19:36:42 -080023#define PIPE_ATOMIC_OS_SOLARIS
Matt Turner504062b2014-11-21 15:50:58 -080024#elif defined(_MSC_VER)
José Fonseca57839d12010-02-01 16:12:44 +000025#define PIPE_ATOMIC_MSVC_INTRINSIC
Timothy Arcerie801fbb2014-12-12 20:47:43 +110026#elif defined(__GNUC__)
Matt Turner024db252014-11-21 14:29:41 -080027#define PIPE_ATOMIC_GCC_INTRINSIC
Keith Whitwell687f3312009-04-17 11:01:22 +010028#else
José Fonseca7827bc72010-02-01 14:23:36 +000029#error "Unsupported platform"
Keith Whitwell687f3312009-04-17 11:01:22 +010030#endif
Keith Whitwelleddfad32009-03-18 11:29:01 +000031
32
Keith Whitwelleddfad32009-03-18 11:29:01 +000033/* Implementation using GCC-provided synchronization intrinsics
34 */
Michel Dänzer3b760722009-04-17 17:02:34 +020035#if defined(PIPE_ATOMIC_GCC_INTRINSIC)
Keith Whitwelleddfad32009-03-18 11:29:01 +000036
37#define PIPE_ATOMIC "GCC Sync Intrinsics"
38
José Fonseca38f6f232010-02-02 14:43:48 +000039#define p_atomic_set(_v, _i) (*(_v) = (_i))
40#define p_atomic_read(_v) (*(_v))
Matt Turner6df72e92014-11-21 16:33:40 -080041#define p_atomic_dec_zero(v) (__sync_sub_and_fetch((v), 1) == 0)
42#define p_atomic_inc(v) (void) __sync_add_and_fetch((v), 1)
43#define p_atomic_dec(v) (void) __sync_sub_and_fetch((v), 1)
Carl Worthb16de0b2015-02-05 15:36:59 -080044#define p_atomic_add(v, i) (void) __sync_add_and_fetch((v), (i))
Matt Turner6df72e92014-11-21 16:33:40 -080045#define p_atomic_inc_return(v) __sync_add_and_fetch((v), 1)
46#define p_atomic_dec_return(v) __sync_sub_and_fetch((v), 1)
47#define p_atomic_cmpxchg(v, old, _new) \
48 __sync_val_compare_and_swap((v), (old), (_new))
José Fonsecae0da3332010-02-03 22:15:53 +000049
Keith Whitwelleddfad32009-03-18 11:29:01 +000050#endif
51
52
53
54/* Unlocked version for single threaded environments, such as some
55 * windows kernel modules.
56 */
Keith Whitwell687f3312009-04-17 11:01:22 +010057#if defined(PIPE_ATOMIC_OS_UNLOCKED)
Keith Whitwelleddfad32009-03-18 11:29:01 +000058
59#define PIPE_ATOMIC "Unlocked"
Michal Krol1e23dac2009-03-17 10:54:08 +010060
José Fonseca38f6f232010-02-02 14:43:48 +000061#define p_atomic_set(_v, _i) (*(_v) = (_i))
62#define p_atomic_read(_v) (*(_v))
José Fonsecaa5299e92014-11-25 14:25:28 +000063#define p_atomic_dec_zero(_v) (p_atomic_dec_return(_v) == 0)
64#define p_atomic_inc(_v) ((void) p_atomic_inc_return(_v))
65#define p_atomic_dec(_v) ((void) p_atomic_dec_return(_v))
Carl Worthb16de0b2015-02-05 15:36:59 -080066#define p_atomic_add(_v, _i) (*(_v) = *(_v) + (_i))
José Fonsecaa5299e92014-11-25 14:25:28 +000067#define p_atomic_inc_return(_v) (++(*(_v)))
68#define p_atomic_dec_return(_v) (--(*(_v)))
69#define p_atomic_cmpxchg(_v, _old, _new) (*(_v) == (_old) ? (*(_v) = (_new), (_old)) : *(_v))
Michal Krol1e23dac2009-03-17 10:54:08 +010070
Keith Whitwelleddfad32009-03-18 11:29:01 +000071#endif
72
73
José Fonseca57839d12010-02-01 16:12:44 +000074#if defined(PIPE_ATOMIC_MSVC_INTRINSIC)
Keith Whitwelleddfad32009-03-18 11:29:01 +000075
José Fonseca57839d12010-02-01 16:12:44 +000076#define PIPE_ATOMIC "MSVC Intrinsics"
Michal Krola7d42e12009-03-16 13:07:22 +010077
José Fonsecad7f2dfb2015-01-20 23:34:26 +000078/* We use the Windows header's Interlocked*64 functions instead of the
79 * _Interlocked*64 intrinsics wherever we can, as support for the latter varies
Matt Turner6df72e92014-11-21 16:33:40 -080080 * with target CPU, whereas Windows headers take care of all portability
81 * issues: using intrinsics where available, falling back to library
82 * implementations where not.
83 */
84#ifndef WIN32_LEAN_AND_MEAN
85#define WIN32_LEAN_AND_MEAN 1
José Fonsecae0da3332010-02-03 22:15:53 +000086#endif
Matt Turner6df72e92014-11-21 16:33:40 -080087#include <windows.h>
88#include <intrin.h>
89#include <assert.h>
90
Matt Turner6df72e92014-11-21 16:33:40 -080091/* MSVC supports decltype keyword, but it's only supported on C++ and doesn't
92 * quite work here; and if a C++-only solution is worthwhile, then it would be
93 * better to use templates / function overloading, instead of decltype magic.
94 * Therefore, we rely on implicit casting to LONGLONG for the functions that return
95 */
José Fonsecae0da3332010-02-03 22:15:53 +000096
José Fonseca38f6f232010-02-02 14:43:48 +000097#define p_atomic_set(_v, _i) (*(_v) = (_i))
98#define p_atomic_read(_v) (*(_v))
Michal Krola7d42e12009-03-16 13:07:22 +010099
Matt Turner6df72e92014-11-21 16:33:40 -0800100#define p_atomic_dec_zero(_v) \
101 (p_atomic_dec_return(_v) == 0)
Michal Krola7d42e12009-03-16 13:07:22 +0100102
Matt Turner6df72e92014-11-21 16:33:40 -0800103#define p_atomic_inc(_v) \
104 ((void) p_atomic_inc_return(_v))
Michal Krola7d42e12009-03-16 13:07:22 +0100105
Matt Turner6df72e92014-11-21 16:33:40 -0800106#define p_atomic_inc_return(_v) (\
José Fonsecad7f2dfb2015-01-20 23:34:26 +0000107 sizeof *(_v) == sizeof(short) ? _InterlockedIncrement16((short *) (_v)) : \
108 sizeof *(_v) == sizeof(long) ? _InterlockedIncrement ((long *) (_v)) : \
109 sizeof *(_v) == sizeof(__int64) ? InterlockedIncrement64 ((__int64 *)(_v)) : \
Matt Turner6df72e92014-11-21 16:33:40 -0800110 (assert(!"should not get here"), 0))
Christoph Bumillercb491322014-11-17 20:05:53 +0100111
Matt Turner6df72e92014-11-21 16:33:40 -0800112#define p_atomic_dec(_v) \
113 ((void) p_atomic_dec_return(_v))
Michal Krola7d42e12009-03-16 13:07:22 +0100114
Matt Turner6df72e92014-11-21 16:33:40 -0800115#define p_atomic_dec_return(_v) (\
José Fonsecad7f2dfb2015-01-20 23:34:26 +0000116 sizeof *(_v) == sizeof(short) ? _InterlockedDecrement16((short *) (_v)) : \
117 sizeof *(_v) == sizeof(long) ? _InterlockedDecrement ((long *) (_v)) : \
118 sizeof *(_v) == sizeof(__int64) ? InterlockedDecrement64 ((__int64 *)(_v)) : \
Matt Turner6df72e92014-11-21 16:33:40 -0800119 (assert(!"should not get here"), 0))
Christoph Bumillercb491322014-11-17 20:05:53 +0100120
Carl Worthb16de0b2015-02-05 15:36:59 -0800121#define p_atomic_add(_v, _i) (\
122 sizeof *(_v) == sizeof(char) ? _InterlockedExchangeAdd8 ((char *) (_v), (_i)) : \
123 sizeof *(_v) == sizeof(short) ? _InterlockedExchangeAdd16((short *) (_v), (_i)) : \
124 sizeof *(_v) == sizeof(long) ? _InterlockedExchangeAdd ((long *) (_v), (_i)) : \
125 sizeof *(_v) == sizeof(__int64) ? InterlockedExchangeAdd64((__int64 *)(_v), (_i)) : \
126 (assert(!"should not get here"), 0))
127
Matt Turner6df72e92014-11-21 16:33:40 -0800128#define p_atomic_cmpxchg(_v, _old, _new) (\
José Fonsecad7f2dfb2015-01-20 23:34:26 +0000129 sizeof *(_v) == sizeof(char) ? _InterlockedCompareExchange8 ((char *) (_v), (char) (_new), (char) (_old)) : \
130 sizeof *(_v) == sizeof(short) ? _InterlockedCompareExchange16((short *) (_v), (short) (_new), (short) (_old)) : \
131 sizeof *(_v) == sizeof(long) ? _InterlockedCompareExchange ((long *) (_v), (long) (_new), (long) (_old)) : \
132 sizeof *(_v) == sizeof(__int64) ? InterlockedCompareExchange64 ((__int64 *)(_v), (__int64)(_new), (__int64)(_old)) : \
Matt Turner6df72e92014-11-21 16:33:40 -0800133 (assert(!"should not get here"), 0))
José Fonsecae0da3332010-02-03 22:15:53 +0000134
Keith Whitwelleddfad32009-03-18 11:29:01 +0000135#endif
136
Alan Coopersmith78572eb2010-02-05 19:36:42 -0800137#if defined(PIPE_ATOMIC_OS_SOLARIS)
138
139#define PIPE_ATOMIC "Solaris OS atomic functions"
140
141#include <atomic.h>
Matt Turner6df72e92014-11-21 16:33:40 -0800142#include <assert.h>
Alan Coopersmith78572eb2010-02-05 19:36:42 -0800143
144#define p_atomic_set(_v, _i) (*(_v) = (_i))
145#define p_atomic_read(_v) (*(_v))
146
Matt Turner6df72e92014-11-21 16:33:40 -0800147#define p_atomic_dec_zero(v) (\
148 sizeof(*v) == sizeof(uint8_t) ? atomic_dec_8_nv ((uint8_t *)(v)) == 0 : \
149 sizeof(*v) == sizeof(uint16_t) ? atomic_dec_16_nv((uint16_t *)(v)) == 0 : \
150 sizeof(*v) == sizeof(uint32_t) ? atomic_dec_32_nv((uint32_t *)(v)) == 0 : \
151 sizeof(*v) == sizeof(uint64_t) ? atomic_dec_64_nv((uint64_t *)(v)) == 0 : \
152 (assert(!"should not get here"), 0))
Alan Coopersmith78572eb2010-02-05 19:36:42 -0800153
Matt Turner6df72e92014-11-21 16:33:40 -0800154#define p_atomic_inc(v) (void) (\
155 sizeof(*v) == sizeof(uint8_t) ? atomic_inc_8 ((uint8_t *)(v)) : \
156 sizeof(*v) == sizeof(uint16_t) ? atomic_inc_16((uint16_t *)(v)) : \
157 sizeof(*v) == sizeof(uint32_t) ? atomic_inc_32((uint32_t *)(v)) : \
158 sizeof(*v) == sizeof(uint64_t) ? atomic_inc_64((uint64_t *)(v)) : \
159 (assert(!"should not get here"), 0))
Alan Coopersmith78572eb2010-02-05 19:36:42 -0800160
Alan Coopersmith4671dca2015-02-15 16:19:06 -0800161#define p_atomic_inc_return(v) ((__typeof(*v)) \
Matt Turner6df72e92014-11-21 16:33:40 -0800162 sizeof(*v) == sizeof(uint8_t) ? atomic_inc_8_nv ((uint8_t *)(v)) : \
163 sizeof(*v) == sizeof(uint16_t) ? atomic_inc_16_nv((uint16_t *)(v)) : \
164 sizeof(*v) == sizeof(uint32_t) ? atomic_inc_32_nv((uint32_t *)(v)) : \
165 sizeof(*v) == sizeof(uint64_t) ? atomic_inc_64_nv((uint64_t *)(v)) : \
166 (assert(!"should not get here"), 0))
Alan Coopersmith78572eb2010-02-05 19:36:42 -0800167
Matt Turner6df72e92014-11-21 16:33:40 -0800168#define p_atomic_dec(v) ((void) \
169 sizeof(*v) == sizeof(uint8_t) ? atomic_dec_8 ((uint8_t *)(v)) : \
170 sizeof(*v) == sizeof(uint16_t) ? atomic_dec_16((uint16_t *)(v)) : \
171 sizeof(*v) == sizeof(uint32_t) ? atomic_dec_32((uint32_t *)(v)) : \
172 sizeof(*v) == sizeof(uint64_t) ? atomic_dec_64((uint64_t *)(v)) : \
173 (assert(!"should not get here"), 0))
Alan Coopersmith78572eb2010-02-05 19:36:42 -0800174
Alan Coopersmith4671dca2015-02-15 16:19:06 -0800175#define p_atomic_dec_return(v) ((__typeof(*v)) \
Matt Turner6df72e92014-11-21 16:33:40 -0800176 sizeof(*v) == sizeof(uint8_t) ? atomic_dec_8_nv ((uint8_t *)(v)) : \
177 sizeof(*v) == sizeof(uint16_t) ? atomic_dec_16_nv((uint16_t *)(v)) : \
178 sizeof(*v) == sizeof(uint32_t) ? atomic_dec_32_nv((uint32_t *)(v)) : \
179 sizeof(*v) == sizeof(uint64_t) ? atomic_dec_64_nv((uint64_t *)(v)) : \
180 (assert(!"should not get here"), 0))
181
Carl Worthb16de0b2015-02-05 15:36:59 -0800182#define p_atomic_add(v, i) ((void) \
183 sizeof(*v) == sizeof(uint8_t) ? atomic_add_8 ((uint8_t *)(v), (i)) : \
184 sizeof(*v) == sizeof(uint16_t) ? atomic_add_16((uint16_t *)(v), (i)) : \
185 sizeof(*v) == sizeof(uint32_t) ? atomic_add_32((uint32_t *)(v), (i)) : \
186 sizeof(*v) == sizeof(uint64_t) ? atomic_add_64((uint64_t *)(v), (i)) : \
187 (assert(!"should not get here"), 0))
188
Alan Coopersmith4671dca2015-02-15 16:19:06 -0800189#define p_atomic_cmpxchg(v, old, _new) ((__typeof(*v)) \
Matt Turner6df72e92014-11-21 16:33:40 -0800190 sizeof(*v) == sizeof(uint8_t) ? atomic_cas_8 ((uint8_t *)(v), (uint8_t )(old), (uint8_t )(_new)) : \
191 sizeof(*v) == sizeof(uint16_t) ? atomic_cas_16((uint16_t *)(v), (uint16_t)(old), (uint16_t)(_new)) : \
192 sizeof(*v) == sizeof(uint32_t) ? atomic_cas_32((uint32_t *)(v), (uint32_t)(old), (uint32_t)(_new)) : \
193 sizeof(*v) == sizeof(uint64_t) ? atomic_cas_64((uint64_t *)(v), (uint64_t)(old), (uint64_t)(_new)) : \
194 (assert(!"should not get here"), 0))
Alan Coopersmith78572eb2010-02-05 19:36:42 -0800195
196#endif
Keith Whitwelleddfad32009-03-18 11:29:01 +0000197
Keith Whitwelleddfad32009-03-18 11:29:01 +0000198#ifndef PIPE_ATOMIC
199#error "No pipe_atomic implementation selected"
200#endif
201
202
Thomas Hellstromfc1ef972009-03-16 11:40:18 +0100203
José Fonseca2aaca1d2010-02-02 15:18:01 +0000204#endif /* U_ATOMIC_H */