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