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 14 #ifndef BOOST_CONTAINER_MUTEX_HPP 15 #define BOOST_CONTAINER_MUTEX_HPP 16 17 #ifndef BOOST_CONFIG_HPP 18 # include <boost/config.hpp> 19 #endif 20 21 #if defined(BOOST_HAS_PRAGMA_ONCE) 22 # pragma once 23 #endif 24 25 //#define BOOST_CONTAINER_NO_MT 26 //#define BOOST_CONTAINER_NO_SPINLOCKS 27 28 #include <boost/container/detail/config_begin.hpp> 29 #include <boost/container/detail/workaround.hpp> 30 31 // Extremely Light-Weight wrapper classes for OS thread synchronization 32 33 #define BOOST_MUTEX_HELPER_NONE 0 34 #define BOOST_MUTEX_HELPER_WIN32 1 35 #define BOOST_MUTEX_HELPER_PTHREAD 2 36 #define BOOST_MUTEX_HELPER_SPINLOCKS 3 37 38 #if !defined(BOOST_HAS_THREADS) && !defined(BOOST_NO_MT) 39 # define BOOST_NO_MT 40 #endif 41 42 #if defined(BOOST_NO_MT) || defined(BOOST_CONTAINER_NO_MT) 43 // No multithreading -> make locks into no-ops 44 #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_NONE 45 #else 46 //Taken from dlmalloc 47 #if !defined(BOOST_CONTAINER_NO_SPINLOCKS) && \ 48 ((defined(__GNUC__) && \ 49 ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ 50 defined(__i386__) || defined(__x86_64__))) || \ 51 (defined(_MSC_VER) && _MSC_VER>=1310)) 52 #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_SPINLOCKS 53 #endif 54 55 #if defined(BOOST_WINDOWS) 56 #include <windows.h> 57 #ifndef BOOST_MUTEX_HELPER 58 #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_WIN32 59 #endif 60 #elif defined(BOOST_HAS_UNISTD_H) 61 #include <unistd.h> 62 #if !defined(BOOST_MUTEX_HELPER) && (defined(_POSIX_THREADS) || defined(BOOST_HAS_PTHREADS)) 63 #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_PTHREAD 64 #endif 65 #endif 66 #endif 67 68 #ifndef BOOST_MUTEX_HELPER 69 #error Unable to determine platform mutex type; #define BOOST_NO_MT to assume single-threaded 70 #endif 71 72 #if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE 73 //... 74 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS 75 #if defined(_MSC_VER) 76 #ifndef _M_AMD64 77 /* These are already defined on AMD64 builds */ 78 #ifdef __cplusplus 79 extern "C" { 80 #endif /* __cplusplus */ 81 long __cdecl _InterlockedCompareExchange(long volatile *Dest, long Exchange, long Comp); 82 long __cdecl _InterlockedExchange(long volatile *Target, long Value); 83 #ifdef __cplusplus 84 } 85 #endif /* __cplusplus */ 86 #endif /* _M_AMD64 */ 87 #pragma intrinsic (_InterlockedCompareExchange) 88 #pragma intrinsic (_InterlockedExchange) 89 #define interlockedcompareexchange _InterlockedCompareExchange 90 #define interlockedexchange _InterlockedExchange 91 #elif defined(WIN32) && defined(__GNUC__) 92 #define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) 93 #define interlockedexchange __sync_lock_test_and_set 94 #endif /* Win32 */ 95 96 /* First, define CAS_LOCK and CLEAR_LOCK on ints */ 97 /* Note CAS_LOCK defined to return 0 on success */ 98 99 #if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) 100 #define BOOST_CONTAINER_CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) 101 #define BOOST_CONTAINER_CLEAR_LOCK(sl) __sync_lock_release(sl) 102 103 #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) 104 /* Custom spin locks for older gcc on x86 */ boost_container_x86_cas_lock(int * sl)105 static inline int boost_container_x86_cas_lock(int *sl) { 106 int ret; 107 int val = 1; 108 int cmp = 0; 109 __asm__ __volatile__ ("lock; cmpxchgl %1, %2" 110 : "=a" (ret) 111 : "r" (val), "m" (*(sl)), "0"(cmp) 112 : "memory", "cc"); 113 return ret; 114 } 115 boost_container_x86_clear_lock(int * sl)116 static inline void boost_container_x86_clear_lock(int* sl) { 117 assert(*sl != 0); 118 int prev = 0; 119 int ret; 120 __asm__ __volatile__ ("lock; xchgl %0, %1" 121 : "=r" (ret) 122 : "m" (*(sl)), "0"(prev) 123 : "memory"); 124 } 125 126 #define BOOST_CONTAINER_CAS_LOCK(sl) boost_container_x86_cas_lock(sl) 127 #define BOOST_CONTAINER_CLEAR_LOCK(sl) boost_container_x86_clear_lock(sl) 128 129 #else /* Win32 MSC */ 130 #define BOOST_CONTAINER_CAS_LOCK(sl) interlockedexchange((long volatile*)sl, (long)1) 131 #define BOOST_CONTAINER_CLEAR_LOCK(sl) interlockedexchange((long volatile*)sl, (long)0) 132 #endif 133 134 /* How to yield for a spin lock */ 135 #define SPINS_PER_YIELD 63 136 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 137 #define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ 138 #define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) 139 #elif defined (__SVR4) && defined (__sun) /* solaris */ 140 #include <thread.h> 141 #define SPIN_LOCK_YIELD thr_yield(); 142 #elif !defined(LACKS_SCHED_H) 143 #include <sched.h> 144 #define SPIN_LOCK_YIELD sched_yield(); 145 #else 146 #define SPIN_LOCK_YIELD 147 #endif /* ... yield ... */ 148 149 #define BOOST_CONTAINER_SPINS_PER_YIELD 63 boost_interprocess_spin_acquire_lock(int * sl)150 inline int boost_interprocess_spin_acquire_lock(int *sl) { 151 int spins = 0; 152 while (*(volatile int *)sl != 0 || 153 BOOST_CONTAINER_CAS_LOCK(sl)) { 154 if ((++spins & BOOST_CONTAINER_SPINS_PER_YIELD) == 0) { 155 SPIN_LOCK_YIELD; 156 } 157 } 158 return 0; 159 } 160 #define BOOST_CONTAINER_MLOCK_T int 161 #define BOOST_CONTAINER_TRY_LOCK(sl) !BOOST_CONTAINER_CAS_LOCK(sl) 162 #define BOOST_CONTAINER_RELEASE_LOCK(sl) BOOST_CONTAINER_CLEAR_LOCK(sl) 163 #define BOOST_CONTAINER_ACQUIRE_LOCK(sl) (BOOST_CONTAINER_CAS_LOCK(sl)? boost_interprocess_spin_acquire_lock(sl) : 0) 164 #define BOOST_MOVE_INITIAL_LOCK(sl) (*sl = 0) 165 #define BOOST_CONTAINER_DESTROY_LOCK(sl) (0) 166 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 167 // 168 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD 169 #include <pthread.h> 170 #endif 171 172 namespace boost { 173 namespace container { 174 namespace dtl { 175 176 #if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE 177 class null_mutex 178 { 179 private: 180 null_mutex(const null_mutex &); 181 void operator=(const null_mutex &); 182 183 public: null_mutex()184 null_mutex() { } 185 lock()186 static void lock() { } unlock()187 static void unlock() { } 188 }; 189 190 typedef null_mutex default_mutex; 191 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS 192 193 class spin_mutex 194 { 195 private: 196 BOOST_CONTAINER_MLOCK_T sl; 197 spin_mutex(const spin_mutex &); 198 void operator=(const spin_mutex &); 199 200 public: 201 spin_mutex() { BOOST_MOVE_INITIAL_LOCK(&sl); } 202 203 void lock() { BOOST_CONTAINER_ACQUIRE_LOCK(&sl); } 204 void unlock() { BOOST_CONTAINER_RELEASE_LOCK(&sl); } 205 }; 206 typedef spin_mutex default_mutex; 207 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 208 class mutex 209 { 210 private: 211 CRITICAL_SECTION mtx; 212 213 mutex(const mutex &); 214 void operator=(const mutex &); 215 216 public: 217 mutex() 218 { InitializeCriticalSection(&mtx); } 219 220 ~mutex() 221 { DeleteCriticalSection(&mtx); } 222 223 void lock() 224 { EnterCriticalSection(&mtx); } 225 226 void unlock() 227 { LeaveCriticalSection(&mtx); } 228 }; 229 230 typedef mutex default_mutex; 231 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD 232 class mutex 233 { 234 private: 235 pthread_mutex_t mtx; 236 237 mutex(const mutex &); 238 void operator=(const mutex &); 239 240 public: 241 mutex() 242 { pthread_mutex_init(&mtx, 0); } 243 244 ~mutex() 245 { pthread_mutex_destroy(&mtx); } 246 247 void lock() 248 { pthread_mutex_lock(&mtx); } 249 250 void unlock() 251 { pthread_mutex_unlock(&mtx); } 252 }; 253 254 typedef mutex default_mutex; 255 #endif 256 257 template<class Mutex> 258 class scoped_lock 259 { 260 public: scoped_lock(Mutex & m)261 scoped_lock(Mutex &m) 262 : m_(m) 263 { m_.lock(); } ~scoped_lock()264 ~scoped_lock() 265 { m_.unlock(); } 266 267 private: 268 Mutex &m_; 269 }; 270 271 } // namespace dtl 272 } // namespace container 273 } // namespace boost 274 275 #undef BOOST_MUTEX_HELPER_WIN32 276 #undef BOOST_MUTEX_HELPER_PTHREAD 277 #undef BOOST_MUTEX_HELPER_NONE 278 #undef BOOST_MUTEX_HELPER 279 #undef BOOST_MUTEX_HELPER_SPINLOCKS 280 281 #include <boost/container/detail/config_end.hpp> 282 283 #endif 284