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: 39*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {} 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 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 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 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> 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> 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 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 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 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 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 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_; } 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> 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> 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> 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> 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> 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> 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