Omit definitions of cas() and xchg() in .hc code
[ghc-hetmet.git] / includes / SMP.h
1 /* ----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 2005-2008
4  *
5  * Macros for multi-CPU support
6  *
7  * -------------------------------------------------------------------------- */
8
9 #ifndef SMP_H
10 #define SMP_H
11
12 /* THREADED_RTS is currently not compatible with the following options:
13  *
14  *      PROFILING (but only 1 CPU supported)
15  *      TICKY_TICKY
16  *      Unregisterised builds are ok, but only 1 CPU supported.
17  */
18
19 #ifdef CMINUSMINUS
20
21 #define unlockClosure(ptr,info)                 \
22     prim %write_barrier() [];                   \
23     StgHeader_info(ptr) = info;    
24
25 #else
26
27 #if defined(THREADED_RTS)
28
29 #if  defined(TICKY_TICKY)
30 #error Build options incompatible with THREADED_RTS.
31 #endif
32
33 /* ----------------------------------------------------------------------------
34    Atomic operations
35    ------------------------------------------------------------------------- */
36    
37 #if !IN_STG_CODE
38 // We only want write_barrier() declared in .hc files.  Defining the
39 // other inline functions here causes type mismatch errors from gcc,
40 // because the generated C code is assuming that there are no
41 // prototypes in scope.
42
43 /* 
44  * The atomic exchange operation: xchg(p,w) exchanges the value
45  * pointed to by p with the value w, returning the old value.
46  *
47  * Used for locking closures during updates (see lockClosure() below)
48  * and the MVar primops.
49  */
50 EXTERN_INLINE StgWord xchg(StgPtr p, StgWord w);
51
52 /* 
53  * Compare-and-swap.  Atomically does this:
54  *
55  * cas(p,o,n) { 
56  *    r = *p; 
57  *    if (r == o) { *p = n }; 
58  *    return r;
59  * }
60  */
61 EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n);
62
63 #endif // !IN_STG_CODE
64
65 /*
66  * Prevents write operations from moving across this call in either
67  * direction.
68  */ 
69 EXTERN_INLINE void write_barrier(void);
70
71 /* ----------------------------------------------------------------------------
72    Implementations
73    ------------------------------------------------------------------------- */
74
75 #if !IN_STG_CODE
76
77 /* 
78  * NB: the xchg instruction is implicitly locked, so we do not need
79  * a lock prefix here. 
80  */
81 EXTERN_INLINE StgWord
82 xchg(StgPtr p, StgWord w)
83 {
84     StgWord result;
85 #if i386_HOST_ARCH || x86_64_HOST_ARCH
86     result = w;
87     __asm__ __volatile__ (
88           "xchg %1,%0"
89           :"+r" (result), "+m" (*p)
90           : /* no input-only operands */
91         );
92 #elif powerpc_HOST_ARCH
93     __asm__ __volatile__ (
94         "1:     lwarx     %0, 0, %2\n"
95         "       stwcx.    %1, 0, %2\n"
96         "       bne-      1b"
97         :"=&r" (result)
98         :"r" (w), "r" (p)
99     );
100 #elif sparc_HOST_ARCH
101     result = w;
102     __asm__ __volatile__ (
103         "swap %1,%0"
104         : "+r" (result), "+m" (*p)
105         : /* no input-only operands */
106       );
107 #elif !defined(WITHSMP)
108     result = *p;
109     *p = w;
110 #else
111 #error xchg() unimplemented on this architecture
112 #endif
113     return result;
114 }
115
116 /* 
117  * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used 
118  * in the STM implementation.
119  */
120 EXTERN_INLINE StgWord
121 cas(StgVolatilePtr p, StgWord o, StgWord n)
122 {
123 #if i386_HOST_ARCH || x86_64_HOST_ARCH
124     __asm__ __volatile__ (
125           "lock\ncmpxchg %3,%1"
126           :"=a"(o), "=m" (*(volatile unsigned int *)p) 
127           :"0" (o), "r" (n));
128     return o;
129 #elif powerpc_HOST_ARCH
130     StgWord result;
131     __asm__ __volatile__ (
132         "1:     lwarx     %0, 0, %3\n"
133         "       cmpw      %0, %1\n"
134         "       bne       2f\n"
135         "       stwcx.    %2, 0, %3\n"
136         "       bne-      1b\n"
137         "2:"
138         :"=&r" (result)
139         :"r" (o), "r" (n), "r" (p)
140         :"cc", "memory"
141     );
142     return result;
143 #elif sparc_HOST_ARCH
144     __asm__ __volatile__ (
145         "cas [%1], %2, %0"
146         : "+r" (n)
147         : "r" (p), "r" (o)
148         : "memory"
149     );
150     return n;
151 #elif !defined(WITHSMP)
152     StgWord result;
153     result = *p;
154     if (result == o) {
155         *p = n;
156     }
157     return result;
158 #else
159 #error cas() unimplemented on this architecture
160 #endif
161 }
162
163 #endif // !IN_STG_CODE
164
165 /*
166  * Write barrier - ensure that all preceding writes have happened
167  * before all following writes.  
168  *
169  * We need to tell both the compiler AND the CPU about the barrier.
170  * This is a brute force solution; better results might be obtained by
171  * using volatile type declarations to get fine-grained ordering
172  * control in C, and optionally a memory barrier instruction on CPUs
173  * that require it (not x86 or x86_64).
174  */
175 EXTERN_INLINE void
176 write_barrier(void) {
177 #if i386_HOST_ARCH || x86_64_HOST_ARCH
178     __asm__ __volatile__ ("" : : : "memory");
179 #elif powerpc_HOST_ARCH
180     __asm__ __volatile__ ("lwsync" : : : "memory");
181 #elif sparc_HOST_ARCH
182     /* Sparc in TSO mode does not require write/write barriers. */
183     __asm__ __volatile__ ("" : : : "memory");
184 #elif !defined(WITHSMP)
185     return;
186 #else
187 #error memory barriers unimplemented on this architecture
188 #endif
189 }
190
191 /* ---------------------------------------------------------------------- */
192 #else /* !THREADED_RTS */
193
194 #define write_barrier() /* nothing */
195
196 INLINE_HEADER StgWord
197 xchg(StgPtr p, StgWord w)
198 {
199     StgWord old = *p;
200     *p = w;
201     return old;
202 }
203
204 #endif /* !THREADED_RTS */
205
206 #endif /* CMINUSMINUS */
207
208 #endif /* SMP_H */