SMP.h 2.67 KB
Newer Older
1
2
/* ----------------------------------------------------------------------------
 *
3
 * (c) The GHC Team, 2005
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * Macros for SMP support
 *
 * -------------------------------------------------------------------------- */

#ifndef SMP_H
#define SMP_H

/* SMP is currently not compatible with the following options:
 *
 *      INTERPRETER
 *      PROFILING
 *      TICKY_TICKY
 *      and unregisterised builds.
 */

#if defined(SMP)

22
#if  defined(PROFILING)  || defined(TICKY_TICKY)
23
24
25
26
27
#error Build options incompatible with SMP.
#endif

/* 
 * XCHG - the atomic exchange instruction.  Used for locking closures
28
 * during updates (see lockClosure() below) and the MVar primops.
29
30
31
 *
 * NB: the xchg instruction is implicitly locked, so we do not need
 * a lock prefix here. 
32
 */
33
34
35
36
37
38
INLINE_HEADER StgWord
xchg(StgPtr p, StgWord w)
{
    StgWord result;
    result = w;
    __asm__ __volatile__ (
39
 	  "xchg %1,%0"
40
41
42
43
44
45
          :"+r" (result), "+m" (*p)
          : /* no input-only operands */
	);
    return result;
}

46
47
48
49
50
51
52
53
54
55
56
57
58
59
/* 
 * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used 
 * in the STM implementation.
 */
INLINE_HEADER StgWord
cas(StgVolatilePtr p, StgWord o, StgWord n)
{
    __asm__ __volatile__ (
 	  "lock cmpxchg %3,%1"
          :"=a"(o), "=m" (*(volatile unsigned int *)p) 
          :"0" (o), "r" (n));
    return o;
}

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
 * Write barrier - ensure that all preceding writes have happened
 * before all following writes.  
 *
 * We need to tell both the compiler AND the CPU about the barrier.
 * This is a brute force solution; better results might be obtained by
 * using volatile type declarations to get fine-grained ordering
 * control in C, and optionally a memory barrier instruction on CPUs
 * that require it (not x86 or x86_64).
 */
INLINE_HEADER void
wb(void) {
#if i386_HOST_ARCH || x86_64_HOST_ARCH
    __asm__ __volatile__ ("" : : : "memory");
#else
#error memory barriers unimplemented on this architecture
#endif
}

/*
 * Locking/unlocking closures
 *
 * This is used primarily in the implementation of MVars.
 */
#define SPIN_COUNT 4000

86
87
88
INLINE_HEADER StgInfoTable *
lockClosure(StgClosure *p)
{
89
#if i386_HOST_ARCH || x86_64_HOST_ARCH
90
91
    StgWord info;
    do {
92
93
94
95
96
	nat i = 0;
	do {
	    info = xchg((P_)&p->header.info, (W_)&stg_WHITEHOLE_info);
	    if (info != (W_)&stg_WHITEHOLE_info) return (StgInfoTable *)info;
	} while (++i < SPIN_COUNT);
97
98
	yieldThread();
    } while (1);
99
#else
100
101
102
103
104
105
106
107
   ACQUIRE_SM_LOCK
#endif
}

INLINE_HEADER void
unlockClosure(StgClosure *p, StgInfoTable *info)
{
#if i386_HOST_ARCH || x86_64_HOST_ARCH
108
109
    // This is a strictly ordered write, so we need a wb():
    wb();
110
111
112
    p->header.info = info;
#else
    RELEASE_SM_LOCK;
113
#endif
114
}
115
116
117
118

#endif /* SMP */

#endif /* SMP_H */