OpenMPI  0.1.1
atomic.h
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-2005 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$
13  *
14  * Additional copyrights may follow
15  *
16  * $HEADER$
17  */
18 
19 #ifndef OMPI_SYS_ARCH_ATOMIC_H
20 #define OMPI_SYS_ARCH_ATOMIC_H 1
21 
22 
23 #if OPAL_WANT_SMP_LOCKS
24 
25 /* BWB - FIX ME! */
26 #ifdef __linux__
27 #define MB() __asm__ __volatile__(".set mips2; sync; .set mips0": : :"memory")
28 #define RMB() __asm__ __volatile__(".set mips2; sync; .set mips0": : :"memory")
29 #define WMB() __asm__ __volatile__(".set mips2; sync; .set mips0": : :"memory")
30 #define SMP_SYNC ".set mips2; sync; .set mips0"
31 #else
32 #define MB() __asm__ __volatile__("sync": : :"memory")
33 #define RMB() __asm__ __volatile__("sync": : :"memory")
34 #define WMB() __asm__ __volatile__("sync": : :"memory")
35 #define SMP_SYNC "sync"
36 #endif
37 
38 #else
39 
40 #define MB()
41 #define RMB()
42 #define WMB()
43 #define SMP_SYNC ""
44 
45 #endif
46 
47 
48 /**********************************************************************
49  *
50  * Define constants for MIPS
51  *
52  *********************************************************************/
53 #define OPAL_HAVE_ATOMIC_MEM_BARRIER 1
54 
55 #define OPAL_HAVE_ATOMIC_CMPSET_32 1
56 
57 #ifdef __mips64
58 #define OPAL_HAVE_ATOMIC_CMPSET_64 1
59 #endif
60 
61 /**********************************************************************
62  *
63  * Memory Barriers
64  *
65  *********************************************************************/
66 #if OMPI_GCC_INLINE_ASSEMBLY
67 
68 static inline
69 void opal_atomic_mb(void)
70 {
71  MB();
72 }
73 
74 
75 static inline
76 void opal_atomic_rmb(void)
77 {
78  RMB();
79 }
80 
81 
82 static inline
83 void opal_atomic_wmb(void)
84 {
85  WMB();
86 }
87 
88 #endif
89 
90 /**********************************************************************
91  *
92  * Atomic math operations
93  *
94  *********************************************************************/
95 #if OMPI_GCC_INLINE_ASSEMBLY
96 
97 static inline int opal_atomic_cmpset_32(volatile int32_t *addr,
98  int32_t oldval, int32_t newval)
99 {
100  int32_t ret;
101 
102  __asm__ __volatile__ (".set noreorder \n"
103  ".set noat \n"
104  "1: \n"
105 #ifdef __linux__
106  ".set mips2 \n\t"
107 #endif
108  "ll %0, %2 \n" /* load *addr into ret */
109  "bne %0, %z3, 2f \n" /* done if oldval != ret */
110  "or $1, %z4, 0 \n" /* tmp = newval (delay slot) */
111  "sc $1, %2 \n" /* store tmp in *addr */
112 #ifdef __linux__
113  ".set mips0 \n\t"
114 #endif
115  /* note: ret will be 0 if failed, 1 if succeeded */
116  "beqz $1, 1b \n" /* if 0 jump back to 1b */
117  "nop \n" /* fill delay slots */
118  "2: \n"
119  ".set reorder \n"
120  : "=&r"(ret), "=m"(*addr)
121  : "m"(*addr), "r"(oldval), "r"(newval)
122  : "cc", "memory");
123  return (ret == oldval);
124 }
125 
126 
127 /* these two functions aren't inlined in the non-gcc case because then
128  there would be two function calls (since neither cmpset_32 nor
129  atomic_?mb can be inlined). Instead, we "inline" them by hand in
130  the assembly, meaning there is one function call overhead instead
131  of two */
132 static inline int opal_atomic_cmpset_acq_32(volatile int32_t *addr,
133  int32_t oldval, int32_t newval)
134 {
135  int rc;
136 
137  rc = opal_atomic_cmpset_32(addr, oldval, newval);
138  opal_atomic_rmb();
139 
140  return rc;
141 }
142 
143 
144 static inline int opal_atomic_cmpset_rel_32(volatile int32_t *addr,
145  int32_t oldval, int32_t newval)
146 {
147  opal_atomic_wmb();
148  return opal_atomic_cmpset_32(addr, oldval, newval);
149 }
150 
151 #ifdef OPAL_HAVE_ATOMIC_CMPSET_64
152 static inline int opal_atomic_cmpset_64(volatile int64_t *addr,
153  int64_t oldval, int64_t newval)
154 {
155  int64_t ret;
156 
157  __asm__ __volatile__ (".set noreorder \n"
158  ".set noat \n"
159  "1: \n\t"
160  "lld %0, %2 \n\t" /* load *addr into ret */
161  "bne %0, %z3, 2f \n\t" /* done if oldval != ret */
162  "or $1, %4, 0 \n\t" /* tmp = newval (delay slot) */
163  "scd $1, %2 \n\t" /* store tmp in *addr */
164  /* note: ret will be 0 if failed, 1 if succeeded */
165  "beqz $1, 1b \n\t" /* if 0 jump back to 1b */
166  "nop \n\t" /* fill delay slot */
167  "2: \n\t"
168  ".set reorder \n"
169  : "=&r" (ret), "=m" (*addr)
170  : "m" (*addr), "r" (oldval), "r" (newval)
171  : "cc", "memory");
172 
173  return (ret == oldval);
174 }
175 
176 
177 /* these two functions aren't inlined in the non-gcc case because then
178  there would be two function calls (since neither cmpset_64 nor
179  atomic_?mb can be inlined). Instead, we "inline" them by hand in
180  the assembly, meaning there is one function call overhead instead
181  of two */
182 static inline int opal_atomic_cmpset_acq_64(volatile int64_t *addr,
183  int64_t oldval, int64_t newval)
184 {
185  int rc;
186 
187  rc = opal_atomic_cmpset_64(addr, oldval, newval);
188  opal_atomic_rmb();
189 
190  return rc;
191 }
192 
193 
194 static inline int opal_atomic_cmpset_rel_64(volatile int64_t *addr,
195  int64_t oldval, int64_t newval)
196 {
197  opal_atomic_wmb();
198  return opal_atomic_cmpset_64(addr, oldval, newval);
199 }
200 #endif /* OPAL_HAVE_ATOMIC_CMPSET_64 */
201 
202 #endif /* OMPI_GCC_INLINE_ASSEMBLY */
203 
204 #endif /* ! OMPI_SYS_ARCH_ATOMIC_H */
void opal_atomic_rmb(void)
Read memory barrier.
void opal_atomic_mb(void)
Memory barrier.
void opal_atomic_wmb(void)
Write memory barrier.