5 * This non-reentrant spinlock implementation for i386 and x86_64 is
6 * based on free code by Gert Boddaert:
8 * http://www.codeproject.com/KB/threads/spinlocks.aspx
10 * Using spinlocks instead of the heavier pthreads mutexes can, in some
11 * cases, help Bowtie perform better for large numbers of threads.
14 // (If the user hasn't specified this, then there's no need for any
15 // kind of locking, so we skip this header)
16 #ifdef BOWTIE_PTHREADS
19 #if defined(__x86_64__) || defined(__i386__)
26 #if defined(__x86_64__)
27 #define SPINLOCK_WORD long
29 #define SPINLOCK_WORD int
33 public: // inlined constructor
35 // inlined NON-virtual destructor
36 inline SpinLock() : m_s(1) {}
39 // enter the lock, spinlocks (with/without Sleep)
40 // when mutex is already locked
41 inline void Enter(void)
46 prev_s = TestAndSet(&m_s, 0);
47 if (m_s == 0 && prev_s == 1)
49 // The lock and was unlocked and we grabbed it
52 // reluinquish current timeslice (can only
53 // be used when OS available and
54 // we do NOT want to 'spin')
59 // Tries to enter the lock, returns 0
60 // when mutex is already locked,
61 // returns != 0 when success
62 inline int TryEnter(void)
64 SPINLOCK_WORD prev_s = TestAndSet(&m_s, 0);
65 if (m_s == 0 && prev_s == 1)
72 // Leaves or unlocks the mutex
73 // (should only be called by lock owner)
74 inline void Leave(void)
80 // sets BIT value and returns previous
81 // value.in 1 atomic un-interruptable operation
82 SPINLOCK_WORD TestAndSet(SPINLOCK_WORD* pTargetAddress, SPINLOCK_WORD nValue);
88 // This part is Platform dependent!
90 /* The following piece of code can be found
91 in function AtomicExchange of file atomicops-internals-x86.h
92 under http://google-perftools.googlecode.com/svn/trunk/src/base/
94 #if defined(__x86_64__)
95 #define TAS(_lw, _res) \
96 asm volatile("xchgq %1,%0":"=r"(_res):"m"(*_lw),"0"(_res):"memory")
97 #elif defined(__i386__)
98 #define TAS(_lw, _res) \
99 asm volatile("xchgl %1,%0":"=r"(_res):"m"(*_lw),"0"(_res):"memory")
101 #error "Architecture is neither x86_64 nor i386 (see spinlock.h)"
103 /* TAS is only defined for GNUC on x86_64 and i386,
104 that is where GNUC x86 inline assembly can be used */
106 inline SPINLOCK_WORD SpinLock::TestAndSet(SPINLOCK_WORD* pTargetAddress, SPINLOCK_WORD nValue) {
111 mov edx, dword ptr [pTargetAddress]
113 lock xchg eax, dword ptr [edx]
116 TAS(pTargetAddress, nValue);
120 // lock = 1 CPU cycle
121 // xchg = 3 CPU cycles
123 #endif /*USE_SPINLOCK*/
125 #endif /*BOWTIE_PTHREADS*/
127 #endif /*SPINLOCK_H_*/