1 #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
2 #define BOOST_THREAD_PTHREAD_MUTEX_HPP
3 // (C) Copyright 2007-8 Anthony Williams
4 // (C) Copyright 2011,2012,2015 Vicente J. Botet Escriba
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 #include <boost/thread/detail/config.hpp>
10 #include <boost/assert.hpp>
11 #include <pthread.h>
12 #include <boost/throw_exception.hpp>
13 #include <boost/core/ignore_unused.hpp>
14 #include <boost/thread/exceptions.hpp>
15 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
16 #include <boost/thread/lock_types.hpp>
17 #endif
18 #include <boost/thread/thread_time.hpp>
19 #include <boost/thread/xtime.hpp>
20 #include <boost/assert.hpp>
21 #include <errno.h>
22 #include <boost/thread/pthread/timespec.hpp>
23 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
24 #ifdef BOOST_THREAD_USES_CHRONO
25 #include <boost/chrono/system_clocks.hpp>
26 #include <boost/chrono/ceil.hpp>
27 #endif
28 #include <boost/thread/detail/delete.hpp>
29 
30 #if (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \
31  || (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
32 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
33 #define BOOST_PTHREAD_HAS_TIMEDLOCK
34 #endif
35 #endif
36 
37 
38 #include <boost/config/abi_prefix.hpp>
39 
40 #ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
41 #define BOOST_THREAD_HAS_EINTR_BUG
42 #endif
43 
44 namespace boost
45 {
46   namespace posix {
47 #ifdef BOOST_THREAD_HAS_EINTR_BUG
pthread_mutex_destroy(pthread_mutex_t * m)48     BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
49     {
50       int ret;
51       do
52       {
53           ret = ::pthread_mutex_destroy(m);
54       } while (ret == EINTR);
55       return ret;
56     }
pthread_mutex_lock(pthread_mutex_t * m)57     BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
58     {
59       int ret;
60       do
61       {
62           ret = ::pthread_mutex_lock(m);
63       } while (ret == EINTR);
64       return ret;
65     }
pthread_mutex_unlock(pthread_mutex_t * m)66     BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
67     {
68       int ret;
69       do
70       {
71           ret = ::pthread_mutex_unlock(m);
72       } while (ret == EINTR);
73       return ret;
74     }
75 #else
76     BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
77     {
78       return ::pthread_mutex_destroy(m);
79     }
80     BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
81     {
82       return ::pthread_mutex_lock(m);
83     }
84     BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
85     {
86       return ::pthread_mutex_unlock(m);
87     }
88 
89 #endif
90 
91   }
92     class mutex
93     {
94     private:
95         pthread_mutex_t m;
96     public:
97         BOOST_THREAD_NO_COPYABLE(mutex)
98 
mutex()99         mutex()
100         {
101             int const res=pthread_mutex_init(&m,NULL);
102             if(res)
103             {
104                 boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
105             }
106         }
~mutex()107         ~mutex()
108         {
109           int const res = posix::pthread_mutex_destroy(&m);
110           boost::ignore_unused(res);
111           BOOST_ASSERT(!res);
112         }
113 
lock()114         void lock()
115         {
116             int res = posix::pthread_mutex_lock(&m);
117             if (res)
118             {
119                 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
120             }
121         }
122 
unlock()123         void unlock()
124         {
125             int res = posix::pthread_mutex_unlock(&m);
126             (void)res;
127             BOOST_ASSERT(res == 0);
128 //            if (res)
129 //            {
130 //                boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
131 //            }
132         }
133 
try_lock()134         bool try_lock()
135         {
136             int res;
137             do
138             {
139                 res = pthread_mutex_trylock(&m);
140             } while (res == EINTR);
141             if (res==EBUSY)
142             {
143                 return false;
144             }
145 
146             return !res;
147         }
148 
149 #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
150         typedef pthread_mutex_t* native_handle_type;
native_handle()151         native_handle_type native_handle()
152         {
153             return &m;
154         }
155 
156 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
157         typedef unique_lock<mutex> scoped_lock;
158         typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
159 #endif
160     };
161 
162     typedef mutex try_mutex;
163 
164     class timed_mutex
165     {
166     private:
167         pthread_mutex_t m;
168 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
169         pthread_cond_t cond;
170         bool is_locked;
171 #endif
172     public:
173         BOOST_THREAD_NO_COPYABLE(timed_mutex)
timed_mutex()174         timed_mutex()
175         {
176             int const res=pthread_mutex_init(&m,NULL);
177             if(res)
178             {
179                 boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
180             }
181 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
182             int const res2=pthread_cond_init(&cond,NULL);
183             if(res2)
184             {
185                 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
186                 //BOOST_VERIFY(!pthread_mutex_destroy(&m));
187                 boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
188             }
189             is_locked=false;
190 #endif
191         }
~timed_mutex()192         ~timed_mutex()
193         {
194             BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
195 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
196             BOOST_VERIFY(!pthread_cond_destroy(&cond));
197 #endif
198         }
199 
200 #if defined BOOST_THREAD_USES_DATETIME
201         template<typename TimeDuration>
timed_lock(TimeDuration const & relative_time)202         bool timed_lock(TimeDuration const & relative_time)
203         {
204             return timed_lock(get_system_time()+relative_time);
205         }
timed_lock(boost::xtime const & absolute_time)206         bool timed_lock(boost::xtime const & absolute_time)
207         {
208             return timed_lock(system_time(absolute_time));
209         }
210 #endif
211 #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
lock()212         void lock()
213         {
214             int res = posix::pthread_mutex_lock(&m);
215             if (res)
216             {
217                 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
218             }
219         }
220 
unlock()221         void unlock()
222         {
223             int res = posix::pthread_mutex_unlock(&m);
224             (void)res;
225             BOOST_ASSERT(res == 0);
226 //            if (res)
227 //            {
228 //                boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
229 //            }
230         }
231 
try_lock()232         bool try_lock()
233         {
234           int res;
235           do
236           {
237               res = pthread_mutex_trylock(&m);
238           } while (res == EINTR);
239           if (res==EBUSY)
240           {
241               return false;
242           }
243 
244           return !res;
245         }
246 
247 
248     private:
do_try_lock_until(struct timespec const & timeout)249         bool do_try_lock_until(struct timespec const &timeout)
250         {
251           int const res=pthread_mutex_timedlock(&m,&timeout);
252           BOOST_ASSERT(!res || res==ETIMEDOUT);
253           return !res;
254         }
255     public:
256 
257 #else
258         void lock()
259         {
260             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
261             while(is_locked)
262             {
263                 BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
264             }
265             is_locked=true;
266         }
267 
268         void unlock()
269         {
270             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
271             is_locked=false;
272             BOOST_VERIFY(!pthread_cond_signal(&cond));
273         }
274 
275         bool try_lock()
276         {
277             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
278             if(is_locked)
279             {
280                 return false;
281             }
282             is_locked=true;
283             return true;
284         }
285 
286     private:
287         bool do_try_lock_until(struct timespec const &timeout)
288         {
289             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
290             while(is_locked)
291             {
292                 int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
293                 if(cond_res==ETIMEDOUT)
294                 {
295                     return false;
296                 }
297                 BOOST_ASSERT(!cond_res);
298             }
299             is_locked=true;
300             return true;
301         }
302     public:
303 #endif
304 
305 #if defined BOOST_THREAD_USES_DATETIME
timed_lock(system_time const & abs_time)306         bool timed_lock(system_time const & abs_time)
307         {
308             struct timespec const ts=boost::detail::to_timespec(abs_time);
309             return do_try_lock_until(ts);
310         }
311 #endif
312 #ifdef BOOST_THREAD_USES_CHRONO
313         template <class Rep, class Period>
try_lock_for(const chrono::duration<Rep,Period> & rel_time)314         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
315         {
316           return try_lock_until(chrono::steady_clock::now() + rel_time);
317         }
318         template <class Clock, class Duration>
try_lock_until(const chrono::time_point<Clock,Duration> & t)319         bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
320         {
321           using namespace chrono;
322           system_clock::time_point     s_now = system_clock::now();
323           typename Clock::time_point  c_now = Clock::now();
324           return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
325         }
326         template <class Duration>
try_lock_until(const chrono::time_point<chrono::system_clock,Duration> & t)327         bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
328         {
329           using namespace chrono;
330           typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
331           return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
332         }
try_lock_until(const chrono::time_point<chrono::system_clock,chrono::nanoseconds> & tp)333         bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
334         {
335           //using namespace chrono;
336           chrono::nanoseconds d = tp.time_since_epoch();
337           timespec ts = boost::detail::to_timespec(d);
338           return do_try_lock_until(ts);
339         }
340 #endif
341 
342 #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
343         typedef pthread_mutex_t* native_handle_type;
native_handle()344         native_handle_type native_handle()
345         {
346             return &m;
347         }
348 
349 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
350         typedef unique_lock<timed_mutex> scoped_timed_lock;
351         typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
352         typedef scoped_timed_lock scoped_lock;
353 #endif
354     };
355 
356 }
357 
358 #include <boost/config/abi_suffix.hpp>
359 
360 
361 #endif
362