1 /* ----------------------------------------------------------------------------
3 * (c) The GHC Team, 2005-2008
5 * Macros for multi-CPU support
7 * -------------------------------------------------------------------------- */
12 #if defined(THREADED_RTS)
14 /* ----------------------------------------------------------------------------
16 ------------------------------------------------------------------------- */
18 #if !IN_STG_CODE || IN_STGCRUN
19 // We only want the barriers, e.g. write_barrier(), declared in .hc
20 // files. Defining the other inline functions here causes type
21 // mismatch errors from gcc, because the generated C code is assuming
22 // that there are no prototypes in scope.
25 * The atomic exchange operation: xchg(p,w) exchanges the value
26 * pointed to by p with the value w, returning the old value.
28 * Used for locking closures during updates (see lockClosure() below)
29 * and the MVar primops.
31 EXTERN_INLINE StgWord xchg(StgPtr p, StgWord w);
34 * Compare-and-swap. Atomically does this:
38 * if (r == o) { *p = n };
42 EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n);
51 EXTERN_INLINE StgWord atomic_inc(StgVolatilePtr p);
60 EXTERN_INLINE StgWord atomic_dec(StgVolatilePtr p);
62 #endif // !IN_STG_CODE
65 * Various kinds of memory barrier.
66 * write_barrier: prevents future stores occurring before prededing stores.
67 * store_load_barrier: prevents future loads occurring before preceding stores.
68 * load_load_barrier: prevents future loads occurring before earlier stores.
70 * Reference for these: "The JSR-133 Cookbook for Compiler Writers"
71 * http://gee.cs.oswego.edu/dl/jmm/cookbook.html
73 * To check whether you got these right, try the test in
74 * testsuite/tests/ghc-regress/rts/testwsdeque.c
75 * This tests the work-stealing deque implementation, which relies on
76 * properly working store_load and load_load memory barriers.
78 EXTERN_INLINE void write_barrier(void);
79 EXTERN_INLINE void store_load_barrier(void);
80 EXTERN_INLINE void load_load_barrier(void);
82 /* ----------------------------------------------------------------------------
84 ------------------------------------------------------------------------- */
86 #if !IN_STG_CODE || IN_STGCRUN
89 xchg(StgPtr p, StgWord w)
92 #if i386_HOST_ARCH || x86_64_HOST_ARCH
94 __asm__ __volatile__ (
95 // NB: the xchg instruction is implicitly locked, so we do not
96 // need a lock prefix here.
98 :"+r" (result), "+m" (*p)
99 : /* no input-only operands */
101 #elif powerpc_HOST_ARCH
102 __asm__ __volatile__ (
103 "1: lwarx %0, 0, %2\n"
104 " stwcx. %1, 0, %2\n"
109 #elif sparc_HOST_ARCH
111 __asm__ __volatile__ (
113 : "+r" (result), "+m" (*p)
114 : /* no input-only operands */
116 #elif !defined(WITHSMP)
120 #error xchg() unimplemented on this architecture
126 * CMPXCHG - the single-word atomic compare-and-exchange instruction. Used
127 * in the STM implementation.
129 EXTERN_INLINE StgWord
130 cas(StgVolatilePtr p, StgWord o, StgWord n)
132 #if i386_HOST_ARCH || x86_64_HOST_ARCH
133 __asm__ __volatile__ (
134 "lock\ncmpxchg %3,%1"
135 :"=a"(o), "=m" (*(volatile unsigned int *)p)
138 #elif powerpc_HOST_ARCH
140 __asm__ __volatile__ (
141 "1: lwarx %0, 0, %3\n"
144 " stwcx. %2, 0, %3\n"
148 :"r" (o), "r" (n), "r" (p)
152 #elif sparc_HOST_ARCH
153 __asm__ __volatile__ (
160 #elif !defined(WITHSMP)
168 #error cas() unimplemented on this architecture
172 EXTERN_INLINE StgWord
173 atomic_inc(StgVolatilePtr p)
175 #if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)
178 __asm__ __volatile__ (
188 } while (cas(p, old, new) != old);
193 EXTERN_INLINE StgWord
194 atomic_dec(StgVolatilePtr p)
196 #if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)
199 __asm__ __volatile__ (
209 } while (cas(p, old, new) != old);
214 #endif // !IN_STG_CODE
217 * We need to tell both the compiler AND the CPU about the barriers.
218 * It's no good preventing the CPU from reordering the operations if
219 * the compiler has already done so - hence the "memory" restriction
220 * on each of the barriers below.
223 write_barrier(void) {
224 #if i386_HOST_ARCH || x86_64_HOST_ARCH
225 __asm__ __volatile__ ("" : : : "memory");
226 #elif powerpc_HOST_ARCH
227 __asm__ __volatile__ ("lwsync" : : : "memory");
228 #elif sparc_HOST_ARCH
229 /* Sparc in TSO mode does not require store/store barriers. */
230 __asm__ __volatile__ ("" : : : "memory");
231 #elif !defined(WITHSMP)
234 #error memory barriers unimplemented on this architecture
239 store_load_barrier(void) {
241 __asm__ __volatile__ ("lock; addl $0,0(%%esp)" : : : "memory");
242 #elif x86_64_HOST_ARCH
243 __asm__ __volatile__ ("lock; addq $0,0(%%rsp)" : : : "memory");
244 #elif powerpc_HOST_ARCH
245 __asm__ __volatile__ ("sync" : : : "memory");
246 #elif sparc_HOST_ARCH
247 __asm__ __volatile__ ("membar #StoreLoad" : : : "memory");
248 #elif !defined(WITHSMP)
251 #error memory barriers unimplemented on this architecture
256 load_load_barrier(void) {
258 __asm__ __volatile__ ("" : : : "memory");
259 #elif x86_64_HOST_ARCH
260 __asm__ __volatile__ ("" : : : "memory");
261 #elif powerpc_HOST_ARCH
262 __asm__ __volatile__ ("lwsync" : : : "memory");
263 #elif sparc_HOST_ARCH
264 /* Sparc in TSO mode does not require load/load barriers. */
265 __asm__ __volatile__ ("" : : : "memory");
266 #elif !defined(WITHSMP)
269 #error memory barriers unimplemented on this architecture
273 /* ---------------------------------------------------------------------- */
274 #else /* !THREADED_RTS */
276 #define write_barrier() /* nothing */
277 #define store_load_barrier() /* nothing */
278 #define load_load_barrier() /* nothing */
280 INLINE_HEADER StgWord
281 xchg(StgPtr p, StgWord w)
288 STATIC_INLINE StgWord
289 cas(StgVolatilePtr p, StgWord o, StgWord n)
299 INLINE_HEADER StgWord
300 atomic_inc(StgVolatilePtr p)
305 INLINE_HEADER StgWord
306 atomic_dec(StgVolatilePtr p)
311 #endif /* !THREADED_RTS */