base: add atomic init, load and store macros
[heimdal.git] / lib / base / heimbase-atomics.h
blob7d55202fd15abd1c93868265129e379567ba8082
1 /*
2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #ifndef HEIM_BASE_ATOMICS_H
37 #define HEIM_BASE_ATOMICS_H 1
39 #include "config.h"
42 * Atomic operations
45 #if defined(HAVE_STDATOMIC_H)
47 #include <stdatomic.h>
49 #define heim_base_atomic_init(t, v) atomic_init(t, v)
50 #define heim_base_atomic_load(x) atomic_load((x))
51 #define heim_base_atomic_store(t, v) atomic_store((t), (v))
53 #define heim_base_atomic(T) _Atomic(T)
55 #define heim_base_atomic_inc(x) (atomic_fetch_add((x), 1) + 1)
56 #define heim_base_atomic_dec(x) (atomic_fetch_sub((x), 1) - 1)
57 #define heim_base_atomic_type heim_base_atomic(unsigned int)
58 #define heim_base_atomic_max UINT_MAX
60 #define heim_base_exchange_pointer(t,v) atomic_exchange((t), (v))
61 #define heim_base_exchange_32(t,v) atomic_exchange((t), (v))
62 #define heim_base_exchange_64(t,v) atomic_exchange((t), (v))
64 #elif defined(__GNUC__) && defined(HAVE___SYNC_ADD_AND_FETCH)
66 #define heim_base_atomic_barrier() __sync_synchronize()
68 #define heim_base_atomic_inc(x) __sync_add_and_fetch((x), 1)
69 #define heim_base_atomic_dec(x) __sync_sub_and_fetch((x), 1)
70 #define heim_base_atomic_type unsigned int
71 #define heim_base_atomic_max UINT_MAX
73 #ifndef __has_builtin
74 #define __has_builtin(x) 0
75 #endif
77 #if __has_builtin(__sync_swap)
78 #define heim_base_exchange_pointer(t,v) __sync_swap((t), (v))
79 #else
80 /* FIXME: some targets may only write the value 1 into *t */
81 #define heim_base_exchange_pointer(t,v) __sync_lock_test_and_set((t), (v))
82 #endif
84 #define heim_base_exchange_32(t,v) heim_base_exchange_pointer((t), (v))
85 #define heim_base_exchange_64(t,v) heim_base_exchange_pointer((t), (v))
87 #elif defined(__sun)
89 #include <sys/atomic.h>
91 #define heim_base_atomic_barrier() __machine_rw_barrier()
93 #define heim_base_atomic_inc(x) atomic_inc_uint_nv((volatile uint_t *)(x))
94 #define heim_base_atomic_dec(x) atomic_dec_uint_nv((volatile uint_t *)(x))
95 #define heim_base_atomic_type uint_t
96 #define heim_base_atomic_max UINT_MAX
98 #define heim_base_exchange_pointer(t,v) atomic_swap_ptr((volatile void *)(t), (void *)(v))
99 #define heim_base_exchange_32(t,v) atomic_swap_32((volatile uint32_t *)(t), (v))
100 #define heim_base_exchange_64(t,v) atomic_swap_64((volatile uint64_t *)(t), (v))
102 #elif defined(_AIX)
104 #include <sys/atomic_op.h>
106 #define heim_base_atomic_barrier() __isync()
108 #define heim_base_atomic_inc(x) (fetch_and_add((atomic_p)(x)) + 1)
109 #define heim_base_atomic_dec(x) (fetch_and_add((atomic_p)(x)) - 1)
110 #define heim_base_atomic_type unsigned int
111 #define heim_base_atomic_max UINT_MAX
113 static inline void *
114 heim_base_exchange_pointer(void *p, void *newval)
116 void *val = *(void **)p;
118 while (!compare_and_swaplp((atomic_l)p, (long *)&val, (long)newval))
121 return val;
124 static inline uint32_t
125 heim_base_exchange_32(uint32_t *p, uint32_t newval)
127 uint32_t val = *p;
129 while (!compare_and_swap((atomic_p)p, (int *)&val, (int)newval))
132 return val;
135 static inline uint64_t
136 heim_base_exchange_64(uint64_t *p, uint64_t newval)
138 uint64_t val = *p;
140 while (!compare_and_swaplp((atomic_l)p, (long *)&val, (long)newval))
143 return val;
146 #elif defined(_WIN32)
148 #define heim_base_atomic_barrier() MemoryBarrier()
150 #define heim_base_atomic_inc(x) InterlockedIncrement(x)
151 #define heim_base_atomic_dec(x) InterlockedDecrement(x)
152 #define heim_base_atomic_type LONG
153 #define heim_base_atomic_max MAXLONG
155 #define heim_base_exchange_pointer(t,v) InterlockedExchangePointer((PVOID volatile *)(t), (PVOID)(v))
156 #define heim_base_exchange_32(t,v) ((ULONG)InterlockedExchange((LONG volatile *)(t), (LONG)(v)))
157 #define heim_base_exchange_64(t,v) ((ULONG64)InterlockedExchange64((LONG64 violatile *)(t), (LONG64)(v)))
159 #else
161 #include <heim_threads.h>
163 #define HEIM_BASE_NEED_ATOMIC_MUTEX 1
164 extern HEIMDAL_MUTEX _heim_base_mutex;
166 #define heim_base_atomic_type unsigned int
167 #define heim_base_atomic_max UINT_MAX
169 static inline heim_base_atomic_type
170 heim_base_atomic_inc(heim_base_atomic_type *x)
172 heim_base_atomic_type t;
173 HEIMDAL_MUTEX_lock(&_heim_base_mutex);
174 t = ++(*x);
175 HEIMDAL_MUTEX_unlock(&_heim_base_mutex);
176 return t;
179 static inline heim_base_atomic_type
180 heim_base_atomic_dec(heim_base_atomic_type *x)
182 heim_base_atomic_type t;
183 HEIMDAL_MUTEX_lock(&_heim_base_mutex);
184 t = --(*x);
185 HEIMDAL_MUTEX_unlock(&_heim_base_mutex);
186 return t;
189 static inline void *
190 heim_base_exchange_pointer(void *target, void *value)
192 void *old;
193 HEIMDAL_MUTEX_lock(&_heim_base_mutex);
194 old = *(void **)target;
195 *(void **)target = value;
196 HEIMDAL_MUTEX_unlock(&_heim_base_mutex);
197 return old;
200 static inline uint32_t
201 heim_base_exchange_32(uint32_t *p, uint32_t newval)
203 uint32_t old;
204 HEIMDAL_MUTEX_lock(&_heim_base_mutex);
205 old = *p;
206 *p = newval;
207 HEIMDAL_MUTEX_unlock(&_heim_base_mutex);
208 return old;
211 static inline uint64_t
212 heim_base_exchange_64(uint64_t *p, uint64_t newval)
214 uint64_t old;
215 HEIMDAL_MUTEX_lock(&_heim_base_mutex);
216 old = *p;
217 *p = newval;
218 HEIMDAL_MUTEX_unlock(&_heim_base_mutex);
219 return old;
222 #endif /* defined(__GNUC__) && defined(HAVE___SYNC_ADD_AND_FETCH) */
224 #ifndef heim_base_atomic
225 #define heim_base_atomic(T) T
226 #endif
228 #ifndef heim_base_atomic_barrier
229 #define heim_base_atomic_barrier()
230 #endif
232 #ifndef heim_base_atomic_load
233 #define heim_base_atomic_load(x) (heim_base_atomic_barrier(), *(x))
234 #endif
236 #ifndef heim_base_atomic_init
237 #define heim_base_atomic_init(t, v) do { (*(t) = (v)); } while (0)
238 #endif
240 #ifndef heim_base_atomic_store
241 #define heim_base_atomic_store(t, v) do { \
242 (*(t) = (v)); \
243 heim_base_atomic_barrier(); \
244 } while (0)
245 #endif
247 #if SIZEOF_TIME_T == 8
248 #define heim_base_exchange_time_t(t,v) heim_base_exchange_64((t), (v))
249 #elif SIZEOF_TIME_T == 4
250 #define heim_base_exchange_time_t(t,v) heim_base_exchange_32((t), (v))
251 #else
252 #error set SIZEOF_TIME_T for your platform
253 #endif
255 #endif /* HEIM_BASE_ATOMICS_H */