Mutex.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * Copyright (c)2019 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2023-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_MUTEX_HPP
  14. #define ZT_MUTEX_HPP
  15. #include "Constants.hpp"
  16. #ifdef __UNIX_LIKE__
  17. #include <stdint.h>
  18. #include <stdlib.h>
  19. #include <pthread.h>
  20. namespace ZeroTier {
  21. #if defined(__GNUC__) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
  22. // Inline ticket lock with yield for x64 systems, provides much better performance when there is no contention.
  23. class Mutex
  24. {
  25. public:
  26. ZT_ALWAYS_INLINE Mutex() : nextTicket(0),nowServing(0) {}
  27. ZT_ALWAYS_INLINE void lock() const
  28. {
  29. const uint16_t myTicket = __sync_fetch_and_add(&(const_cast<Mutex *>(this)->nextTicket),1);
  30. while (nowServing != myTicket) {
  31. pthread_yield_np();
  32. __asm__ __volatile__("rep;nop"::);
  33. __asm__ __volatile__("":::"memory");
  34. }
  35. }
  36. ZT_ALWAYS_INLINE void unlock() const { ++(const_cast<Mutex *>(this)->nowServing); }
  37. class Lock
  38. {
  39. public:
  40. ZT_ALWAYS_INLINE Lock(Mutex &m) : _m(&m) { m.lock(); }
  41. ZT_ALWAYS_INLINE Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
  42. ZT_ALWAYS_INLINE ~Lock() { _m->unlock(); }
  43. private:
  44. Mutex *const _m;
  45. };
  46. private:
  47. inline Mutex(const Mutex &) {}
  48. const Mutex &operator=(const Mutex &) { return *this; }
  49. uint16_t nextTicket;
  50. uint16_t nowServing;
  51. };
  52. #else
  53. // libpthread based mutex lock
  54. class Mutex
  55. {
  56. public:
  57. ZT_ALWAYS_INLINE Mutex() { pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); }
  58. ZT_ALWAYS_INLINE ~Mutex() { pthread_mutex_destroy(&_mh); }
  59. ZT_ALWAYS_INLINE void lock() const { pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh)); }
  60. ZT_ALWAYS_INLINE void unlock() const { pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh)); }
  61. class Lock
  62. {
  63. public:
  64. ZT_ALWAYS_INLINE Lock(Mutex &m) : _m(&m) { m.lock(); }
  65. ZT_ALWAYS_INLINE Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
  66. ZT_ALWAYS_INLINE ~Lock() { _m->unlock(); }
  67. private:
  68. Mutex *const _m;
  69. };
  70. private:
  71. inline Mutex(const Mutex &) {}
  72. const Mutex &operator=(const Mutex &) { return *this; }
  73. pthread_mutex_t _mh;
  74. };
  75. #endif
  76. } // namespace ZeroTier
  77. #endif // Apple / Linux
  78. #ifdef __WINDOWS__
  79. #include <stdlib.h>
  80. #include <Windows.h>
  81. namespace ZeroTier {
  82. // Windows critical section based lock
  83. class Mutex
  84. {
  85. public:
  86. ZT_ALWAYS_INLINE Mutex() { InitializeCriticalSection(&_cs); }
  87. ZT_ALWAYS_INLINE ~Mutex() { DeleteCriticalSection(&_cs); }
  88. ZT_ALWAYS_INLINE void lock() { EnterCriticalSection(&_cs); }
  89. ZT_ALWAYS_INLINE void unlock() { LeaveCriticalSection(&_cs); }
  90. ZT_ALWAYS_INLINE void lock() const { (const_cast <Mutex *> (this))->lock(); }
  91. ZT_ALWAYS_INLINE void unlock() const { (const_cast <Mutex *> (this))->unlock(); }
  92. class Lock
  93. {
  94. public:
  95. ZT_ALWAYS_INLINE Lock(Mutex &m) : _m(&m) { m.lock(); }
  96. ZT_ALWAYS_INLINE Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
  97. ZT_ALWAYS_INLINE ~Lock() { _m->unlock(); }
  98. private:
  99. Mutex *const _m;
  100. };
  101. private:
  102. inline Mutex(const Mutex &) {}
  103. const Mutex &operator=(const Mutex &) { return *this; }
  104. CRITICAL_SECTION _cs;
  105. };
  106. } // namespace ZeroTier
  107. #endif // _WIN32
  108. #endif