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