#include "precompile.h" #include "spinlock.h" // please refer http://book.opensourceproject.org.cn/kernel/kernel3rd/opensource/0596005652/understandlk-chp-5-sect-2.html static __inline void backoff(unsigned int nloop) { //and d, s d <- d & s //if ZF d, s #ifdef _WIN32 __asm { and ecx, nloop; cmovz ecx, nloop; rep nop; } #else //TODO: need to confirm its correctness. __asm__ __volatile__ ("and %edi, %ecx;" "cmovz %edi, %ecx;" "rep;" "nop"); #endif } TOOLKIT_API void spinlock_enter(volatile spinlock_t *sl, int spin_count) { DWORD tid = GetCurrentThreadId(); if (sl->_value == tid) { sl->_reentrance++; } else { int i = 0; if (spin_count <= 0) spin_count = DEFAULT_SPIN_COUNT; while (InterlockedCompareExchange((LONG*)&sl->_value, (LONG)tid, 0) != 0) { for (; i < spin_count; ++i) if (sl->_value == 0) break; if (i >= spin_count) Sleep(1); /* yield cpu */ } sl->_reentrance++; } } TOOLKIT_API void spinlock_leave(volatile spinlock_t *sl) { _ReadWriteBarrier(); if (--sl->_reentrance == 0) InterlockedExchange((LONG*)&sl->_value, 0); } TOOLKIT_API void rw_spinlock_read_lock(rw_spinlock_t *rwlock) { union rw_spinlock_barrier bnew, b; for (;;) { bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ; bnew.readerCount++ ; bnew.writerActive = b.writerActive = 0 ; bnew.writerCount = b.writerCount = 0 ; if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic) break; backoff(DEFAULT_SPIN_COUNT) ; } } TOOLKIT_API void rw_spinlock_read_unlock(rw_spinlock_t *rwlock) { union rw_spinlock_barrier bnew, b ; _ReadWriteBarrier(); for (;;) { bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ; bnew.readerCount-- ; assert( b.writerActive == 0 ) ; if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic) break; backoff(DEFAULT_SPIN_COUNT) ; } } TOOLKIT_API void rw_spinlock_write_lock(rw_spinlock_t *rwlock) { union rw_spinlock_barrier bnew, b ; for (;;) { bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ; bnew.writerCount++ ; if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic) break; backoff(DEFAULT_SPIN_COUNT) ; } for (;;) { bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ; bnew.readerCount = b.readerCount = 0 ; b.writerActive = 0 ; bnew.writerActive = 1 ; if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic) break; backoff(DEFAULT_SPIN_COUNT) ; } } TOOLKIT_API void rw_spinlock_write_unlock(rw_spinlock_t *rwlock) { union rw_spinlock_barrier bnew, b ; _ReadWriteBarrier(); for (;;) { bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ; assert( b.writerActive == 1 ) ; assert( b.readerCount == 0 ) ; bnew.writerActive = 0 ; --bnew.writerCount ; if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic) break; backoff(DEFAULT_SPIN_COUNT) ; } } #define BACKOFF_LIMIT 1000 TOOLKIT_API void fastlock_enter( lock_t l ) { int i = 0; int spin_count = 0; int backoffs = 0; while (InterlockedCompareExchange(l, 1, 0) == 1) { for (spin_count = i + 10000; i < spin_count; ++i) { if (*l == 0) break; #ifdef _WIN32 #if _MSC_VER < 1400 __asm { rep nop } #else /*TODO: the debug point locate here and cannot be kill by cmd 'taskkill' when close SpHost in debug env*/ YieldProcessor(); #endif #else __asm__ __volatile__("rep; nop"); /* a.k.a. PAUSE */ #endif //_WIN32 } backoffs++; if (backoffs % BACKOFF_LIMIT == 0) { Sleep(500); } SwitchToThread(); } } int fastlock_tryenter(lock_t l) { int i = 0; int spin_count = 0; int backoffs = 0; while (InterlockedCompareExchange(l, 1, 0) == 1) { for (spin_count = i + 10000; i < spin_count; ++i) { if (*l == 0) break; #ifdef _WIN32 #if _MSC_VER < 1400 __asm { rep nop } #else /*TODO: the debug point locate here and cannot be kill by cmd 'taskkill' when close SpHost in debug env*/ YieldProcessor(); #endif #else __asm__ __volatile__("rep; nop"); /* a.k.a. PAUSE */ #endif //_WIN32 } backoffs++; if (backoffs % BACKOFF_LIMIT == 0) { Sleep(500); if (*l == 0) break; else return 0; } SwitchToThread(); } return 1; }