Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / thread / pthread / mutex.hpp
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 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 <pthread.h>
11 #include <boost/throw_exception.hpp>
12 #include <boost/core/ignore_unused.hpp>
13 #include <boost/thread/exceptions.hpp>
14 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
15 #include <boost/thread/lock_types.hpp>
16 #endif
17 #include <boost/thread/thread_time.hpp>
18 #include <boost/thread/xtime.hpp>
19 #include <boost/assert.hpp>
20 #include <errno.h>
21 #include <boost/thread/pthread/timespec.hpp>
22 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
23 #ifdef BOOST_THREAD_USES_CHRONO
24 #include <boost/chrono/system_clocks.hpp>
25 #include <boost/chrono/ceil.hpp>
26 #endif
27 #include <boost/thread/detail/delete.hpp>
28
29 #ifdef _POSIX_TIMEOUTS
30 #if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L
31 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
32 #define BOOST_PTHREAD_HAS_TIMEDLOCK
33 #endif
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
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     }
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     }
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
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         }
107         ~mutex()
108         {
109           int const res = posix::pthread_mutex_destroy(&m);
110           boost::ignore_unused(res);
111           BOOST_ASSERT(!res);
112         }
113
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
123         void unlock()
124         {
125             int res = posix::pthread_mutex_unlock(&m);
126             if (res)
127             {
128                 boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
129             }
130         }
131
132         bool try_lock()
133         {
134             int res;
135             do
136             {
137                 res = pthread_mutex_trylock(&m);
138             } while (res == EINTR);
139             if (res==EBUSY)
140             {
141                 return false;
142             }
143
144             return !res;
145         }
146
147 #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
148         typedef pthread_mutex_t* native_handle_type;
149         native_handle_type native_handle()
150         {
151             return &m;
152         }
153
154 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
155         typedef unique_lock<mutex> scoped_lock;
156         typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
157 #endif
158     };
159
160     typedef mutex try_mutex;
161
162     class timed_mutex
163     {
164     private:
165         pthread_mutex_t m;
166 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
167         pthread_cond_t cond;
168         bool is_locked;
169 #endif
170     public:
171         BOOST_THREAD_NO_COPYABLE(timed_mutex)
172         timed_mutex()
173         {
174             int const res=pthread_mutex_init(&m,NULL);
175             if(res)
176             {
177                 boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
178             }
179 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
180             int const res2=pthread_cond_init(&cond,NULL);
181             if(res2)
182             {
183                 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
184                 //BOOST_VERIFY(!pthread_mutex_destroy(&m));
185                 boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
186             }
187             is_locked=false;
188 #endif
189         }
190         ~timed_mutex()
191         {
192             BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
193 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
194             BOOST_VERIFY(!pthread_cond_destroy(&cond));
195 #endif
196         }
197
198 #if defined BOOST_THREAD_USES_DATETIME
199         template<typename TimeDuration>
200         bool timed_lock(TimeDuration const & relative_time)
201         {
202             return timed_lock(get_system_time()+relative_time);
203         }
204         bool timed_lock(boost::xtime const & absolute_time)
205         {
206             return timed_lock(system_time(absolute_time));
207         }
208 #endif
209 #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
210         void lock()
211         {
212             int res = posix::pthread_mutex_lock(&m);
213             if (res)
214             {
215                 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
216             }
217         }
218
219         void unlock()
220         {
221             int res = posix::pthread_mutex_unlock(&m);
222             if (res)
223             {
224                 boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
225             }
226         }
227
228         bool try_lock()
229         {
230           int res;
231           do
232           {
233               res = pthread_mutex_trylock(&m);
234           } while (res == EINTR);
235           if (res==EBUSY)
236           {
237               return false;
238           }
239
240           return !res;
241         }
242
243
244     private:
245         bool do_try_lock_until(struct timespec const &timeout)
246         {
247           int const res=pthread_mutex_timedlock(&m,&timeout);
248           BOOST_ASSERT(!res || res==ETIMEDOUT);
249           return !res;
250         }
251     public:
252
253 #else
254         void lock()
255         {
256             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
257             while(is_locked)
258             {
259                 BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
260             }
261             is_locked=true;
262         }
263
264         void unlock()
265         {
266             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
267             is_locked=false;
268             BOOST_VERIFY(!pthread_cond_signal(&cond));
269         }
270
271         bool try_lock()
272         {
273             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
274             if(is_locked)
275             {
276                 return false;
277             }
278             is_locked=true;
279             return true;
280         }
281
282     private:
283         bool do_try_lock_until(struct timespec const &timeout)
284         {
285             boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
286             while(is_locked)
287             {
288                 int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
289                 if(cond_res==ETIMEDOUT)
290                 {
291                     return false;
292                 }
293                 BOOST_ASSERT(!cond_res);
294             }
295             is_locked=true;
296             return true;
297         }
298     public:
299 #endif
300
301 #if defined BOOST_THREAD_USES_DATETIME
302         bool timed_lock(system_time const & abs_time)
303         {
304             struct timespec const ts=boost::detail::to_timespec(abs_time);
305             return do_try_lock_until(ts);
306         }
307 #endif
308 #ifdef BOOST_THREAD_USES_CHRONO
309         template <class Rep, class Period>
310         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
311         {
312           return try_lock_until(chrono::steady_clock::now() + rel_time);
313         }
314         template <class Clock, class Duration>
315         bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
316         {
317           using namespace chrono;
318           system_clock::time_point     s_now = system_clock::now();
319           typename Clock::time_point  c_now = Clock::now();
320           return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
321         }
322         template <class Duration>
323         bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
324         {
325           using namespace chrono;
326           typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
327           return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
328         }
329         bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
330         {
331           //using namespace chrono;
332           chrono::nanoseconds d = tp.time_since_epoch();
333           timespec ts = boost::detail::to_timespec(d);
334           return do_try_lock_until(ts);
335         }
336 #endif
337
338 #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
339         typedef pthread_mutex_t* native_handle_type;
340         native_handle_type native_handle()
341         {
342             return &m;
343         }
344
345 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
346         typedef unique_lock<timed_mutex> scoped_timed_lock;
347         typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
348         typedef scoped_timed_lock scoped_lock;
349 #endif
350     };
351
352 }
353
354 #include <boost/config/abi_suffix.hpp>
355
356
357 #endif