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