SMP.h 6.59 KB
Newer Older
1 2
/* ----------------------------------------------------------------------------
 *
3
 * (c) The GHC Team, 2005-2008
4
 *
5
 * Macros for multi-CPU support
6 7 8 9 10 11
 *
 * -------------------------------------------------------------------------- */

#ifndef SMP_H
#define SMP_H

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
#if defined(THREADED_RTS)
20

21 22
#if  defined(TICKY_TICKY)
#error Build options incompatible with THREADED_RTS.
23 24
#endif

Simon Marlow's avatar
Simon Marlow committed
25 26 27 28
/* ----------------------------------------------------------------------------
   Atomic operations
   ------------------------------------------------------------------------- */
   
29 30 31 32 33 34
#if !IN_STG_CODE
// We only want write_barrier() declared in .hc files.  Defining the
// other inline functions here causes type mismatch errors from gcc,
// because the generated C code is assuming that there are no
// prototypes in scope.

Simon Marlow's avatar
Simon Marlow committed
35 36 37 38 39 40 41
/* 
 * The atomic exchange operation: xchg(p,w) exchanges the value
 * pointed to by p with the value w, returning the old value.
 *
 * Used for locking closures during updates (see lockClosure() below)
 * and the MVar primops.
 */
Simon Marlow's avatar
Simon Marlow committed
42
EXTERN_INLINE StgWord xchg(StgPtr p, StgWord w);
Simon Marlow's avatar
Simon Marlow committed
43

44
/* 
Simon Marlow's avatar
Simon Marlow committed
45
 * Compare-and-swap.  Atomically does this:
46
 *
Simon Marlow's avatar
Simon Marlow committed
47 48 49 50 51 52
 * cas(p,o,n) { 
 *    r = *p; 
 *    if (r == o) { *p = n }; 
 *    return r;
 * }
 */
Simon Marlow's avatar
Simon Marlow committed
53
EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n);
Simon Marlow's avatar
Simon Marlow committed
54

55 56
#endif // !IN_STG_CODE

Simon Marlow's avatar
Simon Marlow committed
57
/*
58 59 60 61 62 63 64 65 66 67 68 69
 * Various kinds of memory barrier.
 *  write_barrier: prevents future stores occurring before prededing stores.
 *  store_load_barrier: prevents future loads occurring before preceding stores.
 *  load_load_barrier: prevents future loads occurring before earlier stores.
 *
 * Reference for these: "The JSR-133 Cookbook for Compiler Writers"
 * http://gee.cs.oswego.edu/dl/jmm/cookbook.html
 *
 * To check whether you got these right, try the test in 
 *   testsuite/tests/ghc-regress/rts/testwsdeque.c
 * This tests the work-stealing deque implementation, which relies on
 * properly working store_load and load_load memory barriers.
Simon Marlow's avatar
Simon Marlow committed
70
 */ 
Simon Marlow's avatar
Simon Marlow committed
71
EXTERN_INLINE void write_barrier(void);
Simon Marlow's avatar
Simon Marlow committed
72
EXTERN_INLINE void store_load_barrier(void);
73
EXTERN_INLINE void load_load_barrier(void);
Simon Marlow's avatar
Simon Marlow committed
74

Simon Marlow's avatar
Simon Marlow committed
75 76 77
/* ----------------------------------------------------------------------------
   Implementations
   ------------------------------------------------------------------------- */
78 79 80

#if !IN_STG_CODE

Simon Marlow's avatar
Simon Marlow committed
81
/* 
82 83
 * NB: the xchg instruction is implicitly locked, so we do not need
 * a lock prefix here. 
84
 */
Simon Marlow's avatar
Simon Marlow committed
85
EXTERN_INLINE StgWord
86 87 88
xchg(StgPtr p, StgWord w)
{
    StgWord result;
89
#if i386_HOST_ARCH || x86_64_HOST_ARCH
90 91
    result = w;
    __asm__ __volatile__ (
92
 	  "xchg %1,%0"
93 94 95
          :"+r" (result), "+m" (*p)
          : /* no input-only operands */
	);
96 97 98 99 100
#elif powerpc_HOST_ARCH
    __asm__ __volatile__ (
        "1:     lwarx     %0, 0, %2\n"
        "       stwcx.    %1, 0, %2\n"
        "       bne-      1b"
101
        :"=&r" (result)
102 103
        :"r" (w), "r" (p)
    );
104 105 106 107 108 109 110
#elif sparc_HOST_ARCH
    result = w;
    __asm__ __volatile__ (
        "swap %1,%0"
	: "+r" (result), "+m" (*p)
	: /* no input-only operands */
      );
111 112 113
#elif !defined(WITHSMP)
    result = *p;
    *p = w;
114 115 116
#else
#error xchg() unimplemented on this architecture
#endif
117 118 119
    return result;
}

120 121 122 123
/* 
 * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used 
 * in the STM implementation.
 */
Simon Marlow's avatar
Simon Marlow committed
124
EXTERN_INLINE StgWord
125 126
cas(StgVolatilePtr p, StgWord o, StgWord n)
{
127
#if i386_HOST_ARCH || x86_64_HOST_ARCH
128
    __asm__ __volatile__ (
129
 	  "lock\ncmpxchg %3,%1"
130 131 132
          :"=a"(o), "=m" (*(volatile unsigned int *)p) 
          :"0" (o), "r" (n));
    return o;
133 134 135 136 137 138 139 140 141
#elif powerpc_HOST_ARCH
    StgWord result;
    __asm__ __volatile__ (
        "1:     lwarx     %0, 0, %3\n"
        "       cmpw      %0, %1\n"
        "       bne       2f\n"
        "       stwcx.    %2, 0, %3\n"
        "       bne-      1b\n"
        "2:"
142
        :"=&r" (result)
143
        :"r" (o), "r" (n), "r" (p)
144
        :"cc", "memory"
145 146
    );
    return result;
147 148 149 150 151 152 153 154
#elif sparc_HOST_ARCH
    __asm__ __volatile__ (
	"cas [%1], %2, %0"
	: "+r" (n)
	: "r" (p), "r" (o)
	: "memory"
    );
    return n;
155 156 157 158 159 160 161
#elif !defined(WITHSMP)
    StgWord result;
    result = *p;
    if (result == o) {
        *p = n;
    }
    return result;
162 163 164
#else
#error cas() unimplemented on this architecture
#endif
165 166
}

167 168
#endif // !IN_STG_CODE

169
/*
170 171 172 173
 * We need to tell both the compiler AND the CPU about the barriers.
 * It's no good preventing the CPU from reordering the operations if
 * the compiler has already done so - hence the "memory" restriction
 * on each of the barriers below.
174
 */
Simon Marlow's avatar
Simon Marlow committed
175
EXTERN_INLINE void
176
write_barrier(void) {
177 178
#if i386_HOST_ARCH || x86_64_HOST_ARCH
    __asm__ __volatile__ ("" : : : "memory");
179 180
#elif powerpc_HOST_ARCH
    __asm__ __volatile__ ("lwsync" : : : "memory");
181 182 183
#elif sparc_HOST_ARCH
    /* Sparc in TSO mode does not require write/write barriers. */
    __asm__ __volatile__ ("" : : : "memory");
184 185
#elif !defined(WITHSMP)
    return;
186 187 188 189 190
#else
#error memory barriers unimplemented on this architecture
#endif
}

Simon Marlow's avatar
Simon Marlow committed
191 192 193 194 195 196 197
EXTERN_INLINE void
store_load_barrier(void) {
#if i386_HOST_ARCH
    __asm__ __volatile__ ("lock; addl $0,0(%%esp)" : : : "memory");
#elif x86_64_HOST_ARCH
    __asm__ __volatile__ ("lock; addq $0,0(%%rsp)" : : : "memory");
#elif powerpc_HOST_ARCH
198
    __asm__ __volatile__ ("sync" : : : "memory");
Simon Marlow's avatar
Simon Marlow committed
199
#elif sparc_HOST_ARCH
Simon Marlow's avatar
Simon Marlow committed
200
    /* Sparc in TSO mode does not require store/load barriers. */
Simon Marlow's avatar
Simon Marlow committed
201 202 203 204 205 206 207 208
    __asm__ __volatile__ ("membar" : : : "memory");
#elif !defined(WITHSMP)
    return;
#else
#error memory barriers unimplemented on this architecture
#endif
}

209 210 211 212 213 214 215 216 217
EXTERN_INLINE void
load_load_barrier(void) {
#if i386_HOST_ARCH
    __asm__ __volatile__ ("" : : : "memory");
#elif x86_64_HOST_ARCH
    __asm__ __volatile__ ("" : : : "memory");
#elif powerpc_HOST_ARCH
    __asm__ __volatile__ ("lwsync" : : : "memory");
#elif sparc_HOST_ARCH
Simon Marlow's avatar
Simon Marlow committed
218
    /* Sparc in TSO mode does not require load/load barriers. */
219 220 221 222 223 224 225 226
    __asm__ __volatile__ ("" : : : "memory");
#elif !defined(WITHSMP)
    return;
#else
#error memory barriers unimplemented on this architecture
#endif
}

Simon Marlow's avatar
Simon Marlow committed
227
/* ---------------------------------------------------------------------- */
228
#else /* !THREADED_RTS */
229

230
#define write_barrier()      /* nothing */
Simon Marlow's avatar
Simon Marlow committed
231
#define store_load_barrier() /* nothing */
232
#define load_load_barrier()  /* nothing */
Simon Marlow's avatar
Simon Marlow committed
233

234 235 236 237 238 239 240 241
INLINE_HEADER StgWord
xchg(StgPtr p, StgWord w)
{
    StgWord old = *p;
    *p = w;
    return old;
}

242 243 244 245 246 247 248 249 250 251 252
STATIC_INLINE StgWord
cas(StgVolatilePtr p, StgWord o, StgWord n)
{
    StgWord result;
    result = *p;
    if (result == o) {
        *p = n;
    }
    return result;
}

253
#endif /* !THREADED_RTS */
254 255

#endif /* SMP_H */