X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=includes%2FSMP.h;h=bf23e0826092a9fc69341a18281b1c08461b9675;hb=3710a4ef1ca665fe4ed705a6b0f4400d680c7b54;hp=04e4d1326b3885aec638716c00a4bf3724cc9f69;hpb=59c03ecb7fa69bf13647f0106e50748e90711176;p=ghc-hetmet.git diff --git a/includes/SMP.h b/includes/SMP.h index 04e4d13..bf23e08 100644 --- a/includes/SMP.h +++ b/includes/SMP.h @@ -1,8 +1,8 @@ /* ---------------------------------------------------------------------------- * - * (c) The GHC Team, 2005 + * (c) The GHC Team, 2005-2008 * - * Macros for THREADED_RTS support + * Macros for multi-CPU support * * -------------------------------------------------------------------------- */ @@ -26,6 +26,12 @@ Atomic operations ------------------------------------------------------------------------- */ +#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. + /* * The atomic exchange operation: xchg(p,w) exchanges the value * pointed to by p with the value w, returning the old value. @@ -33,7 +39,7 @@ * Used for locking closures during updates (see lockClosure() below) * and the MVar primops. */ -INLINE_HEADER StgWord xchg(StgPtr p, StgWord w); +EXTERN_INLINE StgWord xchg(StgPtr p, StgWord w); /* * Compare-and-swap. Atomically does this: @@ -44,22 +50,27 @@ INLINE_HEADER StgWord xchg(StgPtr p, StgWord w); * return r; * } */ -INLINE_HEADER StgWord cas(StgVolatilePtr p, StgWord o, StgWord n); +EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n); + +#endif // !IN_STG_CODE /* * Prevents write operations from moving across this call in either * direction. */ -INLINE_HEADER void write_barrier(void); +EXTERN_INLINE void write_barrier(void); /* ---------------------------------------------------------------------------- Implementations ------------------------------------------------------------------------- */ + +#if !IN_STG_CODE + /* * NB: the xchg instruction is implicitly locked, so we do not need * a lock prefix here. */ -INLINE_HEADER StgWord +EXTERN_INLINE StgWord xchg(StgPtr p, StgWord w) { StgWord result; @@ -75,7 +86,7 @@ xchg(StgPtr p, StgWord w) "1: lwarx %0, 0, %2\n" " stwcx. %1, 0, %2\n" " bne- 1b" - :"=r" (result) + :"=&r" (result) :"r" (w), "r" (p) ); #elif sparc_HOST_ARCH @@ -98,12 +109,12 @@ xchg(StgPtr p, StgWord w) * CMPXCHG - the single-word atomic compare-and-exchange instruction. Used * in the STM implementation. */ -INLINE_HEADER StgWord +EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n) { #if i386_HOST_ARCH || x86_64_HOST_ARCH __asm__ __volatile__ ( - "lock/cmpxchg %3,%1" + "lock\ncmpxchg %3,%1" :"=a"(o), "=m" (*(volatile unsigned int *)p) :"0" (o), "r" (n)); return o; @@ -141,6 +152,8 @@ cas(StgVolatilePtr p, StgWord o, StgWord n) #endif } +#endif // !IN_STG_CODE + /* * Write barrier - ensure that all preceding writes have happened * before all following writes. @@ -151,7 +164,7 @@ cas(StgVolatilePtr p, StgWord o, StgWord n) * control in C, and optionally a memory barrier instruction on CPUs * that require it (not x86 or x86_64). */ -INLINE_HEADER void +EXTERN_INLINE void write_barrier(void) { #if i386_HOST_ARCH || x86_64_HOST_ARCH __asm__ __volatile__ ("" : : : "memory"); @@ -167,124 +180,6 @@ write_barrier(void) { #endif } -/* ----------------------------------------------------------------------------- - * Locking/unlocking closures - * - * This is used primarily in the implementation of MVars. - * -------------------------------------------------------------------------- */ - -#define SPIN_COUNT 4000 - -INLINE_HEADER StgInfoTable * -lockClosure(StgClosure *p) -{ - StgWord info; - do { - nat i = 0; - do { - info = xchg((P_)(void *)&p->header.info, (W_)&stg_WHITEHOLE_info); - if (info != (W_)&stg_WHITEHOLE_info) return (StgInfoTable *)info; - } while (++i < SPIN_COUNT); - yieldThread(); - } while (1); -} - -INLINE_HEADER void -unlockClosure(StgClosure *p, StgInfoTable *info) -{ - // This is a strictly ordered write, so we need a write_barrier(): - write_barrier(); - p->header.info = info; -} - -/* ----------------------------------------------------------------------------- - * Spin locks - * - * These are simple spin-only locks as opposed to Mutexes which - * probably spin for a while before blocking in the kernel. We use - * these when we are sure that all our threads are actively running on - * a CPU, eg. in the GC. - * - * TODO: measure whether we really need these, or whether Mutexes - * would do (and be a bit safer if a CPU becomes loaded). - * -------------------------------------------------------------------------- */ - -#if defined(DEBUG) -typedef struct StgSync_ -{ - StgWord32 lock; - StgWord64 spin; // DEBUG version counts how much it spins -} StgSync; -#else -typedef StgWord StgSync; -#endif - -typedef lnat StgSyncCount; - - -#if defined(DEBUG) - -// Debug versions of spin locks maintain a spin count - -// How to use: -// To use the debug veriosn of the spin locks, a debug version of the program -// can be run under a deugger with a break point on stat_exit. At exit time -// of the program one can examine the state the spin count counts of various -// spin locks to check for contention. - -// acquire spin lock -INLINE_HEADER void acquireSpinLock(StgSync * p) -{ - StgWord32 r = 0; - do { - p->spin++; - r = cas((StgVolatilePtr)&(p->lock), 1, 0); - } while(r == 0); - p->spin--; -} - -// release spin lock -INLINE_HEADER void releaseSpinLock(StgSync * p) -{ - write_barrier(); - p->lock = 1; -} - -// initialise spin lock -INLINE_HEADER void initSpinLock(StgSync * p) -{ - write_barrier(); - p->lock = 1; - p->spin = 0; -} - -#else - -// acquire spin lock -INLINE_HEADER void acquireSpinLock(StgSync * p) -{ - StgWord32 r = 0; - do { - r = cas((StgVolatilePtr)p, 1, 0); - } while(r == 0); -} - -// release spin lock -INLINE_HEADER void releaseSpinLock(StgSync * p) -{ - write_barrier(); - (*p) = 1; -} - -// init spin lock -INLINE_HEADER void initSpinLock(StgSync * p) -{ - write_barrier(); - (*p) = 1; -} - -#endif /* DEBUG */ - /* ---------------------------------------------------------------------- */ #else /* !THREADED_RTS */ @@ -298,30 +193,6 @@ xchg(StgPtr p, StgWord w) return old; } -INLINE_HEADER StgInfoTable * -lockClosure(StgClosure *p) -{ return (StgInfoTable *)p->header.info; } - -INLINE_HEADER void -unlockClosure(StgClosure *p STG_UNUSED, StgInfoTable *info STG_UNUSED) -{ /* nothing */ } - -INLINE_HEADER void acquireSpinLock(void * p STG_UNUSED) -{ /* nothing */ } - -INLINE_HEADER void releaseSpinLock(void * p STG_UNUSED) -{ /* nothing */ } - -INLINE_HEADER void initSpinLock(void * p STG_UNUSED) -{ /* nothing */ } - #endif /* !THREADED_RTS */ -// Handy specialised versions of lockClosure()/unlockClosure() -INLINE_HEADER void lockTSO(StgTSO *tso) -{ lockClosure((StgClosure *)tso); } - -INLINE_HEADER void unlockTSO(StgTSO *tso) -{ unlockClosure((StgClosure*)tso, (StgInfoTable*)&stg_TSO_info); } - #endif /* SMP_H */