2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
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
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
36 #ifndef HEIM_BASE_ATOMICS_H
37 #define HEIM_BASE_ATOMICS_H 1
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
74 #define __has_builtin(x) 0
77 #if __has_builtin(__sync_swap)
78 #define heim_base_exchange_pointer(t,v) __sync_swap((t), (v))
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))
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))
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))
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
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
))
124 static inline uint32_t
125 heim_base_exchange_32(uint32_t *p
, uint32_t newval
)
129 while (!compare_and_swap((atomic_p
)p
, (int *)&val
, (int)newval
))
135 static inline uint64_t
136 heim_base_exchange_64(uint64_t *p
, uint64_t newval
)
140 while (!compare_and_swaplp((atomic_l
)p
, (long *)&val
, (long)newval
))
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)))
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
);
175 HEIMDAL_MUTEX_unlock(&_heim_base_mutex
);
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
);
185 HEIMDAL_MUTEX_unlock(&_heim_base_mutex
);
190 heim_base_exchange_pointer(void *target
, void *value
)
193 HEIMDAL_MUTEX_lock(&_heim_base_mutex
);
194 old
= *(void **)target
;
195 *(void **)target
= value
;
196 HEIMDAL_MUTEX_unlock(&_heim_base_mutex
);
200 static inline uint32_t
201 heim_base_exchange_32(uint32_t *p
, uint32_t newval
)
204 HEIMDAL_MUTEX_lock(&_heim_base_mutex
);
207 HEIMDAL_MUTEX_unlock(&_heim_base_mutex
);
211 static inline uint64_t
212 heim_base_exchange_64(uint64_t *p
, uint64_t newval
)
215 HEIMDAL_MUTEX_lock(&_heim_base_mutex
);
218 HEIMDAL_MUTEX_unlock(&_heim_base_mutex
);
222 #endif /* defined(__GNUC__) && defined(HAVE___SYNC_ADD_AND_FETCH) */
224 #ifndef heim_base_atomic
225 #define heim_base_atomic(T) T
228 #ifndef heim_base_atomic_barrier
229 #define heim_base_atomic_barrier()
232 #ifndef heim_base_atomic_load
233 #define heim_base_atomic_load(x) (heim_base_atomic_barrier(), *(x))
236 #ifndef heim_base_atomic_init
237 #define heim_base_atomic_init(t, v) do { (*(t) = (v)); } while (0)
240 #ifndef heim_base_atomic_store
241 #define heim_base_atomic_store(t, v) do { \
243 heim_base_atomic_barrier(); \
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))
252 #error set SIZEOF_TIME_T for your platform
255 #endif /* HEIM_BASE_ATOMICS_H */