]>
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) | |
1e59de90 TL |
56 | #include <boost/winapi/critical_section.hpp> |
57 | #include <boost/winapi/thread.hpp> | |
7c673cae FG |
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) | |
1e59de90 | 77 | #include <boost/detail/interlocked.hpp> |
7c673cae FG |
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 */ | |
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 | ||
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 */ | |
1e59de90 | 127 | #define SPIN_LOCK_YIELD boost::winapi::SleepEx(SLEEP_EX_DURATION, 0) |
7c673cae FG |
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 | |
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 { | |
11fdf7f2 | 163 | namespace dtl { |
7c673cae FG |
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: | |
173 | null_mutex() { } | |
174 | ||
175 | static void lock() { } | |
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: | |
250 | scoped_lock(Mutex &m) | |
251 | : m_(m) | |
252 | { m_.lock(); } | |
253 | ~scoped_lock() | |
254 | { m_.unlock(); } | |
255 | ||
256 | private: | |
257 | Mutex &m_; | |
258 | }; | |
259 | ||
11fdf7f2 | 260 | } // namespace dtl |
7c673cae FG |
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 |