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