#include "precompile.h" #include "spinlock.h" static void tkspause() { #if defined __x86_64__ || defined __i386__ #ifdef __SSE2__ __asm__ __volatile__ ("pause"); #else __asm__ __volatile__ ("rep; nop"); #endif #elif defined __arm__ #if __ARM_ARCH == 7 __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); #endif #elif defined __OCTEON__ __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); #elif defined __powerpc__ __asm__ __volatile__ ("ori 27, 27, 27"); #endif } // 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 #if defined _WIN32 // __x86_64__ || defined __i386__ __asm { and ecx, nloop; cmovz ecx, nloop; rep nop; } #elif defined(__linux__) #if defined(__arm__) || defined(__aarch64__) //TODO: #else //TODO: need to confirm its correctness. __asm__ __volatile__ ("and %edi, %ecx;" "cmovz %edi, %ecx;" "rep;" "nop"); #endif #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-- ; TOOLKIT_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 ; TOOLKIT_ASSERT( b.writerActive == 1 ) ; TOOLKIT_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; #if defined(_MSC_VER) #if _MSC_VER < 1400 __asm { rep nop } #else YieldProcessor(); //关闭sphost时,调试在这里停止,且无法通过taskkill关闭sphost #endif #else tkspause(); #endif //_MSC_VER } 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; #if defined(_MSC_VER) #if _MSC_VER < 1400 __asm { rep nop } #else YieldProcessor(); //关闭sphost时,调试在这里停止,且无法通过taskkill关闭sphost #endif #else tkspause(); #endif //_MSC_VER } backoffs++; if (backoffs % BACKOFF_LIMIT == 0) { Sleep(500); if (*l == 0) break; else return 0; } SwitchToThread(); } return 1; }