spinlock.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #include "precompile.h"
  2. #include "spinlock.h"
  3. // please refer http://book.opensourceproject.org.cn/kernel/kernel3rd/opensource/0596005652/understandlk-chp-5-sect-2.html
  4. static __inline void backoff(unsigned int nloop)
  5. {
  6. __asm {
  7. and ecx, nloop ;
  8. cmovz ecx, nloop ;
  9. rep nop ;
  10. }
  11. }
  12. TOOLKIT_API void spinlock_enter(volatile spinlock_t *sl, int spin_count)
  13. {
  14. DWORD tid = GetCurrentThreadId();
  15. if (sl->_value == tid) {
  16. sl->_reentrance++;
  17. } else {
  18. int i = 0;
  19. if (spin_count <= 0)
  20. spin_count = DEFAULT_SPIN_COUNT;
  21. while (InterlockedCompareExchange((LONG*)&sl->_value, (LONG)tid, 0) != 0) {
  22. for (; i < spin_count; ++i)
  23. if (sl->_value == 0)
  24. break;
  25. if (i >= spin_count)
  26. Sleep(1); /* yield cpu */
  27. }
  28. sl->_reentrance++;
  29. }
  30. }
  31. TOOLKIT_API void spinlock_leave(volatile spinlock_t *sl)
  32. {
  33. _ReadWriteBarrier();
  34. if (--sl->_reentrance == 0)
  35. InterlockedExchange((LONG*)&sl->_value, 0);
  36. }
  37. TOOLKIT_API void rw_spinlock_read_lock(rw_spinlock_t *rwlock)
  38. {
  39. union rw_spinlock_barrier bnew, b;
  40. for (;;) {
  41. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  42. bnew.readerCount++ ;
  43. bnew.writerActive = b.writerActive = 0 ;
  44. bnew.writerCount = b.writerCount = 0 ;
  45. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  46. break;
  47. backoff(DEFAULT_SPIN_COUNT) ;
  48. }
  49. }
  50. TOOLKIT_API void rw_spinlock_read_unlock(rw_spinlock_t *rwlock)
  51. {
  52. union rw_spinlock_barrier bnew, b ;
  53. _ReadWriteBarrier();
  54. for (;;) {
  55. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  56. bnew.readerCount-- ;
  57. assert( b.writerActive == 0 ) ;
  58. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  59. break;
  60. backoff(DEFAULT_SPIN_COUNT) ;
  61. }
  62. }
  63. TOOLKIT_API void rw_spinlock_write_lock(rw_spinlock_t *rwlock)
  64. {
  65. union rw_spinlock_barrier bnew, b ;
  66. for (;;) {
  67. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  68. bnew.writerCount++ ;
  69. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  70. break;
  71. backoff(DEFAULT_SPIN_COUNT) ;
  72. }
  73. for (;;) {
  74. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  75. bnew.readerCount =
  76. b.readerCount = 0 ;
  77. b.writerActive = 0 ;
  78. bnew.writerActive = 1 ;
  79. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  80. break;
  81. backoff(DEFAULT_SPIN_COUNT) ;
  82. }
  83. }
  84. TOOLKIT_API void rw_spinlock_write_unlock(rw_spinlock_t *rwlock)
  85. {
  86. union rw_spinlock_barrier bnew, b ;
  87. _ReadWriteBarrier();
  88. for (;;) {
  89. bnew.nAtomic = b.nAtomic = rwlock->barrier.nAtomic ;
  90. assert( b.writerActive == 1 ) ;
  91. assert( b.readerCount == 0 ) ;
  92. bnew.writerActive = 0 ;
  93. --bnew.writerCount ;
  94. if (InterlockedCompareExchange(&rwlock->barrier.nAtomic, bnew.nAtomic, b.nAtomic) == b.nAtomic)
  95. break;
  96. backoff(DEFAULT_SPIN_COUNT) ;
  97. }
  98. }
  99. #define BACKOFF_LIMIT 1000
  100. TOOLKIT_API void fastlock_enter( lock_t l )
  101. {
  102. int i = 0;
  103. int spin_count = 0;
  104. int backoffs = 0;
  105. while (InterlockedCompareExchange(l, 1, 0) == 1) {
  106. for (spin_count = i + 10000; i < spin_count; ++i) {
  107. if (*l == 0)
  108. break;
  109. #if _MSC_VER < 1400
  110. __asm { rep nop }
  111. #else
  112. YieldProcessor(); //关闭sphost时,调试在这里停止,且无法通过taskkill关闭sphost
  113. #endif
  114. }
  115. backoffs++;
  116. if (backoffs % BACKOFF_LIMIT == 0) {
  117. Sleep(500);
  118. }
  119. SwitchToThread();
  120. }
  121. }