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   	#if defined BOOST_THREAD_USES_DATETIME
20   	#include <boost/thread/xtime.hpp>
21   	#endif
22   	#include <boost/assert.hpp>
23   	#include <errno.h>
24   	#include <boost/thread/detail/platform_time.hpp>
25   	#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
26   	#include <boost/thread/pthread/pthread_helpers.hpp>
27   	#ifdef BOOST_THREAD_USES_CHRONO
28   	#include <boost/chrono/system_clocks.hpp>
29   	#include <boost/chrono/ceil.hpp>
30   	#endif
31   	#include <boost/thread/detail/delete.hpp>
32   	
33   	
34   	#include <boost/config/abi_prefix.hpp>
35   	
36   	#ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
37   	#define BOOST_THREAD_HAS_EINTR_BUG
38   	#endif
39   	
40   	namespace boost
41   	{
42   	  namespace posix {
43   	#ifdef BOOST_THREAD_HAS_EINTR_BUG
44   	    BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
45   	    {
46   	      int ret;
47   	      do
48   	      {
49   	          ret = ::pthread_mutex_destroy(m);
50   	      } while (ret == EINTR);
51   	      return ret;
52   	    }
53   	    BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
54   	    {
55   	      int ret;
56   	      do
57   	      {
58   	          ret = ::pthread_mutex_lock(m);
59   	      } while (ret == EINTR);
60   	      return ret;
61   	    }
62   	    BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
63   	    {
64   	      int ret;
65   	      do
(3) Event loop_begin: Jumped back to beginning of loop.
66   	      {
(1) Event unlock: "pthread_mutex_unlock" unlocks "m".
(4) Event double_unlock: "pthread_mutex_unlock" unlocks "m" while it is unlocked.
67   	          ret = ::pthread_mutex_unlock(m);
(2) Event cond_true: Condition "ret == 4", taking true branch.
68   	      } while (ret == EINTR);
69   	      return ret;
70   	    }
71   	#else
72   	    BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
73   	    {
74   	      return ::pthread_mutex_destroy(m);
75   	    }
76   	    BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
77   	    {
78   	      return ::pthread_mutex_lock(m);
79   	    }
80   	    BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
81   	    {
82   	      return ::pthread_mutex_unlock(m);
83   	    }
84   	
85   	#endif
86   	
87   	  }
88   	    class mutex
89   	    {
90   	    private:
91   	        pthread_mutex_t m;
92   	    public:
93   	        BOOST_THREAD_NO_COPYABLE(mutex)
94   	
95   	        mutex()
96   	        {
97   	            int const res=pthread_mutex_init(&m,NULL);
98   	            if(res)
99   	            {
100  	                boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
101  	            }
102  	        }
103  	        ~mutex()
104  	        {
105  	          int const res = posix::pthread_mutex_destroy(&m);
106  	          boost::ignore_unused(res);
107  	          BOOST_ASSERT(!res);
108  	        }
109  	
110  	        void lock()
111  	        {
112  	            int res = posix::pthread_mutex_lock(&m);
113  	            if (res)
114  	            {
115  	                boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
116  	            }
117  	        }
118  	
119  	        void unlock()
120  	        {
121  	            int res = posix::pthread_mutex_unlock(&m);
122  	            (void)res;
123  	            BOOST_ASSERT(res == 0);
124  	//            if (res)
125  	//            {
126  	//                boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
127  	//            }
128  	        }
129  	
130  	        bool try_lock()
131  	        {
132  	            int res;
133  	            do
134  	            {
135  	                res = pthread_mutex_trylock(&m);
136  	            } while (res == EINTR);
137  	            if (res==EBUSY)
138  	            {
139  	                return false;
140  	            }
141  	
142  	            return !res;
143  	        }
144  	
145  	#define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
146  	        typedef pthread_mutex_t* native_handle_type;
147  	        native_handle_type native_handle()
148  	        {
149  	            return &m;
150  	        }
151  	
152  	#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
153  	        typedef unique_lock<mutex> scoped_lock;
154  	        typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
155  	#endif
156  	    };
157  	
158  	    typedef mutex try_mutex;
159  	
160  	    class timed_mutex
161  	    {
162  	    private:
163  	        pthread_mutex_t m;
164  	#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
165  	        pthread_cond_t cond;
166  	        bool is_locked;
167  	#endif
168  	    public:
169  	        BOOST_THREAD_NO_COPYABLE(timed_mutex)
170  	        timed_mutex()
171  	        {
172  	            int const res=pthread_mutex_init(&m,NULL);
173  	            if(res)
174  	            {
175  	                boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
176  	            }
177  	#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
178  	            int const res2=pthread::cond_init(cond);
179  	            if(res2)
180  	            {
181  	                BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
182  	                boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread::cond_init"));
183  	            }
184  	            is_locked=false;
185  	#endif
186  	        }
187  	        ~timed_mutex()
188  	        {
189  	            BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
190  	#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
191  	            BOOST_VERIFY(!pthread_cond_destroy(&cond));
192  	#endif
193  	        }
194  	
195  	#if defined BOOST_THREAD_USES_DATETIME
196  	        template<typename TimeDuration>
197  	        bool timed_lock(TimeDuration const & relative_time)
198  	        {
199  	            if (relative_time.is_pos_infinity())
200  	            {
201  	                lock();
202  	                return true;
203  	            }
204  	            if (relative_time.is_special())
205  	            {
206  	                return true;
207  	            }
208  	            detail::platform_duration d(relative_time);
209  	#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
210  	            const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
211  	            d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
212  	            while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
213  	            {
214  	              d = ts - detail::mono_platform_clock::now();
215  	              if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
216  	              d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
217  	            }
218  	            return true;
219  	#else
220  	            return do_try_lock_until(detail::internal_platform_clock::now() + d);
221  	#endif
222  	        }
223  	        bool timed_lock(boost::xtime const & absolute_time)
224  	        {
225  	            return timed_lock(system_time(absolute_time));
226  	        }
227  	#endif
228  	#ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
229  	        void lock()
230  	        {
231  	            int res = posix::pthread_mutex_lock(&m);
232  	            if (res)
233  	            {
234  	                boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
235  	            }
236  	        }
237  	
238  	        void unlock()
239  	        {
240  	            int res = posix::pthread_mutex_unlock(&m);
241  	            (void)res;
242  	            BOOST_ASSERT(res == 0);
243  	//            if (res)
244  	//            {
245  	//                boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
246  	//            }
247  	        }
248  	
249  	        bool try_lock()
250  	        {
251  	          int res;
252  	          do
253  	          {
254  	              res = pthread_mutex_trylock(&m);
255  	          } while (res == EINTR);
256  	          if (res==EBUSY)
257  	          {
258  	              return false;
259  	          }
260  	
261  	          return !res;
262  	        }
263  	
264  	
265  	    private:
266  	        bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
267  	        {
268  	          int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
269  	          BOOST_ASSERT(!res || res==ETIMEDOUT);
270  	          return !res;
271  	        }
272  	    public:
273  	
274  	#else
275  	        void lock()
276  	        {
277  	            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
278  	            while(is_locked)
279  	            {
280  	                BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
281  	            }
282  	            is_locked=true;
283  	        }
284  	
285  	        void unlock()
286  	        {
287  	            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
288  	            is_locked=false;
289  	            BOOST_VERIFY(!pthread_cond_signal(&cond));
290  	        }
291  	
292  	        bool try_lock()
293  	        {
294  	            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
295  	            if(is_locked)
296  	            {
297  	                return false;
298  	            }
299  	            is_locked=true;
300  	            return true;
301  	        }
302  	
303  	    private:
304  	        bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
305  	        {
306  	            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
307  	            while(is_locked)
308  	            {
309  	                int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs());
310  	                if(cond_res==ETIMEDOUT)
311  	                {
312  	                    break;
313  	                }
314  	                BOOST_ASSERT(!cond_res);
315  	            }
316  	            if(is_locked)
317  	            {
318  	                return false;
319  	            }
320  	            is_locked=true;
321  	            return true;
322  	        }
323  	    public:
324  	#endif
325  	
326  	#if defined BOOST_THREAD_USES_DATETIME
327  	        bool timed_lock(system_time const & abs_time)
328  	        {
329  	            const detail::real_platform_timepoint ts(abs_time);
330  	#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
331  	            detail::platform_duration d(ts - detail::real_platform_clock::now());
332  	            d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
333  	            while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
334  	            {
335  	              d = ts - detail::real_platform_clock::now();
336  	              if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
337  	              d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
338  	            }
339  	            return true;
340  	#else
341  	            return do_try_lock_until(ts);
342  	#endif
343  	        }
344  	#endif
345  	#ifdef BOOST_THREAD_USES_CHRONO
346  	        template <class Rep, class Period>
347  	        bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
348  	        {
349  	          return try_lock_until(chrono::steady_clock::now() + rel_time);
350  	        }
351  	        template <class Clock, class Duration>
352  	        bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
353  	        {
354  	          typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
355  	          common_duration d(t - Clock::now());
356  	          d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
357  	          while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
358  	          {
359  	              d = t - Clock::now();
360  	              if ( d <= common_duration::zero() ) return false; // timeout occurred
361  	              d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
362  	          }
363  	          return true;
364  	        }
365  	        template <class Duration>
366  	        bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
367  	        {
368  	          detail::internal_platform_timepoint ts(t);
369  	          return do_try_lock_until(ts);
370  	        }
371  	#endif
372  	
373  	#define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
374  	        typedef pthread_mutex_t* native_handle_type;
375  	        native_handle_type native_handle()
376  	        {
377  	            return &m;
378  	        }
379  	
380  	#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
381  	        typedef unique_lock<timed_mutex> scoped_timed_lock;
382  	        typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
383  	        typedef scoped_timed_lock scoped_lock;
384  	#endif
385  	    };
386  	}
387  	
388  	#include <boost/config/abi_suffix.hpp>
389  	
390  	
391  	#endif
392