spinlock.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #include "precompile.h"
  2. #include "spinlock.h"
  3. static void tkspause()
  4. {
  5. #if defined __x86_64__ || defined __i386__
  6. #ifdef __SSE2__
  7. __asm__ __volatile__ ("pause");
  8. #else
  9. __asm__ __volatile__ ("rep; nop");
  10. #endif
  11. #elif defined __arm__
  12. #if __ARM_ARCH == 7
  13. __asm__ __volatile__ ("nop");
  14. __asm__ __volatile__ ("nop");
  15. __asm__ __volatile__ ("nop");
  16. __asm__ __volatile__ ("nop");
  17. #endif
  18. #elif defined __OCTEON__
  19. __asm__ __volatile__ ("nop");
  20. __asm__ __volatile__ ("nop");
  21. __asm__ __volatile__ ("nop");
  22. __asm__ __volatile__ ("nop");
  23. __asm__ __volatile__ ("nop");
  24. __asm__ __volatile__ ("nop");
  25. __asm__ __volatile__ ("nop");
  26. __asm__ __volatile__ ("nop");
  27. #elif defined __powerpc__
  28. __asm__ __volatile__ ("ori 27, 27, 27");
  29. #endif
  30. }
  31. // please refer http://book.opensourceproject.org.cn/kernel/kernel3rd/opensource/0596005652/understandlk-chp-5-sect-2.html
  32. static __inline void backoff(unsigned int nloop)
  33. {
  34. //and d, s d <- d & s
  35. //if ZF d, s
  36. #if defined _WIN32 // __x86_64__ || defined __i386__
  37. __asm {
  38. and ecx, nloop;
  39. cmovz ecx, nloop;
  40. rep nop;
  41. }
  42. #elif defined(__linux__)
  43. #if defined(__arm__) || defined(__aarch64__)
  44. //TODO:
  45. #else
  46. //TODO: need to confirm its correctness.
  47. __asm__ __volatile__ ("and %edi, %ecx;"
  48. "cmovz %edi, %ecx;"
  49. "rep;"
  50. "nop");
  51. #endif
  52. #endif
  53. }
  54. TOOLKIT_API void spinlock_enter(volatile spinlock_t *sl, int spin_count)
  55. {
  56. DWORD tid = GetCurrentThreadId();
  57. if (sl->_value == tid) {
  58. sl->_reentrance++;
  59. } else {
  60. int i = 0;
  61. if (spin_count <= 0)
  62. spin_count = DEFAULT_SPIN_COUNT;
  63. while (InterlockedCompareExchange((LONG*)&sl->_value, (LONG)tid, 0) != 0) {
  64. for (; i < spin_count; ++i)
  65. if (sl->_value == 0)
  66. break;
  67. if (i >= spin_count)
  68. Sleep(1); /* yield cpu */
  69. }
  70. sl->_reentrance++;
  71. }
  72. }
  73. TOOLKIT_API void spinlock_leave(volatile spinlock_t *sl)
  74. {
  75. _ReadWriteBarrier();
  76. if (--sl->_reentrance == 0)
  77. InterlockedExchange((LONG*)&sl->_value, 0);
  78. }
  79. TOOLKIT_API void rw_spinlock_read_lock(rw_spinlock_t *rwlock)
  80. {
  81. union rw_spinlock_barrier bnew, b;
  82. for (;;) {
  83. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  84. bnew.readerCount++ ;
  85. bnew.writerActive = b.writerActive = 0 ;
  86. bnew.writerCount = b.writerCount = 0 ;
  87. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  88. break;
  89. backoff(DEFAULT_SPIN_COUNT) ;
  90. }
  91. }
  92. TOOLKIT_API void rw_spinlock_read_unlock(rw_spinlock_t *rwlock)
  93. {
  94. union rw_spinlock_barrier bnew, b ;
  95. _ReadWriteBarrier();
  96. for (;;) {
  97. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  98. bnew.readerCount-- ;
  99. TOOLKIT_ASSERT( b.writerActive == 0 ) ;
  100. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  101. break;
  102. backoff(DEFAULT_SPIN_COUNT) ;
  103. }
  104. }
  105. TOOLKIT_API void rw_spinlock_write_lock(rw_spinlock_t *rwlock)
  106. {
  107. union rw_spinlock_barrier bnew, b ;
  108. for (;;) {
  109. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  110. bnew.writerCount++ ;
  111. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  112. break;
  113. backoff(DEFAULT_SPIN_COUNT) ;
  114. }
  115. for (;;) {
  116. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  117. bnew.readerCount =
  118. b.readerCount = 0 ;
  119. b.writerActive = 0 ;
  120. bnew.writerActive = 1 ;
  121. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  122. break;
  123. backoff(DEFAULT_SPIN_COUNT) ;
  124. }
  125. }
  126. TOOLKIT_API void rw_spinlock_write_unlock(rw_spinlock_t *rwlock)
  127. {
  128. union rw_spinlock_barrier bnew, b ;
  129. _ReadWriteBarrier();
  130. for (;;) {
  131. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  132. TOOLKIT_ASSERT( b.writerActive == 1 ) ;
  133. TOOLKIT_ASSERT( b.readerCount == 0 ) ;
  134. bnew.writerActive = 0 ;
  135. --bnew.writerCount ;
  136. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  137. break;
  138. backoff(DEFAULT_SPIN_COUNT) ;
  139. }
  140. }
  141. #define BACKOFF_LIMIT 1000
  142. TOOLKIT_API void fastlock_enter( lock_t l )
  143. {
  144. int i = 0;
  145. int spin_count = 0;
  146. int backoffs = 0;
  147. while (InterlockedCompareExchange(l, 1, 0) == 1) {
  148. for (spin_count = i + 10000; i < spin_count; ++i) {
  149. if (*l == 0)
  150. break;
  151. #if defined(_MSC_VER)
  152. #if _MSC_VER < 1400
  153. __asm { rep nop }
  154. #else
  155. YieldProcessor(); //关闭sphost时,调试在这里停止,且无法通过taskkill关闭sphost
  156. #endif
  157. #else
  158. tkspause();
  159. #endif //_MSC_VER
  160. }
  161. backoffs++;
  162. if (backoffs % BACKOFF_LIMIT == 0) {
  163. Sleep(500);
  164. }
  165. SwitchToThread();
  166. }
  167. }
  168. int fastlock_tryenter(lock_t l)
  169. {
  170. int i = 0;
  171. int spin_count = 0;
  172. int backoffs = 0;
  173. while (InterlockedCompareExchange(l, 1, 0) == 1) {
  174. for (spin_count = i + 10000; i < spin_count; ++i) {
  175. if (*l == 0)
  176. break;
  177. #if defined(_MSC_VER)
  178. #if _MSC_VER < 1400
  179. __asm { rep nop }
  180. #else
  181. YieldProcessor(); //关闭sphost时,调试在这里停止,且无法通过taskkill关闭sphost
  182. #endif
  183. #else
  184. tkspause();
  185. #endif //_MSC_VER
  186. }
  187. backoffs++;
  188. if (backoffs % BACKOFF_LIMIT == 0) {
  189. Sleep(500);
  190. if (*l == 0)
  191. break;
  192. else
  193. return 0;
  194. }
  195. SwitchToThread();
  196. }
  197. return 1;
  198. }