• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 namespace boost
37 {
38 
39     class BOOST_THREAD_CAPABILITY("mutex") mutex
40     {
41     private:
42         pthread_mutex_t m;
43     public:
44         BOOST_THREAD_NO_COPYABLE(mutex)
45 
mutex()46         mutex()
47         {
48             int const res=posix::pthread_mutex_init(&m);
49             if(res)
50             {
51                 boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
52             }
53         }
~mutex()54         ~mutex()
55         {
56           BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
57         }
58 
lock()59         void lock() BOOST_THREAD_ACQUIRE()
60         {
61             int res = posix::pthread_mutex_lock(&m);
62             if (res)
63             {
64                 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
65             }
66         }
67 
unlock()68         void unlock() BOOST_THREAD_RELEASE()
69         {
70             BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
71         }
72 
try_lock()73         bool try_lock() BOOST_THREAD_TRY_ACQUIRE(true)
74         {
75             int res = posix::pthread_mutex_trylock(&m);
76             if (res==EBUSY)
77             {
78                 return false;
79             }
80 
81             return !res;
82         }
83 
84 #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
85         typedef pthread_mutex_t* native_handle_type;
native_handle()86         native_handle_type native_handle()
87         {
88             return &m;
89         }
90 
91 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
92         typedef unique_lock<mutex> scoped_lock;
93         typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
94 #endif
95     };
96 
97     typedef mutex try_mutex;
98 
99     class timed_mutex
100     {
101     private:
102         pthread_mutex_t m;
103 #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
104         pthread_cond_t cond;
105         bool is_locked;
106 #endif
107     public:
108         BOOST_THREAD_NO_COPYABLE(timed_mutex)
timed_mutex()109         timed_mutex()
110         {
111             int const res=posix::pthread_mutex_init(&m);
112             if(res)
113             {
114                 boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
115             }
116 #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
117             int const res2=posix::pthread_cond_init(&cond);
118             if(res2)
119             {
120                 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
121                 boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
122             }
123             is_locked=false;
124 #endif
125         }
~timed_mutex()126         ~timed_mutex()
127         {
128             BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
129 #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
130             BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
131 #endif
132         }
133 
134 #if defined BOOST_THREAD_USES_DATETIME
135         template<typename TimeDuration>
timed_lock(TimeDuration const & relative_time)136         bool timed_lock(TimeDuration const & relative_time)
137         {
138             if (relative_time.is_pos_infinity())
139             {
140                 lock();
141                 return true;
142             }
143             if (relative_time.is_special())
144             {
145                 return true;
146             }
147             detail::platform_duration d(relative_time);
148 #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
149             const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
150             d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
151             while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
152             {
153               d = ts - detail::mono_platform_clock::now();
154               if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
155               d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
156             }
157             return true;
158 #else
159             return do_try_lock_until(detail::internal_platform_clock::now() + d);
160 #endif
161         }
timed_lock(boost::xtime const & absolute_time)162         bool timed_lock(boost::xtime const & absolute_time)
163         {
164             return timed_lock(system_time(absolute_time));
165         }
166 #endif
167 #ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
lock()168         void lock()
169         {
170             int res = posix::pthread_mutex_lock(&m);
171             if (res)
172             {
173                 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
174             }
175         }
176 
unlock()177         void unlock()
178         {
179             BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
180         }
181 
try_lock()182         bool try_lock()
183         {
184           int res = posix::pthread_mutex_trylock(&m);
185           if (res==EBUSY)
186           {
187               return false;
188           }
189 
190           return !res;
191         }
192 
193 
194     private:
do_try_lock_until(detail::internal_platform_timepoint const & timeout)195         bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
196         {
197           int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
198           BOOST_ASSERT(!res || res==ETIMEDOUT);
199           return !res;
200         }
201     public:
202 
203 #else
204         void lock()
205         {
206             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
207             while(is_locked)
208             {
209                 BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m));
210             }
211             is_locked=true;
212         }
213 
214         void unlock()
215         {
216             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
217             is_locked=false;
218             BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
219         }
220 
221         bool try_lock()
222         {
223             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
224             if(is_locked)
225             {
226                 return false;
227             }
228             is_locked=true;
229             return true;
230         }
231 
232     private:
233         bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
234         {
235             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
236             while(is_locked)
237             {
238                 int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs());
239                 if(cond_res==ETIMEDOUT)
240                 {
241                     break;
242                 }
243                 BOOST_ASSERT(!cond_res);
244             }
245             if(is_locked)
246             {
247                 return false;
248             }
249             is_locked=true;
250             return true;
251         }
252     public:
253 #endif
254 
255 #if defined BOOST_THREAD_USES_DATETIME
timed_lock(system_time const & abs_time)256         bool timed_lock(system_time const & abs_time)
257         {
258             const detail::real_platform_timepoint ts(abs_time);
259 #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
260             detail::platform_duration d(ts - detail::real_platform_clock::now());
261             d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
262             while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
263             {
264               d = ts - detail::real_platform_clock::now();
265               if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
266               d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
267             }
268             return true;
269 #else
270             return do_try_lock_until(ts);
271 #endif
272         }
273 #endif
274 #ifdef BOOST_THREAD_USES_CHRONO
275         template <class Rep, class Period>
try_lock_for(const chrono::duration<Rep,Period> & rel_time)276         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
277         {
278           return try_lock_until(chrono::steady_clock::now() + rel_time);
279         }
280         template <class Clock, class Duration>
try_lock_until(const chrono::time_point<Clock,Duration> & t)281         bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
282         {
283           typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
284           common_duration d(t - Clock::now());
285           d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
286           while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
287           {
288               d = t - Clock::now();
289               if ( d <= common_duration::zero() ) return false; // timeout occurred
290               d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
291           }
292           return true;
293         }
294         template <class Duration>
try_lock_until(const chrono::time_point<detail::internal_chrono_clock,Duration> & t)295         bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
296         {
297           detail::internal_platform_timepoint ts(t);
298           return do_try_lock_until(ts);
299         }
300 #endif
301 
302 #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
303         typedef pthread_mutex_t* native_handle_type;
native_handle()304         native_handle_type native_handle()
305         {
306             return &m;
307         }
308 
309 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
310         typedef unique_lock<timed_mutex> scoped_timed_lock;
311         typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
312         typedef scoped_timed_lock scoped_lock;
313 #endif
314     };
315 }
316 
317 #include <boost/config/abi_suffix.hpp>
318 
319 
320 #endif
321