1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___MUTEX_BASE
11#define _LIBCPP___MUTEX_BASE
12
13#include <__config>
14#include <chrono>
15#include <system_error>
16#include <__threading_support>
17
18
19#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20#pragma GCC system_header
21#endif
22
23_LIBCPP_PUSH_MACROS
24#include <__undef_macros>
25
26
27_LIBCPP_BEGIN_NAMESPACE_STD
28
29#ifndef _LIBCPP_HAS_NO_THREADS
30
31#ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION
32# ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
33# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
34# else
35# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
36# endif
37#endif // _LIBCPP_THREAD_SAFETY_ANNOTATION
38
39class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
40{
41#ifndef _LIBCPP_CXX03_LANG
42 __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
43#else
44 __libcpp_mutex_t __m_;
45#endif
46
47public:
48 _LIBCPP_INLINE_VISIBILITY
49#ifndef _LIBCPP_CXX03_LANG
50 constexpr mutex() = default;
51#else
52 mutex() _NOEXCEPT {__m_ = (__libcpp_mutex_t)_LIBCPP_MUTEX_INITIALIZER;}
53#endif
54 ~mutex();
55
56private:
57 mutex(const mutex&);// = delete;
58 mutex& operator=(const mutex&);// = delete;
59
60public:
61 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
62 bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
63 void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
64
65 typedef __libcpp_mutex_t* native_handle_type;
66 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
67};
68
69static_assert(is_nothrow_default_constructible<mutex>::value,
70 "the default constructor for std::mutex must be nothrow");
71
72struct _LIBCPP_TYPE_VIS defer_lock_t {};
73struct _LIBCPP_TYPE_VIS try_to_lock_t {};
74struct _LIBCPP_TYPE_VIS adopt_lock_t {};
75
76#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
77
78extern _LIBCPP_EXPORTED_FROM_ABI const defer_lock_t defer_lock;
79extern _LIBCPP_EXPORTED_FROM_ABI const try_to_lock_t try_to_lock;
80extern _LIBCPP_EXPORTED_FROM_ABI const adopt_lock_t adopt_lock;
81
82#else
83
84/* _LIBCPP_INLINE_VAR */ constexpr defer_lock_t defer_lock = defer_lock_t();
85/* _LIBCPP_INLINE_VAR */ constexpr try_to_lock_t try_to_lock = try_to_lock_t();
86/* _LIBCPP_INLINE_VAR */ constexpr adopt_lock_t adopt_lock = adopt_lock_t();
87
88#endif
89
90template <class _Mutex>
91class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable)
92lock_guard
93{
94public:
95 typedef _Mutex mutex_type;
96
97private:
98 mutex_type& __m_;
99public:
100
101 _LIBCPP_INLINE_VISIBILITY
102 explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
103 : __m_(__m) {__m_.lock();}
104 _LIBCPP_INLINE_VISIBILITY
105 lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
106 : __m_(__m) {}
107 _LIBCPP_INLINE_VISIBILITY
108 ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
109
110private:
111 lock_guard(lock_guard const&) _LIBCPP_EQUAL_DELETE;
112 lock_guard& operator=(lock_guard const&) _LIBCPP_EQUAL_DELETE;
113};
114
115template <class _Mutex>
116class _LIBCPP_TEMPLATE_VIS unique_lock
117{
118public:
119 typedef _Mutex mutex_type;
120
121private:
122 mutex_type* __m_;
123 bool __owns_;
124
125public:
126 _LIBCPP_INLINE_VISIBILITY
127 unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
128 _LIBCPP_INLINE_VISIBILITY
129 explicit unique_lock(mutex_type& __m)
130 : __m_(_VSTD::addressof(__m)), __owns_(true) {__m_->lock();}
131 _LIBCPP_INLINE_VISIBILITY
132 unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
133 : __m_(_VSTD::addressof(__m)), __owns_(false) {}
134 _LIBCPP_INLINE_VISIBILITY
135 unique_lock(mutex_type& __m, try_to_lock_t)
136 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock()) {}
137 _LIBCPP_INLINE_VISIBILITY
138 unique_lock(mutex_type& __m, adopt_lock_t)
139 : __m_(_VSTD::addressof(__m)), __owns_(true) {}
140 template <class _Clock, class _Duration>
141 _LIBCPP_INLINE_VISIBILITY
142 unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
143 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
144 template <class _Rep, class _Period>
145 _LIBCPP_INLINE_VISIBILITY
146 unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
147 : __m_(_VSTD::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
148 _LIBCPP_INLINE_VISIBILITY
149 ~unique_lock()
150 {
151 if (__owns_)
152 __m_->unlock();
153 }
154
155private:
156 unique_lock(unique_lock const&); // = delete;
157 unique_lock& operator=(unique_lock const&); // = delete;
158
159public:
160#ifndef _LIBCPP_CXX03_LANG
161 _LIBCPP_INLINE_VISIBILITY
162 unique_lock(unique_lock&& __u) _NOEXCEPT
163 : __m_(__u.__m_), __owns_(__u.__owns_)
164 {__u.__m_ = nullptr; __u.__owns_ = false;}
165 _LIBCPP_INLINE_VISIBILITY
166 unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
167 {
168 if (__owns_)
169 __m_->unlock();
170 __m_ = __u.__m_;
171 __owns_ = __u.__owns_;
172 __u.__m_ = nullptr;
173 __u.__owns_ = false;
174 return *this;
175 }
176
177#endif // _LIBCPP_CXX03_LANG
178
179 void lock();
180 bool try_lock();
181
182 template <class _Rep, class _Period>
183 bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
184 template <class _Clock, class _Duration>
185 bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
186
187 void unlock();
188
189 _LIBCPP_INLINE_VISIBILITY
190 void swap(unique_lock& __u) _NOEXCEPT
191 {
192 _VSTD::swap(__m_, __u.__m_);
193 _VSTD::swap(__owns_, __u.__owns_);
194 }
195 _LIBCPP_INLINE_VISIBILITY
196 mutex_type* release() _NOEXCEPT
197 {
198 mutex_type* __m = __m_;
199 __m_ = nullptr;
200 __owns_ = false;
201 return __m;
202 }
203
204 _LIBCPP_INLINE_VISIBILITY
205 bool owns_lock() const _NOEXCEPT {return __owns_;}
206 _LIBCPP_INLINE_VISIBILITY
207 _LIBCPP_EXPLICIT
208 operator bool () const _NOEXCEPT {return __owns_;}
209 _LIBCPP_INLINE_VISIBILITY
210 mutex_type* mutex() const _NOEXCEPT {return __m_;}
211};
212
213template <class _Mutex>
214void
215unique_lock<_Mutex>::lock()
216{
217 if (__m_ == nullptr)
218 __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
219 if (__owns_)
220 __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
221 __m_->lock();
222 __owns_ = true;
223}
224
225template <class _Mutex>
226bool
227unique_lock<_Mutex>::try_lock()
228{
229 if (__m_ == nullptr)
230 __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
231 if (__owns_)
232 __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
233 __owns_ = __m_->try_lock();
234 return __owns_;
235}
236
237template <class _Mutex>
238template <class _Rep, class _Period>
239bool
240unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
241{
242 if (__m_ == nullptr)
243 __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
244 if (__owns_)
245 __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
246 __owns_ = __m_->try_lock_for(__d);
247 return __owns_;
248}
249
250template <class _Mutex>
251template <class _Clock, class _Duration>
252bool
253unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
254{
255 if (__m_ == nullptr)
256 __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
257 if (__owns_)
258 __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
259 __owns_ = __m_->try_lock_until(__t);
260 return __owns_;
261}
262
263template <class _Mutex>
264void
265unique_lock<_Mutex>::unlock()
266{
267 if (!__owns_)
268 __throw_system_error(EPERM, "unique_lock::unlock: not locked");
269 __m_->unlock();
270 __owns_ = false;
271}
272
273template <class _Mutex>
274inline _LIBCPP_INLINE_VISIBILITY
275void
276swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT
277 {__x.swap(__y);}
278
279//enum class cv_status
280_LIBCPP_DECLARE_STRONG_ENUM(cv_status)
281{
282 no_timeout,
283 timeout
284};
285_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
286
287class _LIBCPP_TYPE_VIS condition_variable
288{
289#ifndef _LIBCPP_CXX03_LANG
290 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
291#else
292 __libcpp_condvar_t __cv_;
293#endif
294
295public:
296 _LIBCPP_INLINE_VISIBILITY
297#ifndef _LIBCPP_CXX03_LANG
298 constexpr condition_variable() _NOEXCEPT = default;
299#else
300 condition_variable() _NOEXCEPT {__cv_ = (__libcpp_condvar_t)_LIBCPP_CONDVAR_INITIALIZER;}
301#endif
302 ~condition_variable();
303
304private:
305 condition_variable(const condition_variable&); // = delete;
306 condition_variable& operator=(const condition_variable&); // = delete;
307
308public:
309 void notify_one() _NOEXCEPT;
310 void notify_all() _NOEXCEPT;
311
312 void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
313 template <class _Predicate>
314 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
315 void wait(unique_lock<mutex>& __lk, _Predicate __pred);
316
317 template <class _Clock, class _Duration>
318 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
319 cv_status
320 wait_until(unique_lock<mutex>& __lk,
321 const chrono::time_point<_Clock, _Duration>& __t);
322
323 template <class _Clock, class _Duration, class _Predicate>
324 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
325 bool
326 wait_until(unique_lock<mutex>& __lk,
327 const chrono::time_point<_Clock, _Duration>& __t,
328 _Predicate __pred);
329
330 template <class _Rep, class _Period>
331 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
332 cv_status
333 wait_for(unique_lock<mutex>& __lk,
334 const chrono::duration<_Rep, _Period>& __d);
335
336 template <class _Rep, class _Period, class _Predicate>
337 bool
338 _LIBCPP_INLINE_VISIBILITY
339 wait_for(unique_lock<mutex>& __lk,
340 const chrono::duration<_Rep, _Period>& __d,
341 _Predicate __pred);
342
343 typedef __libcpp_condvar_t* native_handle_type;
344 _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
345
346private:
347 void __do_timed_wait(unique_lock<mutex>& __lk,
348 chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
349};
350#endif // !_LIBCPP_HAS_NO_THREADS
351
352template <class _To, class _Rep, class _Period>
353inline _LIBCPP_INLINE_VISIBILITY
354typename enable_if
355<
356 chrono::__is_duration<_To>::value,
357 _To
358>::type
359__ceil(chrono::duration<_Rep, _Period> __d)
360{
361 using namespace chrono;
362 _To __r = duration_cast<_To>(__d);
363 if (__r < __d)
364 ++__r;
365 return __r;
366}
367
368#ifndef _LIBCPP_HAS_NO_THREADS
369template <class _Predicate>
370void
371condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred)
372{
373 while (!__pred())
374 wait(__lk);
375}
376
377template <class _Clock, class _Duration>
378cv_status
379condition_variable::wait_until(unique_lock<mutex>& __lk,
380 const chrono::time_point<_Clock, _Duration>& __t)
381{
382 using namespace chrono;
383 wait_for(__lk, __t - _Clock::now());
384 return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
385}
386
387template <class _Clock, class _Duration, class _Predicate>
388bool
389condition_variable::wait_until(unique_lock<mutex>& __lk,
390 const chrono::time_point<_Clock, _Duration>& __t,
391 _Predicate __pred)
392{
393 while (!__pred())
394 {
395 if (wait_until(__lk, __t) == cv_status::timeout)
396 return __pred();
397 }
398 return true;
399}
400
401template <class _Rep, class _Period>
402cv_status
403condition_variable::wait_for(unique_lock<mutex>& __lk,
404 const chrono::duration<_Rep, _Period>& __d)
405{
406 using namespace chrono;
407 if (__d <= __d.zero())
408 return cv_status::timeout;
409 typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
410 typedef time_point<system_clock, nanoseconds> __sys_tpi;
411 __sys_tpf _Max = __sys_tpi::max();
412 steady_clock::time_point __c_now = steady_clock::now();
413 system_clock::time_point __s_now = system_clock::now();
414 if (_Max - __d > __s_now)
415 __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
416 else
417 __do_timed_wait(__lk, __sys_tpi::max());
418 return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
419 cv_status::timeout;
420}
421
422template <class _Rep, class _Period, class _Predicate>
423inline
424bool
425condition_variable::wait_for(unique_lock<mutex>& __lk,
426 const chrono::duration<_Rep, _Period>& __d,
427 _Predicate __pred)
428{
429 return wait_until(__lk, chrono::steady_clock::now() + __d,
430 _VSTD::move(__pred));
431}
432
433#endif // !_LIBCPP_HAS_NO_THREADS
434
435_LIBCPP_END_NAMESPACE_STD
436
437_LIBCPP_POP_MACROS
438
439#endif // _LIBCPP___MUTEX_BASE
440