xref: /freebsd-src/contrib/llvm-project/libcxx/include/__mutex/unique_lock.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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