[project @ 2005-11-25 13:06:25 by simonmar]
[ghc-hetmet.git] / ghc / includes / SMP.h
1 /* ----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 2005
4  *
5  * Macros for SMP support
6  *
7  * -------------------------------------------------------------------------- */
8
9 #ifndef SMP_H
10 #define SMP_H
11
12 /* SMP is currently not compatible with the following options:
13  *
14  *      INTERPRETER
15  *      PROFILING
16  *      TICKY_TICKY
17  *      and unregisterised builds.
18  */
19
20 #if defined(SMP)
21
22 #if  defined(PROFILING)  || defined(TICKY_TICKY)
23 #error Build options incompatible with SMP.
24 #endif
25
26 /* 
27  * XCHG - the atomic exchange instruction.  Used for locking closures
28  * during updates (see lockClosure() below) and the MVar primops.
29  *
30  * NB: the xchg instruction is implicitly locked, so we do not need
31  * a lock prefix here. 
32  */
33 INLINE_HEADER StgWord
34 xchg(StgPtr p, StgWord w)
35 {
36     StgWord result;
37     result = w;
38     __asm__ __volatile__ (
39           "xchg %1,%0"
40           :"+r" (result), "+m" (*p)
41           : /* no input-only operands */
42         );
43     return result;
44 }
45
46 /* 
47  * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used 
48  * in the STM implementation.
49  */
50 INLINE_HEADER StgWord
51 cas(StgVolatilePtr p, StgWord o, StgWord n)
52 {
53     __asm__ __volatile__ (
54           "lock cmpxchg %3,%1"
55           :"=a"(o), "=m" (*(volatile unsigned int *)p) 
56           :"0" (o), "r" (n));
57     return o;
58 }
59
60 /*
61  * Write barrier - ensure that all preceding writes have happened
62  * before all following writes.  
63  *
64  * We need to tell both the compiler AND the CPU about the barrier.
65  * This is a brute force solution; better results might be obtained by
66  * using volatile type declarations to get fine-grained ordering
67  * control in C, and optionally a memory barrier instruction on CPUs
68  * that require it (not x86 or x86_64).
69  */
70 INLINE_HEADER void
71 wb(void) {
72 #if i386_HOST_ARCH || x86_64_HOST_ARCH
73     __asm__ __volatile__ ("" : : : "memory");
74 #else
75 #error memory barriers unimplemented on this architecture
76 #endif
77 }
78
79 /*
80  * Locking/unlocking closures
81  *
82  * This is used primarily in the implementation of MVars.
83  */
84 #define SPIN_COUNT 4000
85
86 INLINE_HEADER StgInfoTable *
87 lockClosure(StgClosure *p)
88 {
89 #if i386_HOST_ARCH || x86_64_HOST_ARCH
90     StgWord info;
91     do {
92         nat i = 0;
93         do {
94             info = xchg((P_)&p->header.info, (W_)&stg_WHITEHOLE_info);
95             if (info != (W_)&stg_WHITEHOLE_info) return (StgInfoTable *)info;
96         } while (++i < SPIN_COUNT);
97         yieldThread();
98     } while (1);
99 #else
100    ACQUIRE_SM_LOCK
101 #endif
102 }
103
104 INLINE_HEADER void
105 unlockClosure(StgClosure *p, StgInfoTable *info)
106 {
107 #if i386_HOST_ARCH || x86_64_HOST_ARCH
108     // This is a strictly ordered write, so we need a wb():
109     wb();
110     p->header.info = info;
111 #else
112     RELEASE_SM_LOCK;
113 #endif
114 }
115
116 #else /* !SMP */
117
118 #define wb() /* nothing */
119
120 INLINE_HEADER StgWord
121 xchg(StgPtr p, StgWord w)
122 {
123     StgWord old = *p;
124     *p = w;
125     return old;
126 }
127
128 #endif /* !SMP */
129
130 #endif /* SMP_H */