mutex.hpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Stephen Cleary 2000
  4. // (C) Copyright Ion Gaztanaga 2015-2017.
  5. //
  6. // Distributed under the Boost
  7. // Software License, Version 1.0. (See accompanying file
  8. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // See http://www.boost.org/libs/container for documentation.
  11. //
  12. //////////////////////////////////////////////////////////////////////////////
  13. #ifndef BOOST_CONTAINER_MUTEX_HPP
  14. #define BOOST_CONTAINER_MUTEX_HPP
  15. #ifndef BOOST_CONFIG_HPP
  16. # include <boost/config.hpp>
  17. #endif
  18. #if defined(BOOST_HAS_PRAGMA_ONCE)
  19. # pragma once
  20. #endif
  21. //#define BOOST_CONTAINER_NO_MT
  22. //#define BOOST_CONTAINER_NO_SPINLOCKS
  23. #include <boost/container/detail/config_begin.hpp>
  24. #include <boost/container/detail/workaround.hpp>
  25. // Extremely Light-Weight wrapper classes for OS thread synchronization
  26. #define BOOST_MUTEX_HELPER_NONE 0
  27. #define BOOST_MUTEX_HELPER_WIN32 1
  28. #define BOOST_MUTEX_HELPER_PTHREAD 2
  29. #define BOOST_MUTEX_HELPER_SPINLOCKS 3
  30. #if !defined(BOOST_HAS_THREADS) && !defined(BOOST_NO_MT)
  31. # define BOOST_NO_MT
  32. #endif
  33. #if defined(BOOST_NO_MT) || defined(BOOST_CONTAINER_NO_MT)
  34. // No multithreading -> make locks into no-ops
  35. #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_NONE
  36. #else
  37. //Taken from dlmalloc
  38. #if !defined(BOOST_CONTAINER_NO_SPINLOCKS) && \
  39. ((defined(__GNUC__) && \
  40. ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \
  41. defined(__i386__) || defined(__x86_64__))) || \
  42. (defined(_MSC_VER) && _MSC_VER>=1310))
  43. #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_SPINLOCKS
  44. #endif
  45. #if defined(BOOST_WINDOWS)
  46. #include <boost/winapi/critical_section.hpp>
  47. #include <boost/winapi/thread.hpp>
  48. #ifndef BOOST_MUTEX_HELPER
  49. #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_WIN32
  50. #endif
  51. #elif defined(BOOST_HAS_UNISTD_H)
  52. #include <unistd.h>
  53. #if !defined(BOOST_MUTEX_HELPER) && (defined(_POSIX_THREADS) || defined(BOOST_HAS_PTHREADS))
  54. #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_PTHREAD
  55. #endif
  56. #endif
  57. #endif
  58. #ifndef BOOST_MUTEX_HELPER
  59. #error Unable to determine platform mutex type; #define BOOST_NO_MT to assume single-threaded
  60. #endif
  61. #if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE
  62. //...
  63. #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS
  64. #if defined(_MSC_VER)
  65. #include <boost/detail/interlocked.hpp>
  66. #define interlockedcompareexchange _InterlockedCompareExchange
  67. #define interlockedexchange _InterlockedExchange
  68. #elif defined(WIN32) && defined(__GNUC__)
  69. #define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b)
  70. #define interlockedexchange __sync_lock_test_and_set
  71. #endif /* Win32 */
  72. /* First, define CAS_LOCK and CLEAR_LOCK on ints */
  73. /* Note CAS_LOCK defined to return 0 on success */
  74. #if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
  75. #define BOOST_CONTAINER_CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1)
  76. #define BOOST_CONTAINER_CLEAR_LOCK(sl) __sync_lock_release(sl)
  77. #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
  78. /* Custom spin locks for older gcc on x86 */
  79. static inline int boost_container_x86_cas_lock(int *sl) {
  80. int ret;
  81. int val = 1;
  82. int cmp = 0;
  83. __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
  84. : "=a" (ret)
  85. : "r" (val), "m" (*(sl)), "0"(cmp)
  86. : "memory", "cc");
  87. return ret;
  88. }
  89. static inline void boost_container_x86_clear_lock(int* sl) {
  90. assert(*sl != 0);
  91. int prev = 0;
  92. int ret;
  93. __asm__ __volatile__ ("lock; xchgl %0, %1"
  94. : "=r" (ret)
  95. : "m" (*(sl)), "0"(prev)
  96. : "memory");
  97. }
  98. #define BOOST_CONTAINER_CAS_LOCK(sl) boost_container_x86_cas_lock(sl)
  99. #define BOOST_CONTAINER_CLEAR_LOCK(sl) boost_container_x86_clear_lock(sl)
  100. #else /* Win32 MSC */
  101. #define BOOST_CONTAINER_CAS_LOCK(sl) interlockedexchange((long volatile*)sl, (long)1)
  102. #define BOOST_CONTAINER_CLEAR_LOCK(sl) interlockedexchange((long volatile*)sl, (long)0)
  103. #endif
  104. /* How to yield for a spin lock */
  105. #define SPINS_PER_YIELD 63
  106. #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
  107. #define SLEEP_EX_DURATION 50 /* delay for yield/sleep */
  108. #define SPIN_LOCK_YIELD boost::winapi::SleepEx(SLEEP_EX_DURATION, 0)
  109. #elif defined (__SVR4) && defined (__sun) /* solaris */
  110. #include <thread.h>
  111. #define SPIN_LOCK_YIELD thr_yield();
  112. #elif !defined(LACKS_SCHED_H)
  113. #include <sched.h>
  114. #define SPIN_LOCK_YIELD sched_yield();
  115. #else
  116. #define SPIN_LOCK_YIELD
  117. #endif /* ... yield ... */
  118. #define BOOST_CONTAINER_SPINS_PER_YIELD 63
  119. inline int boost_interprocess_spin_acquire_lock(int *sl) {
  120. int spins = 0;
  121. while (*(volatile int *)sl != 0 ||
  122. BOOST_CONTAINER_CAS_LOCK(sl)) {
  123. if ((++spins & BOOST_CONTAINER_SPINS_PER_YIELD) == 0) {
  124. SPIN_LOCK_YIELD;
  125. }
  126. }
  127. return 0;
  128. }
  129. #define BOOST_CONTAINER_MLOCK_T int
  130. #define BOOST_CONTAINER_TRY_LOCK(sl) !BOOST_CONTAINER_CAS_LOCK(sl)
  131. #define BOOST_CONTAINER_RELEASE_LOCK(sl) BOOST_CONTAINER_CLEAR_LOCK(sl)
  132. #define BOOST_CONTAINER_ACQUIRE_LOCK(sl) (BOOST_CONTAINER_CAS_LOCK(sl)? boost_interprocess_spin_acquire_lock(sl) : 0)
  133. #define BOOST_MOVE_INITIAL_LOCK(sl) (*sl = 0)
  134. #define BOOST_CONTAINER_DESTROY_LOCK(sl) (0)
  135. #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32
  136. //
  137. #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD
  138. #include <pthread.h>
  139. #endif
  140. namespace boost {
  141. namespace container {
  142. namespace dtl {
  143. #if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE
  144. class null_mutex
  145. {
  146. private:
  147. null_mutex(const null_mutex &);
  148. void operator=(const null_mutex &);
  149. public:
  150. null_mutex() { }
  151. static void lock() { }
  152. static void unlock() { }
  153. };
  154. typedef null_mutex default_mutex;
  155. #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS
  156. class spin_mutex
  157. {
  158. private:
  159. BOOST_CONTAINER_MLOCK_T sl;
  160. spin_mutex(const spin_mutex &);
  161. void operator=(const spin_mutex &);
  162. public:
  163. spin_mutex() { BOOST_MOVE_INITIAL_LOCK(&sl); }
  164. void lock() { BOOST_CONTAINER_ACQUIRE_LOCK(&sl); }
  165. void unlock() { BOOST_CONTAINER_RELEASE_LOCK(&sl); }
  166. };
  167. typedef spin_mutex default_mutex;
  168. #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32
  169. class mutex
  170. {
  171. private:
  172. CRITICAL_SECTION mtx;
  173. mutex(const mutex &);
  174. void operator=(const mutex &);
  175. public:
  176. mutex()
  177. { InitializeCriticalSection(&mtx); }
  178. ~mutex()
  179. { DeleteCriticalSection(&mtx); }
  180. void lock()
  181. { EnterCriticalSection(&mtx); }
  182. void unlock()
  183. { LeaveCriticalSection(&mtx); }
  184. };
  185. typedef mutex default_mutex;
  186. #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD
  187. class mutex
  188. {
  189. private:
  190. pthread_mutex_t mtx;
  191. mutex(const mutex &);
  192. void operator=(const mutex &);
  193. public:
  194. mutex()
  195. { pthread_mutex_init(&mtx, 0); }
  196. ~mutex()
  197. { pthread_mutex_destroy(&mtx); }
  198. void lock()
  199. { pthread_mutex_lock(&mtx); }
  200. void unlock()
  201. { pthread_mutex_unlock(&mtx); }
  202. };
  203. typedef mutex default_mutex;
  204. #endif
  205. template<class Mutex>
  206. class scoped_lock
  207. {
  208. public:
  209. scoped_lock(Mutex &m)
  210. : m_(m)
  211. { m_.lock(); }
  212. ~scoped_lock()
  213. { m_.unlock(); }
  214. private:
  215. Mutex &m_;
  216. };
  217. } // namespace dtl
  218. } // namespace container
  219. } // namespace boost
  220. #undef BOOST_MUTEX_HELPER_WIN32
  221. #undef BOOST_MUTEX_HELPER_PTHREAD
  222. #undef BOOST_MUTEX_HELPER_NONE
  223. #undef BOOST_MUTEX_HELPER
  224. #undef BOOST_MUTEX_HELPER_SPINLOCKS
  225. #include <boost/container/detail/config_end.hpp>
  226. #endif