Tidy up file headers and copyrights; point to the wiki for docs
[ghc-hetmet.git] / includes / stg / SMP.h
1 /* ----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 2005-2009
4  *
5  * Macros for multi-CPU support
6  *
7  * Do not #include this file directly: #include "Rts.h" instead.
8  *
9  * To understand the structure of the RTS headers, see the wiki:
10  *   http://hackage.haskell.org/trac/ghc/wiki/Commentary/SourceTree/Includes
11  *
12  * -------------------------------------------------------------------------- */
13
14 #ifndef SMP_H
15 #define SMP_H
16
17 #if defined(THREADED_RTS)
18
19 /* ----------------------------------------------------------------------------
20    Atomic operations
21    ------------------------------------------------------------------------- */
22    
23 #if !IN_STG_CODE || IN_STGCRUN
24 // We only want the barriers, e.g. write_barrier(), declared in .hc
25 // files.  Defining the other inline functions here causes type
26 // mismatch errors from gcc, because the generated C code is assuming
27 // that there are no prototypes in scope.
28
29 /* 
30  * The atomic exchange operation: xchg(p,w) exchanges the value
31  * pointed to by p with the value w, returning the old value.
32  *
33  * Used for locking closures during updates (see lockClosure() below)
34  * and the MVar primops.
35  */
36 EXTERN_INLINE StgWord xchg(StgPtr p, StgWord w);
37
38 /* 
39  * Compare-and-swap.  Atomically does this:
40  *
41  * cas(p,o,n) { 
42  *    r = *p; 
43  *    if (r == o) { *p = n }; 
44  *    return r;
45  * }
46  */
47 EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n);
48
49 /*
50  * Atomic increment
51  *
52  * atomic_inc(p) {
53  *   return ++(*p);
54  * }
55  */
56 EXTERN_INLINE StgWord atomic_inc(StgVolatilePtr p);
57
58 /*
59  * Atomic decrement
60  *
61  * atomic_dec(p) {
62  *   return --(*p);
63  * }
64  */
65 EXTERN_INLINE StgWord atomic_dec(StgVolatilePtr p);
66
67 #endif // !IN_STG_CODE
68
69 /*
70  * Various kinds of memory barrier.
71  *  write_barrier: prevents future stores occurring before prededing stores.
72  *  store_load_barrier: prevents future loads occurring before preceding stores.
73  *  load_load_barrier: prevents future loads occurring before earlier stores.
74  *
75  * Reference for these: "The JSR-133 Cookbook for Compiler Writers"
76  * http://gee.cs.oswego.edu/dl/jmm/cookbook.html
77  *
78  * To check whether you got these right, try the test in 
79  *   testsuite/tests/ghc-regress/rts/testwsdeque.c
80  * This tests the work-stealing deque implementation, which relies on
81  * properly working store_load and load_load memory barriers.
82  */ 
83 EXTERN_INLINE void write_barrier(void);
84 EXTERN_INLINE void store_load_barrier(void);
85 EXTERN_INLINE void load_load_barrier(void);
86
87 /* ----------------------------------------------------------------------------
88    Implementations
89    ------------------------------------------------------------------------- */
90
91 #if !IN_STG_CODE || IN_STGCRUN
92
93 EXTERN_INLINE StgWord
94 xchg(StgPtr p, StgWord w)
95 {
96     StgWord result;
97 #if i386_HOST_ARCH || x86_64_HOST_ARCH
98     result = w;
99     __asm__ __volatile__ (
100         // NB: the xchg instruction is implicitly locked, so we do not
101         // need a lock prefix here.
102           "xchg %1,%0"
103           :"+r" (result), "+m" (*p)
104           : /* no input-only operands */
105         );
106 #elif powerpc_HOST_ARCH
107     __asm__ __volatile__ (
108         "1:     lwarx     %0, 0, %2\n"
109         "       stwcx.    %1, 0, %2\n"
110         "       bne-      1b"
111         :"=&r" (result)
112         :"r" (w), "r" (p)
113     );
114 #elif sparc_HOST_ARCH
115     result = w;
116     __asm__ __volatile__ (
117         "swap %1,%0"
118         : "+r" (result), "+m" (*p)
119         : /* no input-only operands */
120       );
121 #elif !defined(WITHSMP)
122     result = *p;
123     *p = w;
124 #else
125 #error xchg() unimplemented on this architecture
126 #endif
127     return result;
128 }
129
130 /* 
131  * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used 
132  * in the STM implementation.
133  */
134 EXTERN_INLINE StgWord
135 cas(StgVolatilePtr p, StgWord o, StgWord n)
136 {
137 #if i386_HOST_ARCH || x86_64_HOST_ARCH
138     __asm__ __volatile__ (
139           "lock\ncmpxchg %3,%1"
140           :"=a"(o), "=m" (*(volatile unsigned int *)p) 
141           :"0" (o), "r" (n));
142     return o;
143 #elif powerpc_HOST_ARCH
144     StgWord result;
145     __asm__ __volatile__ (
146         "1:     lwarx     %0, 0, %3\n"
147         "       cmpw      %0, %1\n"
148         "       bne       2f\n"
149         "       stwcx.    %2, 0, %3\n"
150         "       bne-      1b\n"
151         "2:"
152         :"=&r" (result)
153         :"r" (o), "r" (n), "r" (p)
154         :"cc", "memory"
155     );
156     return result;
157 #elif sparc_HOST_ARCH
158     __asm__ __volatile__ (
159         "cas [%1], %2, %0"
160         : "+r" (n)
161         : "r" (p), "r" (o)
162         : "memory"
163     );
164     return n;
165 #elif !defined(WITHSMP)
166     StgWord result;
167     result = *p;
168     if (result == o) {
169         *p = n;
170     }
171     return result;
172 #else
173 #error cas() unimplemented on this architecture
174 #endif
175 }
176
177 EXTERN_INLINE StgWord
178 atomic_inc(StgVolatilePtr p)
179 {
180 #if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)
181     StgWord r;
182     r = 1;
183     __asm__ __volatile__ (
184         "lock\nxadd %0,%1":
185             "+r" (r), "+m" (*p):
186     );
187     return r+1;
188 #else
189     StgWord old, new;
190     do {
191         old = *p;
192         new = old + 1;
193     } while (cas(p, old, new) != old);
194     return new;
195 #endif
196 }
197
198 EXTERN_INLINE StgWord
199 atomic_dec(StgVolatilePtr p)
200 {
201 #if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)
202     StgWord r;
203     r = (StgWord)-1;
204     __asm__ __volatile__ (
205         "lock\nxadd %0,%1":
206             "+r" (r), "+m" (*p):
207     );
208     return r-1;
209 #else
210     StgWord old, new;
211     do {
212         old = *p;
213         new = old - 1;
214     } while (cas(p, old, new) != old);
215     return new;
216 #endif
217 }
218
219 #endif // !IN_STG_CODE
220
221 /*
222  * We need to tell both the compiler AND the CPU about the barriers.
223  * It's no good preventing the CPU from reordering the operations if
224  * the compiler has already done so - hence the "memory" restriction
225  * on each of the barriers below.
226  */
227 EXTERN_INLINE void
228 write_barrier(void) {
229 #if i386_HOST_ARCH || x86_64_HOST_ARCH
230     __asm__ __volatile__ ("" : : : "memory");
231 #elif powerpc_HOST_ARCH
232     __asm__ __volatile__ ("lwsync" : : : "memory");
233 #elif sparc_HOST_ARCH
234     /* Sparc in TSO mode does not require store/store barriers. */
235     __asm__ __volatile__ ("" : : : "memory");
236 #elif !defined(WITHSMP)
237     return;
238 #else
239 #error memory barriers unimplemented on this architecture
240 #endif
241 }
242
243 EXTERN_INLINE void
244 store_load_barrier(void) {
245 #if i386_HOST_ARCH
246     __asm__ __volatile__ ("lock; addl $0,0(%%esp)" : : : "memory");
247 #elif x86_64_HOST_ARCH
248     __asm__ __volatile__ ("lock; addq $0,0(%%rsp)" : : : "memory");
249 #elif powerpc_HOST_ARCH
250     __asm__ __volatile__ ("sync" : : : "memory");
251 #elif sparc_HOST_ARCH
252     __asm__ __volatile__ ("membar #StoreLoad" : : : "memory");
253 #elif !defined(WITHSMP)
254     return;
255 #else
256 #error memory barriers unimplemented on this architecture
257 #endif
258 }
259
260 EXTERN_INLINE void
261 load_load_barrier(void) {
262 #if i386_HOST_ARCH
263     __asm__ __volatile__ ("" : : : "memory");
264 #elif x86_64_HOST_ARCH
265     __asm__ __volatile__ ("" : : : "memory");
266 #elif powerpc_HOST_ARCH
267     __asm__ __volatile__ ("lwsync" : : : "memory");
268 #elif sparc_HOST_ARCH
269     /* Sparc in TSO mode does not require load/load barriers. */
270     __asm__ __volatile__ ("" : : : "memory");
271 #elif !defined(WITHSMP)
272     return;
273 #else
274 #error memory barriers unimplemented on this architecture
275 #endif
276 }
277
278 /* ---------------------------------------------------------------------- */
279 #else /* !THREADED_RTS */
280
281 #define write_barrier()      /* nothing */
282 #define store_load_barrier() /* nothing */
283 #define load_load_barrier()  /* nothing */
284
285 INLINE_HEADER StgWord
286 xchg(StgPtr p, StgWord w)
287 {
288     StgWord old = *p;
289     *p = w;
290     return old;
291 }
292
293 STATIC_INLINE StgWord
294 cas(StgVolatilePtr p, StgWord o, StgWord n)
295 {
296     StgWord result;
297     result = *p;
298     if (result == o) {
299         *p = n;
300     }
301     return result;
302 }
303
304 INLINE_HEADER StgWord
305 atomic_inc(StgVolatilePtr p)
306 {
307     return ++(*p);
308 }
309
310 INLINE_HEADER StgWord
311 atomic_dec(StgVolatilePtr p)
312 {
313     return --(*p);
314 }
315
316 #endif /* !THREADED_RTS */
317
318 #endif /* SMP_H */