You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
2.0 KiB

1 year ago
  1. #pragma once
  2. #include <atomic>
  3. #include <mutex>
  4. #ifdef __powerpc__
  5. #include "../../arch/powerpc/include/uapi/asm/unistd.h"
  6. #endif
  7. // Simple spinlock mutex based on std::atomic_flag
  8. // Compatible with std::lock_guard
  9. namespace vlc
  10. {
  11. #if defined(_WIN32)
  12. #if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_ARM) )
  13. extern "C" void YieldProcessor();
  14. #else
  15. extern "C" void _mm_pause();
  16. #endif
  17. #endif
  18. static inline void cpu_relax()
  19. {
  20. #if defined(__arc__) || defined(__mips__) || defined(__arm__) || defined(__powerpc__)
  21. asm volatile("" ::: "memory");
  22. #elif defined(__i386__) || defined(__x86_64__)
  23. asm volatile("rep; nop" ::: "memory");
  24. #elif defined(__aarch64__)
  25. asm volatile("yield" ::: "memory");
  26. #elif defined(__ia64__)
  27. asm volatile ("hint @pause" ::: "memory");
  28. #elif defined(_WIN32)
  29. #if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_ARM) )
  30. YieldProcessor();
  31. #else
  32. _mm_pause();
  33. #endif
  34. #endif
  35. }
  36. // Optimized Spinlock implementation
  37. // Reference https://rigtorp.se/spinlock/
  38. class Spinlock
  39. {
  40. public:
  41. Spinlock() : m_lock(false)
  42. {
  43. }
  44. Spinlock(const Spinlock&) = delete;
  45. Spinlock& operator = (const Spinlock&) = delete;
  46. void lock() noexcept
  47. {
  48. for (;;)
  49. {
  50. // Optimistically assume the lock is free on the first try
  51. if (!m_lock.exchange(true, std::memory_order_acquire))
  52. return;
  53. while (m_lock.load(std::memory_order_relaxed))
  54. {
  55. // Hint CPU that we're in spin-wait loop
  56. cpu_relax();
  57. }
  58. }
  59. }
  60. bool try_lock() noexcept
  61. {
  62. // Check first that we have free lock without CAS
  63. // because CAS writes to destination memory even if comparison failed
  64. // so we can reduce memory traffic just by prior checking for free lock
  65. return !m_lock.load(std::memory_order_relaxed) &&
  66. !m_lock.exchange(true, std::memory_order_acquire);
  67. }
  68. void unlock() noexcept
  69. {
  70. m_lock.store(false, std::memory_order_release);
  71. }
  72. private:
  73. std::atomic<bool> m_lock;
  74. };
  75. using SpinlockGuard = std::lock_guard<Spinlock>;
  76. }