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 <boost/winapi/critical_section.hpp> 57 #include <boost/winapi/thread.hpp> 58 #ifndef BOOST_MUTEX_HELPER 59 #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_WIN32 60 #endif 61 #elif defined(BOOST_HAS_UNISTD_H) 62 #include <unistd.h> 63 #if !defined(BOOST_MUTEX_HELPER) && (defined(_POSIX_THREADS) || defined(BOOST_HAS_PTHREADS)) 64 #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_PTHREAD 65 #endif 66 #endif 67 #endif 68 69 #ifndef BOOST_MUTEX_HELPER 70 #error Unable to determine platform mutex type; #define BOOST_NO_MT to assume single-threaded 71 #endif 72 73 #if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE 74 //... 75 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS 76 #if defined(_MSC_VER) 77 #include <boost/detail/interlocked.hpp> 78 #define interlockedcompareexchange _InterlockedCompareExchange 79 #define interlockedexchange _InterlockedExchange 80 #elif defined(WIN32) && defined(__GNUC__) 81 #define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) 82 #define interlockedexchange __sync_lock_test_and_set 83 #endif /* Win32 */ 84 85 /* First, define CAS_LOCK and CLEAR_LOCK on ints */ 86 /* Note CAS_LOCK defined to return 0 on success */ 87 88 #if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) 89 #define BOOST_CONTAINER_CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) 90 #define BOOST_CONTAINER_CLEAR_LOCK(sl) __sync_lock_release(sl) 91 92 #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) 93 /* Custom spin locks for older gcc on x86 */ boost_container_x86_cas_lock(int * sl)94 static inline int boost_container_x86_cas_lock(int *sl) { 95 int ret; 96 int val = 1; 97 int cmp = 0; 98 __asm__ __volatile__ ("lock; cmpxchgl %1, %2" 99 : "=a" (ret) 100 : "r" (val), "m" (*(sl)), "0"(cmp) 101 : "memory", "cc"); 102 return ret; 103 } 104 boost_container_x86_clear_lock(int * sl)105 static inline void boost_container_x86_clear_lock(int* sl) { 106 assert(*sl != 0); 107 int prev = 0; 108 int ret; 109 __asm__ __volatile__ ("lock; xchgl %0, %1" 110 : "=r" (ret) 111 : "m" (*(sl)), "0"(prev) 112 : "memory"); 113 } 114 115 #define BOOST_CONTAINER_CAS_LOCK(sl) boost_container_x86_cas_lock(sl) 116 #define BOOST_CONTAINER_CLEAR_LOCK(sl) boost_container_x86_clear_lock(sl) 117 118 #else /* Win32 MSC */ 119 #define BOOST_CONTAINER_CAS_LOCK(sl) interlockedexchange((long volatile*)sl, (long)1) 120 #define BOOST_CONTAINER_CLEAR_LOCK(sl) interlockedexchange((long volatile*)sl, (long)0) 121 #endif 122 123 /* How to yield for a spin lock */ 124 #define SPINS_PER_YIELD 63 125 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 126 #define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ 127 #define SPIN_LOCK_YIELD boost::winapi::SleepEx(SLEEP_EX_DURATION, 0) 128 #elif defined (__SVR4) && defined (__sun) /* solaris */ 129 #include <thread.h> 130 #define SPIN_LOCK_YIELD thr_yield(); 131 #elif !defined(LACKS_SCHED_H) 132 #include <sched.h> 133 #define SPIN_LOCK_YIELD sched_yield(); 134 #else 135 #define SPIN_LOCK_YIELD 136 #endif /* ... yield ... */ 137 138 #define BOOST_CONTAINER_SPINS_PER_YIELD 63 boost_interprocess_spin_acquire_lock(int * sl)139 inline int boost_interprocess_spin_acquire_lock(int *sl) { 140 int spins = 0; 141 while (*(volatile int *)sl != 0 || 142 BOOST_CONTAINER_CAS_LOCK(sl)) { 143 if ((++spins & BOOST_CONTAINER_SPINS_PER_YIELD) == 0) { 144 SPIN_LOCK_YIELD; 145 } 146 } 147 return 0; 148 } 149 #define BOOST_CONTAINER_MLOCK_T int 150 #define BOOST_CONTAINER_TRY_LOCK(sl) !BOOST_CONTAINER_CAS_LOCK(sl) 151 #define BOOST_CONTAINER_RELEASE_LOCK(sl) BOOST_CONTAINER_CLEAR_LOCK(sl) 152 #define BOOST_CONTAINER_ACQUIRE_LOCK(sl) (BOOST_CONTAINER_CAS_LOCK(sl)? boost_interprocess_spin_acquire_lock(sl) : 0) 153 #define BOOST_MOVE_INITIAL_LOCK(sl) (*sl = 0) 154 #define BOOST_CONTAINER_DESTROY_LOCK(sl) (0) 155 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 156 // 157 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD 158 #include <pthread.h> 159 #endif 160 161 namespace boost { 162 namespace container { 163 namespace dtl { 164 165 #if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE 166 class null_mutex 167 { 168 private: 169 null_mutex(const null_mutex &); 170 void operator=(const null_mutex &); 171 172 public: null_mutex()173 null_mutex() { } 174 lock()175 static void lock() { } unlock()176 static void unlock() { } 177 }; 178 179 typedef null_mutex default_mutex; 180 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS 181 182 class spin_mutex 183 { 184 private: 185 BOOST_CONTAINER_MLOCK_T sl; 186 spin_mutex(const spin_mutex &); 187 void operator=(const spin_mutex &); 188 189 public: 190 spin_mutex() { BOOST_MOVE_INITIAL_LOCK(&sl); } 191 192 void lock() { BOOST_CONTAINER_ACQUIRE_LOCK(&sl); } 193 void unlock() { BOOST_CONTAINER_RELEASE_LOCK(&sl); } 194 }; 195 typedef spin_mutex default_mutex; 196 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 197 class mutex 198 { 199 private: 200 CRITICAL_SECTION mtx; 201 202 mutex(const mutex &); 203 void operator=(const mutex &); 204 205 public: 206 mutex() 207 { InitializeCriticalSection(&mtx); } 208 209 ~mutex() 210 { DeleteCriticalSection(&mtx); } 211 212 void lock() 213 { EnterCriticalSection(&mtx); } 214 215 void unlock() 216 { LeaveCriticalSection(&mtx); } 217 }; 218 219 typedef mutex default_mutex; 220 #elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD 221 class mutex 222 { 223 private: 224 pthread_mutex_t mtx; 225 226 mutex(const mutex &); 227 void operator=(const mutex &); 228 229 public: 230 mutex() 231 { pthread_mutex_init(&mtx, 0); } 232 233 ~mutex() 234 { pthread_mutex_destroy(&mtx); } 235 236 void lock() 237 { pthread_mutex_lock(&mtx); } 238 239 void unlock() 240 { pthread_mutex_unlock(&mtx); } 241 }; 242 243 typedef mutex default_mutex; 244 #endif 245 246 template<class Mutex> 247 class scoped_lock 248 { 249 public: scoped_lock(Mutex & m)250 scoped_lock(Mutex &m) 251 : m_(m) 252 { m_.lock(); } ~scoped_lock()253 ~scoped_lock() 254 { m_.unlock(); } 255 256 private: 257 Mutex &m_; 258 }; 259 260 } // namespace dtl 261 } // namespace container 262 } // namespace boost 263 264 #undef BOOST_MUTEX_HELPER_WIN32 265 #undef BOOST_MUTEX_HELPER_PTHREAD 266 #undef BOOST_MUTEX_HELPER_NONE 267 #undef BOOST_MUTEX_HELPER 268 #undef BOOST_MUTEX_HELPER_SPINLOCKS 269 270 #include <boost/container/detail/config_end.hpp> 271 272 #endif 273