spinlock.h 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #pragma once
  2. #include "atomic.h"
  3. #include "spin_wait.h"
  4. class TSpinLockBase {
  5. protected:
  6. inline TSpinLockBase() noexcept {
  7. AtomicSet(Val_, 0);
  8. }
  9. public:
  10. inline bool IsLocked() const noexcept {
  11. return AtomicGet(Val_);
  12. }
  13. inline bool TryAcquire() noexcept {
  14. return AtomicTryLock(&Val_);
  15. }
  16. inline bool try_lock() noexcept {
  17. return TryAcquire();
  18. }
  19. protected:
  20. TAtomic Val_;
  21. };
  22. static inline void SpinLockPause() {
  23. #if defined(__GNUC__)
  24. #if defined(_i386_) || defined(_x86_64_)
  25. __asm __volatile("pause");
  26. #elif defined(_arm64_)
  27. __asm __volatile("yield" ::
  28. : "memory");
  29. #endif
  30. #endif
  31. }
  32. static inline void AcquireSpinLock(TAtomic* l) {
  33. if (!AtomicTryLock(l)) {
  34. do {
  35. SpinLockPause();
  36. } while (!AtomicTryAndTryLock(l));
  37. }
  38. }
  39. static inline void ReleaseSpinLock(TAtomic* l) {
  40. AtomicUnlock(l);
  41. }
  42. /*
  43. * You should almost always use TAdaptiveLock instead of TSpinLock
  44. */
  45. class TSpinLock: public TSpinLockBase {
  46. public:
  47. using TSpinLockBase::TSpinLockBase;
  48. inline void Release() noexcept {
  49. ReleaseSpinLock(&Val_);
  50. }
  51. inline void Acquire() noexcept {
  52. AcquireSpinLock(&Val_);
  53. }
  54. inline void unlock() noexcept {
  55. Release();
  56. }
  57. inline void lock() noexcept {
  58. Acquire();
  59. }
  60. };
  61. static inline void AcquireAdaptiveLock(TAtomic* l) {
  62. if (!AtomicTryLock(l)) {
  63. TSpinWait sw;
  64. while (!AtomicTryAndTryLock(l)) {
  65. sw.Sleep();
  66. }
  67. }
  68. }
  69. static inline void ReleaseAdaptiveLock(TAtomic* l) {
  70. AtomicUnlock(l);
  71. }
  72. class TAdaptiveLock: public TSpinLockBase {
  73. public:
  74. using TSpinLockBase::TSpinLockBase;
  75. inline void Release() noexcept {
  76. ReleaseAdaptiveLock(&Val_);
  77. }
  78. inline void Acquire() noexcept {
  79. AcquireAdaptiveLock(&Val_);
  80. }
  81. inline void unlock() noexcept {
  82. Release();
  83. }
  84. inline void lock() noexcept {
  85. Acquire();
  86. }
  87. };
  88. #include "guard.h"
  89. template <>
  90. struct TCommonLockOps<TAtomic> {
  91. static inline void Acquire(TAtomic* v) noexcept {
  92. AcquireAdaptiveLock(v);
  93. }
  94. static inline bool TryAcquire(TAtomic* v) noexcept {
  95. return AtomicTryLock(v);
  96. }
  97. static inline void Release(TAtomic* v) noexcept {
  98. ReleaseAdaptiveLock(v);
  99. }
  100. };