]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // | |
b32b8144 FG |
3 | // (C) Copyright Stephen Cleary 2000 |
4 | // (C) Copyright Ion Gaztanaga 2015-2017. | |
5 | // | |
6 | // Distributed under the Boost | |
7c673cae FG |
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 */ | |
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 | ||
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 | |
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 { | |
11fdf7f2 | 174 | namespace dtl { |
7c673cae FG |
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: | |
184 | null_mutex() { } | |
185 | ||
186 | static void lock() { } | |
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: | |
261 | scoped_lock(Mutex &m) | |
262 | : m_(m) | |
263 | { m_.lock(); } | |
264 | ~scoped_lock() | |
265 | { m_.unlock(); } | |
266 | ||
267 | private: | |
268 | Mutex &m_; | |
269 | }; | |
270 | ||
11fdf7f2 | 271 | } // namespace dtl |
7c673cae FG |
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 |