"Initial commit to Gerrit"
[profile/ivi/libatomic_ops.git] / src / atomic_ops.h
1 /*
2  * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
3  * 
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  * 
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE. 
21  */ 
22
23 #ifndef ATOMIC_OPS_H
24
25 #define ATOMIC_OPS_H
26
27 #include <assert.h>
28
29 /* We define various atomic operations on memory in a           */
30 /* machine-specific way.  Unfortunately, this is complicated    */
31 /* by the fact that these may or may not be combined with       */
32 /* various memory barriers.  Thus the actual operations we      */
33 /* define have the form AO_<atomic-op>_<barrier>, for all       */
34 /* plausible combinations of <atomic-op> and <barrier>.         */
35 /* This of course results in a mild combinatorial explosion.    */
36 /* To deal with it, we try to generate derived                  */
37 /* definitions for as many of the combinations as we can, as    */
38 /* automatically as possible.                                   */
39 /*                                                              */
40 /* Our assumption throughout is that the programmer will        */
41 /* specify the least demanding operation and memory barrier     */
42 /* that will guarantee correctness for the implementation.      */
43 /* Our job is to find the least expensive way to implement it   */
44 /* on the applicable hardware.  In many cases that will         */
45 /* involve, for example, a stronger memory barrier, or a        */
46 /* combination of hardware primitives.                          */
47 /*                                                              */
48 /* Conventions:                                                 */
49 /* "plain" atomic operations are not guaranteed to include      */
50 /* a barrier.  The suffix in the name specifies the barrier     */
51 /* type.  Suffixes are:                                         */
52 /* _release: Earlier operations may not be delayed past it.     */
53 /* _acquire: Later operations may not move ahead of it.         */
54 /* _read: Subsequent reads must follow this operation and       */
55 /*        preceding reads.                                      */
56 /* _write: Earlier writes precede both this operation and       */
57 /*        later writes.                                         */
58 /* _full: Ordered with respect to both earlier and later memops.*/
59 /* _release_write: Ordered with respect to earlier writes.      */
60 /* _acquire_read: Ordered with repsect to later reads.          */
61 /*                                                              */
62 /* Currently we try to define the following atomic memory       */
63 /* operations, in combination with the above barriers:          */
64 /* AO_nop                                                       */
65 /* AO_load                                                      */
66 /* AO_store                                                     */
67 /* AO_test_and_set (binary)                                     */
68 /* AO_fetch_and_add                                             */
69 /* AO_fetch_and_add1                                            */
70 /* AO_fetch_and_sub1                                            */
71 /* AO_or                                                        */
72 /* AO_compare_and_swap                                          */
73 /*                                                              */
74 /* Note that atomicity guarantees are valid only if both        */
75 /* readers and writers use AO_ operations to access the         */
76 /* shared value, while ordering constraints are intended to     */
77 /* apply all memory operations.  If a location can potentially  */
78 /* be accessed simultaneously from multiple threads, and one of */
79 /* those accesses may be a write access, then all such          */
80 /* accesses to that location should be through AO_ primitives.  */
81 /* However if AO_ operations enforce sufficient ordering to     */
82 /* ensure that a location x cannot be accessed concurrently,    */
83 /* or can only be read concurrently, then x can be accessed     */
84 /* via ordinary references and assignments.                     */
85 /*                                                              */
86 /* Compare_and_exchange takes an address and an expected old    */
87 /* value and a new value, and returns an int.  Nonzero          */
88 /* indicates that it succeeded.                                 */
89 /* Test_and_set takes an address, atomically replaces it by     */
90 /* AO_TS_SET, and returns the prior value.                      */
91 /* An AO_TS_t location can be reset with the                    */
92 /* AO_CLEAR macro, which normally uses AO_store_release.        */
93 /* AO_fetch_and_add takes an address and an AO_t increment      */
94 /* value.  The AO_fetch_and_add1 and AO_fetch_and_sub1 variants */
95 /* are provided, since they allow faster implementations on     */
96 /* some hardware. AO_or atomically ors an AO_t value into a     */
97 /* memory location, but does not provide access to the original.*/
98 /*                                                              */
99 /* We expect this list to grow slowly over time.                */
100 /*                                                              */
101 /* Note that AO_nop_full is a full memory barrier.              */
102 /*                                                              */
103 /* Note that if some data is initialized with                   */
104 /*      data.x = ...; data.y = ...; ...                         */
105 /*      AO_store_release_write(&data_is_initialized, 1)         */
106 /* then data is guaranteed to be initialized after the test     */
107 /*      if (AO_load_release_read(&data_is_initialized)) ...     */
108 /* succeeds.  Furthermore, this should generate near-optimal    */
109 /* code on all common platforms.                                */
110 /*                                                              */
111 /* All operations operate on unsigned AO_t, which               */
112 /* is the natural word size, and usually unsigned long.         */
113 /* It is possible to check whether a particular operation op    */
114 /* is available on a particular platform by checking whether    */
115 /* AO_HAVE_op is defined.  We make heavy use of these macros    */
116 /* internally.                                                  */
117
118 /* The rest of this file basically has three sections:          */
119 /*                                                              */
120 /* Some utility and default definitions.                        */
121 /*                                                              */
122 /* The architecture dependent section:                          */
123 /* This defines atomic operations that have direct hardware     */
124 /* support on a particular platform, mostly by uncluding the    */
125 /* appropriate compiler- and hardware-dependent file.           */
126 /*                                                              */
127 /* The synthesis section:                                       */
128 /* This tries to define other atomic operations in terms of     */
129 /* those that are explicitly available on the platform.         */
130 /* This section is hardware independent.                        */
131 /* We make no attempt to synthesize operations in ways that     */
132 /* effectively introduce locks, except for the debugging/demo   */
133 /* pthread-based implementation at the beginning.  A more       */
134 /* relistic implementation that falls back to locks could be    */
135 /* added as a higher layer.  But that would sacrifice           */
136 /* usability from signal handlers.                              */
137 /* The synthesis section is implemented almost entirely in      */
138 /* atomic_ops_generalize.h.                                     */
139
140 /* Some common defaults.  Overridden for some architectures.    */
141 #define AO_t unsigned long
142         /* Could conceivably be redefined below if/when we add  */
143         /* win64 support.                                       */
144
145 /* The test_and_set primitive returns an AO_TS_VAL_t value.     */
146 /* AO_TS_t is the type of an in-memory test-and-set location.   */
147
148 #define AO_TS_INITIALIZER (AO_t)AO_TS_CLEAR
149
150 /* Platform-dependent stuff:                                    */
151 #if defined(__GNUC__) || defined(_MSC_VER) || defined(__INTEL_COMPILER)
152 # define AO_INLINE static __inline
153 #else
154 # define AO_INLINE static
155 #endif
156
157 #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
158 # define AO_compiler_barrier() __asm__ __volatile__("" : : : "memory")
159 #elif defined(_MSC_VER)
160 # define AO_compiler_barrier() __asm { }
161 #elif defined(__INTEL_COMPILER)
162 # define AO_compiler_barrier() __memory_barrier() /* Too strong? IA64-only? */
163 #elif defined(_HPUX_SOURCE)
164 # if defined(__ia64)
165 #   include <machine/sys/inline.h>
166 #   define AO_compiler_barrier() _Asm_sched_fence()
167 # else
168     /* FIXME - We dont know how to do this.  This is a guess.   */
169     /* And probably a bad one.                                  */
170     static volatile int AO_barrier_dummy;
171 #   define AO_compiler_barrier() AO_barrier_dummy = AO_barrier_dummy
172 # endif
173 #else
174   /* We conjecture that the following usually gives us the right        */
175   /* semantics or an error.                                             */
176 # define AO_compiler_barrier() asm("")
177 #endif
178
179 #if defined(AO_USE_PTHREAD_DEFS)
180 # include "atomic_ops/sysdeps/generic_pthread.h"
181 #endif /* AO_USE_PTHREAD_DEFS */
182
183 #if defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS) \
184     && !defined(__INTEL_COMPILER)
185 # if defined(__i386__)
186 #   include "atomic_ops/sysdeps/gcc/x86.h"
187 # endif /* __i386__ */
188 # if defined(__x86_64__)
189 #   include "atomic_ops/sysdeps/gcc/x86_64.h"
190 # endif /* __i386__ */
191 # if defined(__ia64__)
192 #   include "atomic_ops/sysdeps/gcc/ia64.h"
193 #   define AO_GENERALIZE_TWICE
194 # endif /* __ia64__ */
195 # if defined(__hppa__)
196 #   include "atomic_ops/sysdeps/gcc/hppa.h"
197 #   define AO_CAN_EMUL_CAS
198 # endif /* __hppa__ */
199 # if defined(__alpha__)
200 #   include "atomic_ops/sysdeps/gcc/alpha.h"
201 #   define AO_GENERALIZE_TWICE
202 # endif /* __alpha__ */
203 # if defined(__s390__)
204 #   include "atomic_ops/sysdeps/gcc/s390.h"
205 # endif /* __s390__ */
206 # if defined(__sparc__)
207 #   include "atomic_ops/sysdeps/gcc/sparc.h"
208 #   define AO_CAN_EMUL_CAS
209 # endif /* __sparc__ */
210 # if defined(__m68k__)
211 #   include "atomic_ops/sysdeps/gcc/m68k.h"
212 # endif /* __m68k__ */
213 # if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)
214 #   include "atomic_ops/sysdeps/gcc/powerpc.h"
215 # endif /* __powerpc__ */
216 # if defined(__arm__) && !defined(AO_USE_PTHREAD_DEFS)
217 #   include "atomic_ops/sysdeps/gcc/arm.h"
218 #   define AO_CAN_EMUL_CAS
219 # endif /* __arm__ */
220 # if defined(__cris__) || defined(CRIS)
221 #   include "atomic_ops/sysdeps/gcc/cris.h"
222 # endif
223 #endif /* __GNUC__ && !AO_USE_PTHREAD_DEFS */
224
225 #if defined(__INTEL_COMPILER) && !defined(AO_USE_PTHREAD_DEFS)
226 # if defined(__ia64__)
227 #   include "atomic_ops/sysdeps/icc/ia64.h"
228 #   define AO_GENERALIZE_TWICE
229 # endif
230 #endif
231
232 #if defined(_HPUX_SOURCE) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)
233 # if defined(__ia64)
234 #   include "atomic_ops/sysdeps/hpc/ia64.h"
235 #   define AO_GENERALIZE_TWICE
236 # else
237 #   include "atomic_ops/sysdeps/hpc/hppa.h"
238 #   define AO_CAN_EMUL_CAS
239 # endif
240 #endif
241
242 #if !defined(__GNUC__) && (defined(sparc) || defined(__sparc)) \
243     && !defined(AO_USE_PTHREAD_DEFS)
244 #   include "atomic_ops/sysdeps/sunc/sparc.h"
245 #   define AO_CAN_EMUL_CAS
246 #endif
247
248 #if defined(_MSC_VER)
249 # if _M_IX86 >= 400
250 #   include "atomic_ops/sysdeps/msftc/x86.h"
251 # endif
252 #endif
253
254 #if defined(AO_REQUIRE_CAS) && !defined(AO_HAVE_compare_and_swap) \
255     && !defined(AO_HAVE_compare_and_swap_full) \
256     && !defined(AO_HAVE_compare_and_swap_acquire)
257 # if defined(AO_CAN_EMUL_CAS)
258 #   include "atomic_ops/sysdeps/emul_cas.h"
259 # else
260 #  error Cannot implement AO_compare_and_swap_full on this architecture.
261 # endif
262 #endif  /* AO_REQUIRE_CAS && !AO_HAVE_compare_and_swap ... */
263
264 /* The most common way to clear a test-and-set location         */
265 /* at the end of a critical section.                            */
266 #if AO_AO_TS_T && !defined(AO_CLEAR)
267 # define AO_CLEAR(addr) AO_store_release((AO_TS_t *)addr, AO_TS_CLEAR)
268 #endif
269 #if AO_CHAR_TS_T && !defined(AO_CLEAR)
270 # define AO_CLEAR(addr) AO_char_store_release((AO_TS_t *)addr, AO_TS_CLEAR)
271 #endif
272
273 /*
274  * The generalization section.
275  * Theoretically this should repeatedly include atomic_ops_generalize.h.
276  * In fact, we observe that this converges after a small fixed number
277  * of iterations, usually one.
278  */
279 #include "atomic_ops/generalize.h"
280 #ifdef AO_GENERALIZE_TWICE
281 # include "atomic_ops/generalize.h"
282 #endif
283
284 /* For compatibility with version 0.4 and earlier       */
285 #define AO_TS_T AO_TS_t
286 #define AO_T AO_t
287 #define AO_TS_VAL AO_TS_VAL_t
288
289 #endif /* ATOMIC_OPS_H */