Mutex.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Copyright (c)2013-2020 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: 2024-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. #include <cstdint>
  17. #include <cstdlib>
  18. #ifndef __WINDOWS__
  19. #include <pthread.h>
  20. #endif
  21. namespace ZeroTier {
  22. class Mutex
  23. {
  24. public:
  25. ZT_INLINE Mutex() noexcept { pthread_mutex_init(&_mh,nullptr); }
  26. ZT_INLINE ~Mutex() noexcept { pthread_mutex_destroy(&_mh); }
  27. ZT_INLINE void lock() const noexcept { pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh)); }
  28. ZT_INLINE void unlock() const noexcept { pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh)); }
  29. class Lock
  30. {
  31. public:
  32. explicit ZT_INLINE Lock(Mutex &m) noexcept : _m(&m) { m.lock(); }
  33. explicit ZT_INLINE Lock(const Mutex &m) noexcept : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
  34. ZT_INLINE ~Lock() { _m->unlock(); }
  35. private:
  36. Mutex *const _m;
  37. };
  38. private:
  39. ZT_INLINE Mutex(const Mutex &) noexcept {}
  40. ZT_INLINE const Mutex &operator=(const Mutex &) noexcept { return *this; }
  41. pthread_mutex_t _mh;
  42. };
  43. class RWMutex
  44. {
  45. public:
  46. ZT_INLINE RWMutex() noexcept { pthread_rwlock_init(&_mh,nullptr); }
  47. ZT_INLINE ~RWMutex() noexcept { pthread_rwlock_destroy(&_mh); }
  48. ZT_INLINE void lock() const noexcept { pthread_rwlock_wrlock(&((const_cast <RWMutex *> (this))->_mh)); }
  49. ZT_INLINE void rlock() const noexcept { pthread_rwlock_rdlock(&((const_cast <RWMutex *> (this))->_mh)); }
  50. ZT_INLINE void unlock() const noexcept { pthread_rwlock_unlock(&((const_cast <RWMutex *> (this))->_mh)); }
  51. ZT_INLINE void runlock() const noexcept { pthread_rwlock_unlock(&((const_cast <RWMutex *> (this))->_mh)); }
  52. /**
  53. * RAAI locker that acquires only the read lock (shared read)
  54. */
  55. class RLock
  56. {
  57. public:
  58. explicit ZT_INLINE RLock(RWMutex &m) noexcept : _m(&m) { m.rlock(); }
  59. explicit ZT_INLINE RLock(const RWMutex &m) noexcept : _m(const_cast<RWMutex *>(&m)) { _m->rlock(); }
  60. ZT_INLINE ~RLock() { _m->runlock(); }
  61. private:
  62. RWMutex *const _m;
  63. };
  64. /**
  65. * RAAI locker that acquires the write lock (exclusive write, no readers)
  66. */
  67. class Lock
  68. {
  69. public:
  70. explicit ZT_INLINE Lock(RWMutex &m) noexcept : _m(&m) { m.lock(); }
  71. explicit ZT_INLINE Lock(const RWMutex &m) noexcept : _m(const_cast<RWMutex *>(&m)) { _m->lock(); }
  72. ZT_INLINE ~Lock() { _m->unlock(); }
  73. private:
  74. RWMutex *const _m;
  75. };
  76. /**
  77. * RAAI locker that acquires the read lock first and can switch modes
  78. *
  79. * Use writing() to acquire the write lock if not already acquired. Use reading() to
  80. * let go of the write lock and go back to only holding the read lock.
  81. */
  82. class RMaybeWLock
  83. {
  84. public:
  85. explicit ZT_INLINE RMaybeWLock(RWMutex &m) noexcept : _m(&m),_w(false) { m.rlock(); }
  86. explicit ZT_INLINE RMaybeWLock(const RWMutex &m) noexcept : _m(const_cast<RWMutex *>(&m)),_w(false) { _m->rlock(); }
  87. ZT_INLINE void writing() noexcept { if (!_w) { _w = true; _m->runlock(); _m->lock(); } }
  88. ZT_INLINE void reading() noexcept { if (_w) { _w = false; _m->unlock(); _m->rlock(); } }
  89. ZT_INLINE ~RMaybeWLock() { if (_w) _m->unlock(); else _m->runlock(); }
  90. private:
  91. RWMutex *const _m;
  92. bool _w;
  93. };
  94. private:
  95. ZT_INLINE RWMutex(const RWMutex &) noexcept {}
  96. ZT_INLINE const RWMutex &operator=(const RWMutex &) noexcept { return *this; }
  97. pthread_rwlock_t _mh;
  98. };
  99. } // namespace ZeroTier
  100. #if 0
  101. #include <Windows.h>
  102. namespace ZeroTier {
  103. class Mutex
  104. {
  105. public:
  106. ZT_INLINE Mutex() { InitializeCriticalSection(&_cs); }
  107. ZT_INLINE ~Mutex() { DeleteCriticalSection(&_cs); }
  108. ZT_INLINE void lock() { EnterCriticalSection(&_cs); }
  109. ZT_INLINE void unlock() { LeaveCriticalSection(&_cs); }
  110. ZT_INLINE void lock() const { (const_cast <Mutex *> (this))->lock(); }
  111. ZT_INLINE void unlock() const { (const_cast <Mutex *> (this))->unlock(); }
  112. class Lock
  113. {
  114. public:
  115. ZT_INLINE Lock(Mutex &m) : _m(&m) { m.lock(); }
  116. ZT_INLINE Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
  117. ZT_INLINE ~Lock() { _m->unlock(); }
  118. private:
  119. Mutex *const _m;
  120. };
  121. private:
  122. ZT_INLINE Mutex(const Mutex &) {}
  123. ZT_INLINE const Mutex &operator=(const Mutex &) { return *this; }
  124. CRITICAL_SECTION _cs;
  125. };
  126. } // namespace ZeroTier
  127. #endif
  128. #endif