OpenMPI  0.1.1
atomic.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3  * University Research and Technology
4  * Corporation. All rights reserved.
5  * Copyright (c) 2004-2006 The University of Tennessee and The University
6  * of Tennessee Research Foundation. All rights
7  * reserved.
8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9  * University of Stuttgart. All rights reserved.
10  * Copyright (c) 2004-2005 The Regents of the University of California.
11  * All rights reserved.
12  * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
13  * Copyright (c) 2011 Sandia National Laboratories. All rights reserved.
14  * $COPYRIGHT$
15  *
16  * Additional copyrights may follow
17  *
18  * $HEADER$
19  */
20 
21 /** @file
22  *
23  * Atomic operations.
24  *
25  * This API is patterned after the FreeBSD kernel atomic interface
26  * (which is influenced by Intel's ia64 architecture). The
27  * FreeBSD interface is documented at
28  *
29  * http://www.freebsd.org/cgi/man.cgi?query=atomic&sektion=9
30  *
31  * Only the necessary subset of functions are implemented here.
32  *
33  * The following #defines will be true / false based on
34  * assembly support:
35  *
36  * - \c OPAL_HAVE_ATOMIC_MEM_BARRIER atomic memory barriers
37  * - \c OPAL_HAVE_ATOMIC_SPINLOCKS atomic spinlocks
38  * - \c OPAL_HAVE_ATOMIC_MATH_32 if 32 bit add/sub/cmpset can be done "atomicly"
39  * - \c OPAL_HAVE_ATOMIC_MATH_64 if 32 bit add/sub/cmpset can be done "atomicly"
40  *
41  * Note that for the Atomic math, atomic add/sub may be implemented as
42  * C code using opal_atomic_cmpset. The appearance of atomic
43  * operation will be upheld in these cases.
44  */
45 
46 #ifndef OPAL_SYS_ATOMIC_H
47 #define OPAL_SYS_ATOMIC_H 1
48 
49 #include "opal_config.h"
50 
51 #include "opal/sys/architecture.h"
52 
53 #ifdef HAVE_SYS_TYPES_H
54 #include <sys/types.h>
55 #endif
56 
57 /* do some quick #define cleanup in cases where we are doing
58  testing... */
59 #ifdef OMPI_DISABLE_INLINE_ASM
60 #undef OPAL_C_GCC_INLINE_ASSEMBLY
61 #define OPAL_C_GCC_INLINE_ASSEMBLY 0
62 #undef OMPI_CXX_GCC_INLINE_ASSEMBLY
63 #define OMPI_CXX_GCC_INLINE_ASSEMBLY 0
64 #undef OPAL_C_DEC_INLINE_ASSEMBLY
65 #define OPAL_C_DEC_INLINE_ASSEMBLY 0
66 #undef OMPI_CXX_DEC_INLINE_ASSEMBLY
67 #define OMPI_CXX_DEC_INLINE_ASSEMBLY 0
68 #undef OPAL_C_XLC_INLINE_ASSEMBLY
69 #define OPAL_C_XLC_INLINE_ASSEMBLY 0
70 #undef OMPI_CXX_XLC_INLINE_ASSEMBLY
71 #define OMPI_CXX_XLC_INLINE_ASSEMBLY 0
72 #endif
73 
74 /* define OMPI_{GCC,DEC,XLC}_INLINE_ASSEMBLY based on the
75  OMPI_{C,CXX}_{GCC,DEC,XLC}_INLINE_ASSEMBLY defines and whether we
76  are in C or C++ */
77 #if defined(c_plusplus) || defined(__cplusplus)
78 #define OMPI_GCC_INLINE_ASSEMBLY OMPI_CXX_GCC_INLINE_ASSEMBLY
79 #define OMPI_DEC_INLINE_ASSEMBLY OMPI_CXX_DEC_INLINE_ASSEMBLY
80 #define OMPI_XLC_INLINE_ASSEMBLY OMPI_CXX_XLC_INLINE_ASSEMBLY
81 #else
82 #define OMPI_GCC_INLINE_ASSEMBLY OPAL_C_GCC_INLINE_ASSEMBLY
83 #define OMPI_DEC_INLINE_ASSEMBLY OPAL_C_DEC_INLINE_ASSEMBLY
84 #define OMPI_XLC_INLINE_ASSEMBLY OPAL_C_XLC_INLINE_ASSEMBLY
85 #endif
86 
87 
88 BEGIN_C_DECLS
89 /**********************************************************************
90  *
91  * Data structures for atomic ops
92  *
93  *********************************************************************/
94 /**
95  * Volatile lock object (with optional padding).
96  *
97  * \note The internals of the lock are included here, but should be
98  * considered private. The implementation currently in use may choose
99  * to use an int or unsigned char as the lock value - the user is not
100  * informed either way.
101  */
103  union {
104  volatile int32_t lock; /**< The lock address (an integer) */
105  volatile unsigned char sparc_lock; /**< The lock address on sparc */
106  char padding[sizeof(int)]; /**< Array for optional padding */
107  } u;
108 };
110 
111 /**********************************************************************
112  *
113  * Set or unset these macros in the architecture-specific atomic.h
114  * files if we need to specify them as inline or non-inline
115  *
116  *********************************************************************/
117 #if !OMPI_GCC_INLINE_ASSEMBLY
118 #define OPAL_HAVE_INLINE_ATOMIC_MEM_BARRIER 0
119 #define OPAL_HAVE_INLINE_ATOMIC_CMPSET_32 0
120 #define OPAL_HAVE_INLINE_ATOMIC_CMPSET_64 0
121 #define OPAL_HAVE_INLINE_ATOMIC_ADD_32 0
122 #define OPAL_HAVE_INLINE_ATOMIC_SUB_32 0
123 #define OPAL_HAVE_INLINE_ATOMIC_ADD_64 0
124 #define OPAL_HAVE_INLINE_ATOMIC_SUB_64 0
125 #define OPAL_HAVE_INLINE_ATOMIC_SWAP_32 0
126 #define OPAL_HAVE_INLINE_ATOMIC_SWAP_64 0
127 #else
128 #define OPAL_HAVE_INLINE_ATOMIC_MEM_BARRIER 1
129 #define OPAL_HAVE_INLINE_ATOMIC_CMPSET_32 1
130 #define OPAL_HAVE_INLINE_ATOMIC_CMPSET_64 1
131 #define OPAL_HAVE_INLINE_ATOMIC_ADD_32 1
132 #define OPAL_HAVE_INLINE_ATOMIC_SUB_32 1
133 #define OPAL_HAVE_INLINE_ATOMIC_ADD_64 1
134 #define OPAL_HAVE_INLINE_ATOMIC_SUB_64 1
135 #define OPAL_HAVE_INLINE_ATOMIC_SWAP_32 1
136 #define OPAL_HAVE_INLINE_ATOMIC_SWAP_64 1
137 #endif
138 
139 /**********************************************************************
140  *
141  * Load the appropriate architecture files and set some reasonable
142  * default values for our support
143  *
144  *********************************************************************/
145 #if defined(DOXYGEN)
146 /* don't include system-level gorp when generating doxygen files */
147 #elif OPAL_ASSEMBLY_ARCH == OMPI_WINDOWS
148 /* windows first, as they have API-level primitives for this stuff */
149 #include "opal/sys/win32/atomic.h"
150 #elif OPAL_ASSEMBLY_ARCH == OMPI_ALPHA
151 #include "opal/sys/alpha/atomic.h"
152 #elif OPAL_ASSEMBLY_ARCH == OMPI_AMD64
153 #include "opal/sys/amd64/atomic.h"
154 #elif OPAL_ASSEMBLY_ARCH == OMPI_ARM
155 #include "opal/sys/arm/atomic.h"
156 #elif OPAL_ASSEMBLY_ARCH == OMPI_IA32
157 #include "opal/sys/ia32/atomic.h"
158 #elif OPAL_ASSEMBLY_ARCH == OMPI_IA64
159 #include "opal/sys/ia64/atomic.h"
160 #elif OPAL_ASSEMBLY_ARCH == OMPI_MIPS
161 #include "opal/sys/mips/atomic.h"
162 #elif OPAL_ASSEMBLY_ARCH == OMPI_POWERPC32
163 #include "opal/sys/powerpc/atomic.h"
164 #elif OPAL_ASSEMBLY_ARCH == OMPI_POWERPC64
165 #include "opal/sys/powerpc/atomic.h"
166 #elif OPAL_ASSEMBLY_ARCH == OMPI_SPARC
167 #include "opal/sys/sparc/atomic.h"
168 #elif OPAL_ASSEMBLY_ARCH == OMPI_SPARCV9_32
169 #include "opal/sys/sparcv9/atomic.h"
170 #elif OPAL_ASSEMBLY_ARCH == OMPI_SPARCV9_64
171 #include "opal/sys/sparcv9/atomic.h"
172 #elif OPAL_ASSEMBLY_ARCH == OMPI_SYNC_BUILTIN
173 #include "opal/sys/sync_builtin/atomic.h"
174 #endif
175 
176 #ifndef DOXYGEN
177 /* compare and set operations can't really be emulated from software,
178  so if these defines aren't already set, they should be set to 0
179  now */
180 #ifndef OPAL_HAVE_ATOMIC_CMPSET_32
181 #define OPAL_HAVE_ATOMIC_CMPSET_32 0
182 #endif
183 #ifndef OPAL_HAVE_ATOMIC_CMPSET_64
184 #define OPAL_HAVE_ATOMIC_CMPSET_64 0
185 #endif
186 #endif /* DOXYGEN */
187 
188 /**********************************************************************
189  *
190  * Memory Barriers - defined here if running doxygen or have barriers
191  * but can't inline
192  *
193  *********************************************************************/
194 #if !defined(OPAL_HAVE_ATOMIC_MEM_BARRIER) && !defined(DOXYGEN)
195 /* no way to emulate in C code */
196 #define OPAL_HAVE_ATOMIC_MEM_BARRIER 0
197 #endif
198 
199 #if defined(DOXYGEN) || OPAL_HAVE_ATOMIC_MEM_BARRIER
200 /**
201  * Memory barrier
202  *
203  * Will use system-specific features to instruct the processor and
204  * memory controller that all writes and reads that have been posted
205  * before the call to \c opal_atomic_mb() must appear to have
206  * completed before the next read or write.
207  *
208  * \note This can have some expensive side effects, including flushing
209  * the pipeline, preventing the cpu from reordering instructions, and
210  * generally grinding the memory controller's performance. Use only
211  * if you need *both* read and write barriers.
212  */
213 
214 #if OPAL_HAVE_INLINE_ATOMIC_MEM_BARRIER
215 static inline
216 #endif
217 void opal_atomic_mb(void);
218 
219 /**
220  * Read memory barrier
221  *
222  * Use system-specific features to instruct the processor and memory
223  * conrtoller that all reads that have been posted before the call to
224  * \c opal_atomic_rmb() must appear to have been completed before the
225  * next read. Nothing is said about the ordering of writes when using
226  * \c opal_atomic_rmb().
227  */
228 
229 #if OPAL_HAVE_INLINE_ATOMIC_MEM_BARRIER
230 static inline
231 #endif
232 void opal_atomic_rmb(void);
233 
234 /**
235  * Write memory barrier.
236  *
237  * Use system-specific features to instruct the processor and memory
238  * conrtoller that all writes that have been posted before the call to
239  * \c opal_atomic_wmb() must appear to have been completed before the
240  * next write. Nothing is said about the ordering of reads when using
241  * \c opal_atomic_wmb().
242  */
243 
244 #if OPAL_HAVE_INLINE_ATOMIC_MEM_BARRIER
245 static inline
246 #endif
247 void opal_atomic_wmb(void);
248 
249 #endif /* defined(DOXYGEN) || OPAL_HAVE_ATOMIC_MEM_BARRIER */
250 
251 
252 /**********************************************************************
253  *
254  * Atomic spinlocks - always inlined, if have atomic cmpset
255  *
256  *********************************************************************/
257 
258 #if !defined(OPAL_HAVE_ATOMIC_SPINLOCKS) && !defined(DOXYGEN)
259 /* 0 is more like "pending" - we'll fix up at the end after all
260  the static inline functions are declared */
261 #define OPAL_HAVE_ATOMIC_SPINLOCKS 0
262 #endif
263 
264 #if defined(DOXYGEN) || OPAL_HAVE_ATOMIC_SPINLOCKS || (OPAL_HAVE_ATOMIC_CMPSET_32 || OPAL_HAVE_ATOMIC_CMPSET_64)
265 
266 /**
267  * Enumeration of lock states
268  */
269 enum {
270  OPAL_ATOMIC_UNLOCKED = 0,
271  OPAL_ATOMIC_LOCKED = 1
272 };
273 
274 
275 /**
276  * Initialize a lock to value
277  *
278  * @param lock Address of the lock
279  * @param value Initial value to set lock to
280  */
281 #if OPAL_HAVE_ATOMIC_SPINLOCKS == 0
282 static inline
283 #endif
284 void opal_atomic_init(opal_atomic_lock_t* lock, int32_t value);
285 
286 
287 /**
288  * Try to acquire a lock.
289  *
290  * @param lock Address of the lock.
291  * @return 0 if the lock was acquired, 1 otherwise.
292  */
293 #if OPAL_HAVE_ATOMIC_SPINLOCKS == 0
294 static inline
295 #endif
297 
298 
299 /**
300  * Acquire a lock by spinning.
301  *
302  * @param lock Address of the lock.
303  */
304 #if OPAL_HAVE_ATOMIC_SPINLOCKS == 0
305 static inline
306 #endif
308 
309 
310 /**
311  * Release a lock.
312  *
313  * @param lock Address of the lock.
314  */
315 #if OPAL_HAVE_ATOMIC_SPINLOCKS == 0
316 static inline
317 #endif
319 
320 
321 #if OPAL_HAVE_ATOMIC_SPINLOCKS == 0
322 #undef OPAL_HAVE_ATOMIC_SPINLOCKS
323 #define OPAL_HAVE_ATOMIC_SPINLOCKS (OPAL_HAVE_ATOMIC_CMPSET_32 || OPAL_HAVE_ATOMIC_CMPSET_64)
324 #define OPAL_NEED_INLINE_ATOMIC_SPINLOCKS
325 #endif
326 
327 #endif /* OPAL_HAVE_ATOMIC_SPINLOCKS */
328 
329 
330 /**********************************************************************
331  *
332  * Atomic math operations
333  *
334  *********************************************************************/
335 #if !defined(OPAL_HAVE_ATOMIC_CMPSET_32) && !defined(DOXYGEN)
336 #define OPAL_HAVE_ATOMIC_CMPSET_32 0
337 #endif
338 #if defined(DOXYGEN) || OPAL_HAVE_ATOMIC_CMPSET_32
339 
340 #if OPAL_HAVE_INLINE_ATOMIC_CMPSET_32
341 static inline
342 #endif
343 int opal_atomic_cmpset_32(volatile int32_t *addr, int32_t oldval,
344  int32_t newval);
345 
346 #if OPAL_HAVE_INLINE_ATOMIC_CMPSET_32
347 static inline
348 #endif
349 int opal_atomic_cmpset_acq_32(volatile int32_t *addr, int32_t oldval,
350  int32_t newval);
351 
352 #if OPAL_HAVE_INLINE_ATOMIC_CMPSET_32
353 static inline
354 #endif
355 int opal_atomic_cmpset_rel_32(volatile int32_t *addr, int32_t oldval,
356  int32_t newval);
357 #endif
358 
359 
360 #if !defined(OPAL_HAVE_ATOMIC_CMPSET_64) && !defined(DOXYGEN)
361 #define OPAL_HAVE_ATOMIC_CMPSET_64 0
362 #endif
363 #if defined(DOXYGEN) || OPAL_HAVE_ATOMIC_CMPSET_64
364 
365 #if OPAL_HAVE_INLINE_ATOMIC_CMPSET_64
366 static inline
367 #endif
368 int opal_atomic_cmpset_64(volatile int64_t *addr, int64_t oldval,
369  int64_t newval);
370 
371 #if OPAL_HAVE_INLINE_ATOMIC_CMPSET_64
372 static inline
373 #endif
374 int opal_atomic_cmpset_acq_64(volatile int64_t *addr, int64_t oldval,
375  int64_t newval);
376 
377 #if OPAL_HAVE_INLINE_ATOMIC_CMPSET_64
378 static inline
379 #endif
380 int opal_atomic_cmpset_rel_64(volatile int64_t *addr, int64_t oldval,
381  int64_t newval);
382 
383 #endif
384 
385 #if !defined(OPAL_HAVE_ATOMIC_MATH_32) && !defined(DOXYGEN)
386  /* define to 0 for these tests. WIll fix up later. */
387  #define OPAL_HAVE_ATOMIC_MATH_32 0
388 #endif
389 
390 #if defined(DOXYGEN) || OPAL_HAVE_ATOMIC_MATH_32 || OPAL_HAVE_ATOMIC_CMPSET_32
391 
392 /* OPAL_HAVE_INLINE_ATOMIC_*_32 will be 1 if <arch>/atomic.h provides
393  a static inline version of it (in assembly). If it's 0 but
394  OPAL_HAVE_ATOMIC_CMPSET_32 is 1, then atomic_impl.h (below) will
395  define a static inline version of it (in C, using
396  atomic_cmpset_32()). */
397 #if OPAL_HAVE_INLINE_ATOMIC_ADD_32 || OPAL_HAVE_ATOMIC_CMPSET_32
398 static inline
399 #endif
400 int32_t opal_atomic_add_32(volatile int32_t *addr, int delta);
401 
402 /* OPAL_HAVE_INLINE_ATOMIC_*_32 will be 1 if <arch>/atomic.h provides
403  a static inline version of it (in assembly). If it's 0 but
404  OPAL_HAVE_ATOMIC_CMPSET_32 is 1, then atomic_impl.h (below) will
405  define a static inline version of it (in C, using
406  atomic_cmpset_32()). */
407 #if OPAL_HAVE_INLINE_ATOMIC_SUB_32 || OPAL_HAVE_ATOMIC_CMPSET_32
408 static inline
409 #endif
410 int32_t opal_atomic_sub_32(volatile int32_t *addr, int delta);
411 
412 #endif /* OPAL_HAVE_ATOMIC_MATH_32 */
413 
414 #if ! OPAL_HAVE_ATOMIC_MATH_32
415 /* fix up the value of ompi_have_atomic_math_32 to allow for C versions */
416 #undef OPAL_HAVE_ATOMIC_MATH_32
417 #define OPAL_HAVE_ATOMIC_MATH_32 OPAL_HAVE_ATOMIC_CMPSET_32
418 #endif
419 
420 #ifndef OPAL_HAVE_ATOMIC_MATH_64
421 /* define to 0 for these tests. WIll fix up later. */
422 #define OPAL_HAVE_ATOMIC_MATH_64 0
423 #endif
424 
425 #if defined(DOXYGEN) || OPAL_HAVE_ATOMIC_MATH_64 || OPAL_HAVE_ATOMIC_CMPSET_64
426 
427 /* OPAL_HAVE_INLINE_ATOMIC_*_64 will be 1 if <arch>/atomic.h provides
428  a static inline version of it (in assembly). If it's 0 but
429  OPAL_HAVE_ATOMIC_CMPSET_64 is 1, then atomic_impl.h (below) will
430  define a static inline version of it (in C, using
431  atomic_cmpset_64()). */
432 #if OPAL_HAVE_INLINE_ATOMIC_ADD_64 || OPAL_HAVE_ATOMIC_CMPSET_64
433 static inline
434 #endif
435 int64_t opal_atomic_add_64(volatile int64_t *addr, int64_t delta);
436 
437 /* OPAL_HAVE_INLINE_ATOMIC_*_64 will be 1 if <arch>/atomic.h provides
438  a static inline version of it (in assembly). If it's 0 but
439  OPAL_HAVE_ATOMIC_CMPSET_64 is 1, then atomic_impl.h (below) will
440  define a static inline version of it (in C, using
441  atomic_cmpset_64()). */
442 #if OPAL_HAVE_INLINE_ATOMIC_SUB_64 || OPAL_HAVE_ATOMIC_CMPSET_64
443 static inline
444 #endif
445 int64_t opal_atomic_sub_64(volatile int64_t *addr, int64_t delta);
446 
447 #endif /* OPAL_HAVE_ATOMIC_MATH_32 */
448 
449 #if ! OPAL_HAVE_ATOMIC_MATH_64
450 /* fix up the value of ompi_have_atomic_math_64 to allow for C versions */
451 #undef OPAL_HAVE_ATOMIC_MATH_64
452 #define OPAL_HAVE_ATOMIC_MATH_64 OPAL_HAVE_ATOMIC_CMPSET_64
453 #endif
454 
455 /* provide a size_t add/subtract. When in debug mode, make it an
456  * inline function so that we don't have any casts in the
457  * interface and can catch type errors. When not in debug mode,
458  * just make it a macro, so that there's no performance penalty
459  */
460 #if defined(DOXYGEN) || OPAL_ENABLE_DEBUG
461 static inline size_t
462 opal_atomic_add_size_t(volatile size_t *addr, int delta)
463 {
464 #if SIZEOF_SIZE_T == 4
465  return (size_t) opal_atomic_add_32((int32_t*) addr, delta);
466 #elif SIZEOF_SIZE_T == 8
467  return (size_t) opal_atomic_add_64((int64_t*) addr, delta);
468 #else
469 #error "Unknown size_t size"
470 #endif
471 }
472 static inline size_t
473 opal_atomic_sub_size_t(volatile size_t *addr, int delta)
474 {
475 #if SIZEOF_SIZE_T == 4
476  return (size_t) opal_atomic_sub_32((int32_t*) addr, delta);
477 #elif SIZEOF_SIZE_T == 8
478  return (size_t) opal_atomic_sub_64((int64_t*) addr, delta);
479 #else
480 #error "Unknown size_t size"
481 #endif
482 }
483 #else
484 #if SIZEOF_SIZE_T == 4
485 #define opal_atomic_add_size_t(addr, delta) ((size_t) opal_atomic_add_32((int32_t*) addr, delta))
486 #define opal_atomic_sub_size_t(addr, delta) ((size_t) opal_atomic_sub_32((int32_t*) addr, delta))
487 #elif SIZEOF_SIZE_T ==8
488 #define opal_atomic_add_size_t(addr, delta) ((size_t) opal_atomic_add_64((int64_t*) addr, delta))
489 #define opal_atomic_sub_size_t(addr, delta) ((size_t) opal_atomic_sub_64((int64_t*) addr, delta))
490 #else
491 #error "Unknown size_t size"
492 #endif
493 #endif
494 
495 #if defined(DOXYGEN) || (OPAL_HAVE_ATOMIC_CMPSET_32 || OPAL_HAVE_ATOMIC_CMPSET_64)
496 /* these are always done with inline functions, so always mark as
497  static inline */
498 static inline int opal_atomic_cmpset_xx(volatile void* addr, int64_t oldval,
499  int64_t newval, size_t length);
500 static inline int opal_atomic_cmpset_acq_xx(volatile void* addr,
501  int64_t oldval, int64_t newval,
502  size_t length);
503 static inline int opal_atomic_cmpset_rel_xx(volatile void* addr,
504  int64_t oldval, int64_t newval,
505  size_t length);
506 
507 static inline int opal_atomic_cmpset_ptr(volatile void* addr,
508  void* oldval,
509  void* newval);
510 static inline int opal_atomic_cmpset_acq_ptr(volatile void* addr,
511  void* oldval,
512  void* newval);
513 static inline int opal_atomic_cmpset_rel_ptr(volatile void* addr,
514  void* oldval,
515  void* newval);
516 
517 /**
518  * Atomic compare and set of pointer with relaxed semantics. This
519  * macro detect at compile time the type of the first argument and
520  * choose the correct function to be called.
521  *
522  * \note This macro should only be used for integer types.
523  *
524  * @param addr Address of <TYPE>.
525  * @param oldval Comparison value <TYPE>.
526  * @param newval New value to set if comparision is true <TYPE>.
527  *
528  * See opal_atomic_cmpset_* for pseudo-code.
529  */
530 #define opal_atomic_cmpset( ADDR, OLDVAL, NEWVAL ) \
531  opal_atomic_cmpset_xx( (volatile void*)(ADDR), (intptr_t)(OLDVAL), \
532  (intptr_t)(NEWVAL), sizeof(*(ADDR)) )
533 
534 /**
535  * Atomic compare and set of pointer with acquire semantics. This
536  * macro detect at compile time the type of the first argument
537  * and choose the correct function to be called.
538  *
539  * \note This macro should only be used for integer types.
540  *
541  * @param addr Address of <TYPE>.
542  * @param oldval Comparison value <TYPE>.
543  * @param newval New value to set if comparision is true <TYPE>.
544  *
545  * See opal_atomic_cmpset_acq_* for pseudo-code.
546  */
547 #define opal_atomic_cmpset_acq( ADDR, OLDVAL, NEWVAL ) \
548  opal_atomic_cmpset_acq_xx( (volatile void*)(ADDR), (int64_t)(OLDVAL), \
549  (int64_t)(NEWVAL), sizeof(*(ADDR)) )
550 
551 
552 /**
553  * Atomic compare and set of pointer with release semantics. This
554  * macro detect at compile time the type of the first argument
555  * and choose the correct function to b
556  *
557  * \note This macro should only be used for integer types.
558  *
559  * @param addr Address of <TYPE>.
560  * @param oldval Comparison value <TYPE>.
561  * @param newval New value to set if comparision is true <TYPE>.
562  *
563  * See opal_atomic_cmpsetrel_* for pseudo-code.
564  */
565 #define opal_atomic_cmpset_rel( ADDR, OLDVAL, NEWVAL ) \
566  opal_atomic_cmpset_rel_xx( (volatile void*)(ADDR), (int64_t)(OLDVAL), \
567  (int64_t)(NEWVAL), sizeof(*(ADDR)) )
568 
569 #endif /* (OPAL_HAVE_ATOMIC_CMPSET_32 || OPAL_HAVE_ATOMIC_CMPSET_64) */
570 
571 #if defined(DOXYGEN) || (OPAL_HAVE_ATOMIC_MATH_32 || OPAL_HAVE_ATOMIC_MATH_64)
572 
573 static inline void opal_atomic_add_xx(volatile void* addr,
574  int32_t value, size_t length);
575 static inline void opal_atomic_sub_xx(volatile void* addr,
576  int32_t value, size_t length);
577 #if SIZEOF_VOID_P == 4 && OPAL_HAVE_ATOMIC_CMPSET_32
578 static inline int32_t opal_atomic_add_ptr( volatile void* addr, void* delta );
579 static inline int32_t opal_atomic_sub_ptr( volatile void* addr, void* delta );
580 #elif SIZEOF_VOID_P == 8 && OPAL_HAVE_ATOMIC_CMPSET_64
581 static inline int64_t opal_atomic_add_ptr( volatile void* addr, void* delta );
582 static inline int64_t opal_atomic_sub_ptr( volatile void* addr, void* delta );
583 #else
584 #error Atomic arithmetic on pointers not supported
585 #endif
586 
587 /**
588  * Atomically increment the content depending on the type. This
589  * macro detect at compile time the type of the first argument
590  * and choose the correct function to be called.
591  *
592  * \note This macro should only be used for integer types.
593  *
594  * @param addr Address of <TYPE>
595  * @param delta Value to add (converted to <TYPE>).
596  */
597 #define opal_atomic_add( ADDR, VALUE ) \
598  opal_atomic_add_xx( (volatile void*)(ADDR), (int32_t)(VALUE), \
599  sizeof(*(ADDR)) )
600 
601 /**
602  * Atomically decrement the content depending on the type. This
603  * macro detect at compile time the type of the first argument
604  * and choose the correct function to be called.
605  *
606  * \note This macro should only be used for integer types.
607  *
608  * @param addr Address of <TYPE>
609  * @param delta Value to substract (converted to <TYPE>).
610  */
611 #define opal_atomic_sub( ADDR, VALUE ) \
612  opal_atomic_sub_xx( (volatile void*)(ADDR), (int32_t)(VALUE), \
613  sizeof(*(ADDR)) )
614 
615 #endif /* OPAL_HAVE_ATOMIC_MATH_32 || OPAL_HAVE_ATOMIC_MATH_64 */
616 
617 
618 /**********************************************************************
619  *
620  * Include system specific inline asm definitions. Otherwise
621  * the definitions are in system specific .s files in src/util.
622  *
623  *********************************************************************/
624 #include "opal/sys/atomic_impl.h"
625 
626 END_C_DECLS
627 
628 #endif /* OPAL_SYS_ATOMIC_H */
volatile unsigned char sparc_lock
The lock address on sparc.
Definition: atomic.h:105
void opal_atomic_rmb(void)
Read memory barrier.
Volatile lock object (with optional padding).
Definition: atomic.h:102
static void opal_atomic_unlock(opal_atomic_lock_t *lock)
Release a lock.
void opal_atomic_mb(void)
Memory barrier.
static void opal_atomic_lock(opal_atomic_lock_t *lock)
Acquire a lock by spinning.
void opal_atomic_wmb(void)
Write memory barrier.
static void opal_atomic_init(opal_atomic_lock_t *lock, int32_t value)
Initialize a lock to value.
volatile int32_t lock
The lock address (an integer)
Definition: atomic.h:104
static int opal_atomic_trylock(opal_atomic_lock_t *lock)
Try to acquire a lock.
char padding[sizeof(int)]
Array for optional padding.
Definition: atomic.h:106