Mutex.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * You can be released from the requirements of the license by purchasing
  21. * a commercial license. Buying such a license is mandatory as soon as you
  22. * develop commercial closed-source software that incorporates or links
  23. * directly against ZeroTier software without disclosing the source code
  24. * of your own application.
  25. */
  26. #ifndef ZT_MUTEX_HPP
  27. #define ZT_MUTEX_HPP
  28. #include "Constants.hpp"
  29. #ifdef __UNIX_LIKE__
  30. #include <stdint.h>
  31. #include <stdlib.h>
  32. #include <pthread.h>
  33. namespace ZeroTier {
  34. #if defined(__GNUC__) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
  35. // Inline ticket lock on x64 systems with GCC and CLANG (Mac, Linux) -- this is really fast as long as locking durations are very short
  36. class Mutex
  37. {
  38. public:
  39. inline Mutex() :
  40. nextTicket(0),
  41. nowServing(0)
  42. {
  43. }
  44. inline void lock() const
  45. {
  46. const uint16_t myTicket = __sync_fetch_and_add(&(const_cast<Mutex *>(this)->nextTicket),1);
  47. while (nowServing != myTicket) {
  48. __asm__ __volatile__("rep;nop"::);
  49. __asm__ __volatile__("":::"memory");
  50. }
  51. }
  52. inline void unlock() const { ++(const_cast<Mutex *>(this)->nowServing); }
  53. /**
  54. * Uses C++ contexts and constructor/destructor to lock/unlock automatically
  55. */
  56. class Lock
  57. {
  58. public:
  59. inline Lock(Mutex &m) : _m(&m) { m.lock(); }
  60. inline Lock(const Mutex &m) : _m(const_cast<Mutex *>(&m)) { _m->lock(); }
  61. inline ~Lock() { _m->unlock(); }
  62. private:
  63. Mutex *const _m;
  64. };
  65. private:
  66. inline Mutex(const Mutex &) {}
  67. const Mutex &operator=(const Mutex &) { return *this; }
  68. uint16_t nextTicket;
  69. uint16_t nowServing;
  70. };
  71. #else
  72. // libpthread based mutex lock
  73. class Mutex
  74. {
  75. public:
  76. inline Mutex()
  77. {
  78. pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0);
  79. }
  80. inline ~Mutex()
  81. {
  82. pthread_mutex_destroy(&_mh);
  83. }
  84. inline void lock() const
  85. {
  86. pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh));
  87. }
  88. inline void unlock() const
  89. {
  90. pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh));
  91. }
  92. class Lock
  93. {
  94. public:
  95. inline Lock(Mutex &m) :
  96. _m(&m)
  97. {
  98. m.lock();
  99. }
  100. inline Lock(const Mutex &m) :
  101. _m(const_cast<Mutex *>(&m))
  102. {
  103. _m->lock();
  104. }
  105. inline ~Lock()
  106. {
  107. _m->unlock();
  108. }
  109. private:
  110. Mutex *const _m;
  111. };
  112. private:
  113. inline Mutex(const Mutex &) {}
  114. const Mutex &operator=(const Mutex &) { return *this; }
  115. pthread_mutex_t _mh;
  116. };
  117. #endif
  118. } // namespace ZeroTier
  119. #endif // Apple / Linux
  120. #ifdef __WINDOWS__
  121. #include <stdlib.h>
  122. #include <Windows.h>
  123. namespace ZeroTier {
  124. // Windows critical section based lock
  125. class Mutex
  126. {
  127. public:
  128. inline Mutex()
  129. {
  130. InitializeCriticalSection(&_cs);
  131. }
  132. inline ~Mutex()
  133. {
  134. DeleteCriticalSection(&_cs);
  135. }
  136. inline void lock()
  137. {
  138. EnterCriticalSection(&_cs);
  139. }
  140. inline void unlock()
  141. {
  142. LeaveCriticalSection(&_cs);
  143. }
  144. inline void lock() const
  145. {
  146. (const_cast <Mutex *> (this))->lock();
  147. }
  148. inline void unlock() const
  149. {
  150. (const_cast <Mutex *> (this))->unlock();
  151. }
  152. class Lock
  153. {
  154. public:
  155. inline Lock(Mutex &m) :
  156. _m(&m)
  157. {
  158. m.lock();
  159. }
  160. inline Lock(const Mutex &m) :
  161. _m(const_cast<Mutex *>(&m))
  162. {
  163. _m->lock();
  164. }
  165. inline ~Lock()
  166. {
  167. _m->unlock();
  168. }
  169. private:
  170. Mutex *const _m;
  171. };
  172. private:
  173. inline Mutex(const Mutex &) {}
  174. const Mutex &operator=(const Mutex &) { return *this; }
  175. CRITICAL_SECTION _cs;
  176. };
  177. } // namespace ZeroTier
  178. #endif // _WIN32
  179. #endif