util: Use stdbool.h's bool rather than "boolean".
[mesa.git] / src / util / u_atomic.h
1 /**
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
9 #ifndef U_ATOMIC_H
10 #define U_ATOMIC_H
11
12 #include <stdbool.h>
13
14 /* Favor OS-provided implementations.
15 *
16 * Where no OS-provided implementation is available, fall back to
17 * locally coded assembly, compiler intrinsic or ultimately a
18 * mutex-based implementation.
19 */
20 #if defined(__sun)
21 #define PIPE_ATOMIC_OS_SOLARIS
22 #elif defined(_MSC_VER)
23 #define PIPE_ATOMIC_MSVC_INTRINSIC
24 #elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 401)
25 #define PIPE_ATOMIC_GCC_INTRINSIC
26 #else
27 #error "Unsupported platform"
28 #endif
29
30
31 /* Implementation using GCC-provided synchronization intrinsics
32 */
33 #if defined(PIPE_ATOMIC_GCC_INTRINSIC)
34
35 #define PIPE_ATOMIC "GCC Sync Intrinsics"
36
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40
41 #define p_atomic_set(_v, _i) (*(_v) = (_i))
42 #define p_atomic_read(_v) (*(_v))
43
44 static inline boolean
45 p_atomic_dec_zero(int32_t *v)
46 {
47 return (__sync_sub_and_fetch(v, 1) == 0);
48 }
49
50 static inline void
51 p_atomic_inc(int32_t *v)
52 {
53 (void) __sync_add_and_fetch(v, 1);
54 }
55
56 static inline void
57 p_atomic_dec(int32_t *v)
58 {
59 (void) __sync_sub_and_fetch(v, 1);
60 }
61
62 static inline int32_t
63 p_atomic_inc_return(int32_t *v)
64 {
65 return __sync_add_and_fetch(v, 1);
66 }
67
68 static inline int32_t
69 p_atomic_dec_return(int32_t *v)
70 {
71 return __sync_sub_and_fetch(v, 1);
72 }
73
74 static inline int32_t
75 p_atomic_cmpxchg(int32_t *v, int32_t old, int32_t _new)
76 {
77 return __sync_val_compare_and_swap(v, old, _new);
78 }
79
80 #ifdef __cplusplus
81 }
82 #endif
83
84 #endif
85
86
87
88 /* Unlocked version for single threaded environments, such as some
89 * windows kernel modules.
90 */
91 #if defined(PIPE_ATOMIC_OS_UNLOCKED)
92
93 #define PIPE_ATOMIC "Unlocked"
94
95 #define p_atomic_set(_v, _i) (*(_v) = (_i))
96 #define p_atomic_read(_v) (*(_v))
97 #define p_atomic_dec_zero(_v) ((bool) --(*(_v)))
98 #define p_atomic_inc(_v) ((void) (*(_v))++)
99 #define p_atomic_dec(_v) ((void) (*(_v))--)
100 #define p_atomic_inc_return(_v) ((*(_v))++)
101 #define p_atomic_dec_return(_v) ((*(_v))--)
102 #define p_atomic_cmpxchg(_v, old, _new) (*(_v) == old ? *(_v) = (_new) : *(_v))
103
104 #endif
105
106
107 #if defined(PIPE_ATOMIC_MSVC_INTRINSIC)
108
109 #define PIPE_ATOMIC "MSVC Intrinsics"
110
111 #include <intrin.h>
112
113 #pragma intrinsic(_InterlockedIncrement)
114 #pragma intrinsic(_InterlockedDecrement)
115 #pragma intrinsic(_InterlockedCompareExchange)
116
117 #ifdef __cplusplus
118 extern "C" {
119 #endif
120
121 #define p_atomic_set(_v, _i) (*(_v) = (_i))
122 #define p_atomic_read(_v) (*(_v))
123
124 static inline bool
125 p_atomic_dec_zero(int32_t *v)
126 {
127 return _InterlockedDecrement((long *)v) == 0;
128 }
129
130 static inline void
131 p_atomic_inc(int32_t *v)
132 {
133 _InterlockedIncrement((long *)v);
134 }
135
136 static inline int32_t
137 p_atomic_inc_return(int32_t *v)
138 {
139 return _InterlockedIncrement((long *)v);
140 }
141
142 static inline void
143 p_atomic_dec(int32_t *v)
144 {
145 _InterlockedDecrement((long *)v);
146 }
147
148 static inline int32_t
149 p_atomic_dec_return(int32_t *v)
150 {
151 return _InterlockedDecrement((long *)v);
152 }
153
154 static inline int32_t
155 p_atomic_cmpxchg(int32_t *v, int32_t old, int32_t _new)
156 {
157 return _InterlockedCompareExchange((long *)v, _new, old);
158 }
159
160 #ifdef __cplusplus
161 }
162 #endif
163
164 #endif
165
166 #if defined(PIPE_ATOMIC_OS_SOLARIS)
167
168 #define PIPE_ATOMIC "Solaris OS atomic functions"
169
170 #include <atomic.h>
171
172 #ifdef __cplusplus
173 extern "C" {
174 #endif
175
176 #define p_atomic_set(_v, _i) (*(_v) = (_i))
177 #define p_atomic_read(_v) (*(_v))
178
179 static inline bool
180 p_atomic_dec_zero(int32_t *v)
181 {
182 uint32_t n = atomic_dec_32_nv((uint32_t *) v);
183
184 return n != 0;
185 }
186
187 #define p_atomic_inc(_v) atomic_inc_32((uint32_t *) _v)
188 #define p_atomic_dec(_v) atomic_dec_32((uint32_t *) _v)
189 #define p_atomic_inc_return(_v) atomic_inc_32_nv((uint32_t *) _v)
190 #define p_atomic_dec_return(_v) atomic_dec_32_nv((uint32_t *) _v)
191
192 #define p_atomic_cmpxchg(_v, _old, _new) \
193 atomic_cas_32( (uint32_t *) _v, (uint32_t) _old, (uint32_t) _new)
194
195 #ifdef __cplusplus
196 }
197 #endif
198
199 #endif
200
201
202 #ifndef PIPE_ATOMIC
203 #error "No pipe_atomic implementation selected"
204 #endif
205
206
207
208 #endif /* U_ATOMIC_H */