blob: 515029bf232c65b1ad551ad137589fd9e0af47a6 [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
Howard Hinnantf5256e12010-05-11 21:36:01 +00004// The LLVM Compiler Infrastructure
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00005//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#ifndef _LIBCPP___MUTEX_BASE
12#define _LIBCPP___MUTEX_BASE
13
14#include <__config>
15#include <chrono>
16#include <system_error>
17#include <pthread.h>
18
19#pragma GCC system_header
20
21_LIBCPP_BEGIN_NAMESPACE_STD
22
23class mutex
24{
25 pthread_mutex_t __m_;
26
27public:
28 mutex() {__m_ = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;}
29 ~mutex();
30
31private:
32 mutex(const mutex&);// = delete;
33 mutex& operator=(const mutex&);// = delete;
34
35public:
36 void lock();
37 bool try_lock();
38 void unlock();
39
40 typedef pthread_mutex_t* native_handle_type;
41 native_handle_type native_handle() {return &__m_;}
42};
43
44struct defer_lock_t {};
45struct try_to_lock_t {};
46struct adopt_lock_t {};
47
48//constexpr
49extern const
50defer_lock_t defer_lock;
51
52//constexpr
53extern const
54try_to_lock_t try_to_lock;
55
56//constexpr
57extern const
58adopt_lock_t adopt_lock;
59
60template <class _Mutex>
61class lock_guard
62{
63public:
64 typedef _Mutex mutex_type;
65
66private:
67 mutex_type& __m_;
68public:
69
70 explicit lock_guard(mutex_type& __m)
71 : __m_(__m) {__m_.lock();}
72 lock_guard(mutex_type& __m, adopt_lock_t)
73 : __m_(__m) {}
74 ~lock_guard() {__m_.unlock();}
75
76private:
77 lock_guard(lock_guard const&);// = delete;
78 lock_guard& operator=(lock_guard const&);// = delete;
79};
80
81template <class _Mutex>
82class unique_lock
83{
84public:
85 typedef _Mutex mutex_type;
86
87private:
88 mutex_type* __m_;
89 bool __owns_;
90
91public:
92 unique_lock() : __m_(nullptr), __owns_(false) {}
93 explicit unique_lock(mutex_type& __m)
94 : __m_(&__m), __owns_(true) {__m_->lock();}
95 unique_lock(mutex_type& __m, defer_lock_t)
96 : __m_(&__m), __owns_(false) {}
97 unique_lock(mutex_type& __m, try_to_lock_t)
98 : __m_(&__m), __owns_(__m.try_lock()) {}
99 unique_lock(mutex_type& __m, adopt_lock_t)
100 : __m_(&__m), __owns_(true) {}
101 template <class _Clock, class _Duration>
102 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
103 : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
104 template <class _Rep, class _Period>
105 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
106 : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
107 ~unique_lock()
108 {
109 if (__owns_)
110 __m_->unlock();
111 }
112
113private:
114 unique_lock(unique_lock const&); // = delete;
115 unique_lock& operator=(unique_lock const&); // = delete;
116
117public:
Howard Hinnant73d21a42010-09-04 23:28:19 +0000118#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000119 unique_lock(unique_lock&& __u)
120 : __m_(__u.__m_), __owns_(__u.__owns_)
121 {__u.__m_ = nullptr; __u.__owns_ = false;}
122 unique_lock& operator=(unique_lock&& __u)
123 {
124 if (__owns_)
125 __m_->unlock();
126 __m_ = __u.__m_;
127 __owns_ = __u.__owns_;
128 __u.__m_ = nullptr;
129 __u.__owns_ = false;
130 return *this;
131 }
Howard Hinnant73d21a42010-09-04 23:28:19 +0000132#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000133
134 void lock();
135 bool try_lock();
136
137 template <class _Rep, class _Period>
138 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
139 template <class _Clock, class _Duration>
140 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
141
142 void unlock();
143
144 void swap(unique_lock& __u)
145 {
146 _STD::swap(__m_, __u.__m_);
147 _STD::swap(__owns_, __u.__owns_);
148 }
149 mutex_type* release()
150 {
151 mutex_type* __m = __m_;
152 __m_ = nullptr;
153 __owns_ = false;
154 return __m;
155 }
156
157 bool owns_lock() const {return __owns_;}
158// explicit
159 operator bool () const {return __owns_;}
160 mutex_type* mutex() const {return __m_;}
161};
162
163template <class _Mutex>
164void
165unique_lock<_Mutex>::lock()
166{
167 if (__m_ == nullptr)
168 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
169 if (__owns_)
170 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
171 __m_->lock();
172 __owns_ = true;
173}
174
175template <class _Mutex>
176bool
177unique_lock<_Mutex>::try_lock()
178{
179 if (__m_ == nullptr)
180 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
181 if (__owns_)
182 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
183 __owns_ = __m_->try_lock();
184 return __owns_;
185}
186
187template <class _Mutex>
188template <class _Rep, class _Period>
189bool
190unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
191{
192 if (__m_ == nullptr)
193 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
194 if (__owns_)
195 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
196 __owns_ = __m_->try_lock_for(__d);
197 return __owns_;
198}
199
200template <class _Mutex>
201template <class _Clock, class _Duration>
202bool
203unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
204{
205 if (__m_ == nullptr)
206 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
207 if (__owns_)
208 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
209 __owns_ = __m_->try_lock_until(__t);
210 return __owns_;
211}
212
213template <class _Mutex>
214void
215unique_lock<_Mutex>::unlock()
216{
217 if (!__owns_)
218 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
219 __m_->unlock();
220 __owns_ = false;
221}
222
223template <class _Mutex>
224inline
225void
226swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) {__x.swap(__y);}
227
228struct cv_status
229{
230 enum _ {
231 no_timeout,
232 timeout
233 };
234
235 _ __v_;
236
237 cv_status(_ __v) : __v_(__v) {}
238 operator int() const {return __v_;}
239
240};
241
242class condition_variable
243{
244 pthread_cond_t __cv_;
245public:
246 condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
247 ~condition_variable();
248
249private:
250 condition_variable(const condition_variable&); // = delete;
251 condition_variable& operator=(const condition_variable&); // = delete;
252
253public:
254 void notify_one();
255 void notify_all();
256
257 void wait(unique_lock<mutex>& __lk);
258 template <class _Predicate>
259 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
260
261 template <class _Duration>
262 cv_status
263 wait_until(unique_lock<mutex>& __lk,
264 const chrono::time_point<chrono::system_clock, _Duration>& __t);
265
266 template <class _Clock, class _Duration>
267 cv_status
268 wait_until(unique_lock<mutex>& __lk,
269 const chrono::time_point<_Clock, _Duration>& __t);
270
271 template <class _Clock, class _Duration, class _Predicate>
272 bool
273 wait_until(unique_lock<mutex>& __lk,
274 const chrono::time_point<_Clock, _Duration>& __t,
275 _Predicate __pred);
276
277 template <class _Rep, class _Period>
278 cv_status
279 wait_for(unique_lock<mutex>& __lk,
280 const chrono::duration<_Rep, _Period>& __d);
281
282 template <class _Rep, class _Period, class _Predicate>
283 bool
284 wait_for(unique_lock<mutex>& __lk,
285 const chrono::duration<_Rep, _Period>& __d,
286 _Predicate __pred);
287
288 typedef pthread_cond_t* native_handle_type;
289 native_handle_type native_handle() {return &__cv_;}
290
291private:
292 void __do_timed_wait(unique_lock<mutex>& __lk,
293 chrono::time_point<chrono::system_clock, chrono::nanoseconds>);
294};
295
296template <class _To, class _Rep, class _Period>
297inline
298typename enable_if
299<
300 chrono::__is_duration<_To>::value,
301 _To
302>::type
303__ceil(chrono::duration<_Rep, _Period> __d)
304{
305 using namespace chrono;
306 _To __r = duration_cast<_To>(__d);
307 if (__r < __d)
308 ++__r;
309 return __r;
310}
311
312template <class _Predicate>
313void
314condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
315{
316 while (!__pred())
317 wait(__lk);
318}
319
320template <class _Duration>
321cv_status
322condition_variable::wait_until(unique_lock<mutex>& __lk,
323 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 __do_timed_wait(__lk,
328 __nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch())));
329 return system_clock::now() < __t ? cv_status::no_timeout :
330 cv_status::timeout;
331}
332
333template <class _Clock, class _Duration>
334cv_status
335condition_variable::wait_until(unique_lock<mutex>& __lk,
336 const chrono::time_point<_Clock, _Duration>& __t)
337{
338 using namespace chrono;
339 system_clock::time_point __s_now = system_clock::now();
340 typename _Clock::time_point __c_now = _Clock::now();
341 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now));
342 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
343}
344
345template <class _Clock, class _Duration, class _Predicate>
346bool
347condition_variable::wait_until(unique_lock<mutex>& __lk,
348 const chrono::time_point<_Clock, _Duration>& __t,
349 _Predicate __pred)
350{
351 while (!__pred())
352 {
353 if (wait_until(__lk, __t) == cv_status::timeout)
354 return __pred();
355 }
356 return true;
357}
358
359template <class _Rep, class _Period>
360cv_status
361condition_variable::wait_for(unique_lock<mutex>& __lk,
362 const chrono::duration<_Rep, _Period>& __d)
363{
364 using namespace chrono;
365 system_clock::time_point __s_now = system_clock::now();
366 monotonic_clock::time_point __c_now = monotonic_clock::now();
367 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
368 return monotonic_clock::now() - __c_now < __d ? cv_status::no_timeout :
369 cv_status::timeout;
370}
371
372template <class _Rep, class _Period, class _Predicate>
373inline
374bool
375condition_variable::wait_for(unique_lock<mutex>& __lk,
376 const chrono::duration<_Rep, _Period>& __d,
377 _Predicate __pred)
378{
379 return wait_until(__lk, chrono::monotonic_clock::now() + __d,
380 _STD::move(__pred));
381}
382
383_LIBCPP_END_NAMESPACE_STD
384
385#endif // _LIBCPP___MUTEX_BASE