106c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric
906c3fb27SDimitry Andric #ifndef _LIBCPP___MUTEX_UNIQUE_LOCK_H
1006c3fb27SDimitry Andric #define _LIBCPP___MUTEX_UNIQUE_LOCK_H
1106c3fb27SDimitry Andric
1206c3fb27SDimitry Andric #include <__chrono/duration.h>
1306c3fb27SDimitry Andric #include <__chrono/time_point.h>
1406c3fb27SDimitry Andric #include <__config>
1506c3fb27SDimitry Andric #include <__memory/addressof.h>
1606c3fb27SDimitry Andric #include <__mutex/tag_types.h>
1706c3fb27SDimitry Andric #include <__system_error/system_error.h>
1806c3fb27SDimitry Andric #include <__utility/swap.h>
1906c3fb27SDimitry Andric #include <cerrno>
2006c3fb27SDimitry Andric
2106c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2206c3fb27SDimitry Andric # pragma GCC system_header
2306c3fb27SDimitry Andric #endif
2406c3fb27SDimitry Andric
2506c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
2606c3fb27SDimitry Andric
2706c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
2806c3fb27SDimitry Andric
2906c3fb27SDimitry Andric template <class _Mutex>
3006c3fb27SDimitry Andric class _LIBCPP_TEMPLATE_VIS unique_lock {
3106c3fb27SDimitry Andric public:
3206c3fb27SDimitry Andric typedef _Mutex mutex_type;
3306c3fb27SDimitry Andric
3406c3fb27SDimitry Andric private:
3506c3fb27SDimitry Andric mutex_type* __m_;
3606c3fb27SDimitry Andric bool __owns_;
3706c3fb27SDimitry Andric
3806c3fb27SDimitry Andric public:
unique_lock()39*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
unique_lock(mutex_type & __m)40*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI explicit unique_lock(mutex_type& __m)
41*0fca6ea1SDimitry Andric : __m_(std::addressof(__m)), __owns_(true) {
4206c3fb27SDimitry Andric __m_->lock();
4306c3fb27SDimitry Andric }
4406c3fb27SDimitry Andric
unique_lock(mutex_type & __m,defer_lock_t)45*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
4606c3fb27SDimitry Andric : __m_(std::addressof(__m)),
4706c3fb27SDimitry Andric __owns_(false) {}
4806c3fb27SDimitry Andric
unique_lock(mutex_type & __m,try_to_lock_t)49*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, try_to_lock_t)
5006c3fb27SDimitry Andric : __m_(std::addressof(__m)), __owns_(__m.try_lock()) {}
5106c3fb27SDimitry Andric
unique_lock(mutex_type & __m,adopt_lock_t)52*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, adopt_lock_t)
53*0fca6ea1SDimitry Andric : __m_(std::addressof(__m)), __owns_(true) {}
5406c3fb27SDimitry Andric
5506c3fb27SDimitry Andric template <class _Clock, class _Duration>
unique_lock(mutex_type & __m,const chrono::time_point<_Clock,_Duration> & __t)56*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
5706c3fb27SDimitry Andric : __m_(std::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
5806c3fb27SDimitry Andric
5906c3fb27SDimitry Andric template <class _Rep, class _Period>
unique_lock(mutex_type & __m,const chrono::duration<_Rep,_Period> & __d)60*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
6106c3fb27SDimitry Andric : __m_(std::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
6206c3fb27SDimitry Andric
~unique_lock()6306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI ~unique_lock() {
6406c3fb27SDimitry Andric if (__owns_)
6506c3fb27SDimitry Andric __m_->unlock();
6606c3fb27SDimitry Andric }
6706c3fb27SDimitry Andric
6806c3fb27SDimitry Andric unique_lock(unique_lock const&) = delete;
6906c3fb27SDimitry Andric unique_lock& operator=(unique_lock const&) = delete;
7006c3fb27SDimitry Andric
unique_lock(unique_lock && __u)71*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock(unique_lock&& __u) _NOEXCEPT
72*0fca6ea1SDimitry Andric : __m_(__u.__m_),
73*0fca6ea1SDimitry Andric __owns_(__u.__owns_) {
7406c3fb27SDimitry Andric __u.__m_ = nullptr;
7506c3fb27SDimitry Andric __u.__owns_ = false;
7606c3fb27SDimitry Andric }
7706c3fb27SDimitry Andric
7806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI unique_lock& operator=(unique_lock&& __u) _NOEXCEPT {
7906c3fb27SDimitry Andric if (__owns_)
8006c3fb27SDimitry Andric __m_->unlock();
8106c3fb27SDimitry Andric
8206c3fb27SDimitry Andric __m_ = __u.__m_;
8306c3fb27SDimitry Andric __owns_ = __u.__owns_;
8406c3fb27SDimitry Andric __u.__m_ = nullptr;
8506c3fb27SDimitry Andric __u.__owns_ = false;
8606c3fb27SDimitry Andric return *this;
8706c3fb27SDimitry Andric }
8806c3fb27SDimitry Andric
8906c3fb27SDimitry Andric void lock();
9006c3fb27SDimitry Andric bool try_lock();
9106c3fb27SDimitry Andric
9206c3fb27SDimitry Andric template <class _Rep, class _Period>
9306c3fb27SDimitry Andric bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
9406c3fb27SDimitry Andric
9506c3fb27SDimitry Andric template <class _Clock, class _Duration>
9606c3fb27SDimitry Andric bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
9706c3fb27SDimitry Andric
9806c3fb27SDimitry Andric void unlock();
9906c3fb27SDimitry Andric
swap(unique_lock & __u)10006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void swap(unique_lock& __u) _NOEXCEPT {
10106c3fb27SDimitry Andric std::swap(__m_, __u.__m_);
10206c3fb27SDimitry Andric std::swap(__owns_, __u.__owns_);
10306c3fb27SDimitry Andric }
10406c3fb27SDimitry Andric
release()10506c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT {
10606c3fb27SDimitry Andric mutex_type* __m = __m_;
10706c3fb27SDimitry Andric __m_ = nullptr;
10806c3fb27SDimitry Andric __owns_ = false;
10906c3fb27SDimitry Andric return __m;
11006c3fb27SDimitry Andric }
11106c3fb27SDimitry Andric
owns_lock()11206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; }
11306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; }
mutex()11406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; }
11506c3fb27SDimitry Andric };
11606c3fb27SDimitry Andric _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(unique_lock);
11706c3fb27SDimitry Andric
11806c3fb27SDimitry Andric template <class _Mutex>
lock()11906c3fb27SDimitry Andric void unique_lock<_Mutex>::lock() {
12006c3fb27SDimitry Andric if (__m_ == nullptr)
12106c3fb27SDimitry Andric __throw_system_error(EPERM, "unique_lock::lock: references null mutex");
12206c3fb27SDimitry Andric if (__owns_)
12306c3fb27SDimitry Andric __throw_system_error(EDEADLK, "unique_lock::lock: already locked");
12406c3fb27SDimitry Andric __m_->lock();
12506c3fb27SDimitry Andric __owns_ = true;
12606c3fb27SDimitry Andric }
12706c3fb27SDimitry Andric
12806c3fb27SDimitry Andric template <class _Mutex>
try_lock()12906c3fb27SDimitry Andric bool unique_lock<_Mutex>::try_lock() {
13006c3fb27SDimitry Andric if (__m_ == nullptr)
13106c3fb27SDimitry Andric __throw_system_error(EPERM, "unique_lock::try_lock: references null mutex");
13206c3fb27SDimitry Andric if (__owns_)
13306c3fb27SDimitry Andric __throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
13406c3fb27SDimitry Andric __owns_ = __m_->try_lock();
13506c3fb27SDimitry Andric return __owns_;
13606c3fb27SDimitry Andric }
13706c3fb27SDimitry Andric
13806c3fb27SDimitry Andric template <class _Mutex>
13906c3fb27SDimitry Andric template <class _Rep, class _Period>
try_lock_for(const chrono::duration<_Rep,_Period> & __d)14006c3fb27SDimitry Andric bool unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
14106c3fb27SDimitry Andric if (__m_ == nullptr)
14206c3fb27SDimitry Andric __throw_system_error(EPERM, "unique_lock::try_lock_for: references null mutex");
14306c3fb27SDimitry Andric if (__owns_)
14406c3fb27SDimitry Andric __throw_system_error(EDEADLK, "unique_lock::try_lock_for: already locked");
14506c3fb27SDimitry Andric __owns_ = __m_->try_lock_for(__d);
14606c3fb27SDimitry Andric return __owns_;
14706c3fb27SDimitry Andric }
14806c3fb27SDimitry Andric
14906c3fb27SDimitry Andric template <class _Mutex>
15006c3fb27SDimitry Andric template <class _Clock, class _Duration>
try_lock_until(const chrono::time_point<_Clock,_Duration> & __t)15106c3fb27SDimitry Andric bool unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
15206c3fb27SDimitry Andric if (__m_ == nullptr)
15306c3fb27SDimitry Andric __throw_system_error(EPERM, "unique_lock::try_lock_until: references null mutex");
15406c3fb27SDimitry Andric if (__owns_)
15506c3fb27SDimitry Andric __throw_system_error(EDEADLK, "unique_lock::try_lock_until: already locked");
15606c3fb27SDimitry Andric __owns_ = __m_->try_lock_until(__t);
15706c3fb27SDimitry Andric return __owns_;
15806c3fb27SDimitry Andric }
15906c3fb27SDimitry Andric
16006c3fb27SDimitry Andric template <class _Mutex>
unlock()16106c3fb27SDimitry Andric void unique_lock<_Mutex>::unlock() {
16206c3fb27SDimitry Andric if (!__owns_)
16306c3fb27SDimitry Andric __throw_system_error(EPERM, "unique_lock::unlock: not locked");
16406c3fb27SDimitry Andric __m_->unlock();
16506c3fb27SDimitry Andric __owns_ = false;
16606c3fb27SDimitry Andric }
16706c3fb27SDimitry Andric
16806c3fb27SDimitry Andric template <class _Mutex>
swap(unique_lock<_Mutex> & __x,unique_lock<_Mutex> & __y)16906c3fb27SDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT {
17006c3fb27SDimitry Andric __x.swap(__y);
17106c3fb27SDimitry Andric }
17206c3fb27SDimitry Andric
17306c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
17406c3fb27SDimitry Andric
17506c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_THREADS
17606c3fb27SDimitry Andric
17706c3fb27SDimitry Andric #endif // _LIBCPP___MUTEX_UNIQUE_LOCK_H
178