1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <__assert> 10 #include <__thread/id.h> 11 #include <__utility/exception_guard.h> 12 #include <limits> 13 #include <mutex> 14 15 #include "include/atomic_support.h" 16 17 #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) 18 # pragma comment(lib, "pthread") 19 #endif 20 21 _LIBCPP_PUSH_MACROS 22 #include <__undef_macros> 23 24 _LIBCPP_BEGIN_NAMESPACE_STD 25 26 // ~mutex is defined elsewhere 27 28 void mutex::lock() { 29 int ec = __libcpp_mutex_lock(&__m_); 30 if (ec) 31 __throw_system_error(ec, "mutex lock failed"); 32 } 33 34 bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(&__m_); } 35 36 void mutex::unlock() noexcept { 37 int ec = __libcpp_mutex_unlock(&__m_); 38 (void)ec; 39 _LIBCPP_ASSERT_UNCATEGORIZED(ec == 0, "call to mutex::unlock failed"); 40 } 41 42 // recursive_mutex 43 44 recursive_mutex::recursive_mutex() { 45 int ec = __libcpp_recursive_mutex_init(&__m_); 46 if (ec) 47 __throw_system_error(ec, "recursive_mutex constructor failed"); 48 } 49 50 recursive_mutex::~recursive_mutex() { 51 int e = __libcpp_recursive_mutex_destroy(&__m_); 52 (void)e; 53 _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to ~recursive_mutex() failed"); 54 } 55 56 void recursive_mutex::lock() { 57 int ec = __libcpp_recursive_mutex_lock(&__m_); 58 if (ec) 59 __throw_system_error(ec, "recursive_mutex lock failed"); 60 } 61 62 void recursive_mutex::unlock() noexcept { 63 int e = __libcpp_recursive_mutex_unlock(&__m_); 64 (void)e; 65 _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to recursive_mutex::unlock() failed"); 66 } 67 68 bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); } 69 70 // timed_mutex 71 72 timed_mutex::timed_mutex() : __locked_(false) {} 73 74 timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); } 75 76 void timed_mutex::lock() { 77 unique_lock<mutex> lk(__m_); 78 while (__locked_) 79 __cv_.wait(lk); 80 __locked_ = true; 81 } 82 83 bool timed_mutex::try_lock() noexcept { 84 unique_lock<mutex> lk(__m_, try_to_lock); 85 if (lk.owns_lock() && !__locked_) { 86 __locked_ = true; 87 return true; 88 } 89 return false; 90 } 91 92 void timed_mutex::unlock() noexcept { 93 lock_guard<mutex> _(__m_); 94 __locked_ = false; 95 __cv_.notify_one(); 96 } 97 98 // recursive_timed_mutex 99 100 recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {} 101 102 recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); } 103 104 void recursive_timed_mutex::lock() { 105 __thread_id id = this_thread::get_id(); 106 unique_lock<mutex> lk(__m_); 107 if (id == __id_) { 108 if (__count_ == numeric_limits<size_t>::max()) 109 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); 110 ++__count_; 111 return; 112 } 113 while (__count_ != 0) 114 __cv_.wait(lk); 115 __count_ = 1; 116 __id_ = id; 117 } 118 119 bool recursive_timed_mutex::try_lock() noexcept { 120 __thread_id id = this_thread::get_id(); 121 unique_lock<mutex> lk(__m_, try_to_lock); 122 if (lk.owns_lock() && (__count_ == 0 || id == __id_)) { 123 if (__count_ == numeric_limits<size_t>::max()) 124 return false; 125 ++__count_; 126 __id_ = id; 127 return true; 128 } 129 return false; 130 } 131 132 void recursive_timed_mutex::unlock() noexcept { 133 unique_lock<mutex> lk(__m_); 134 if (--__count_ == 0) { 135 __id_.__reset(); 136 lk.unlock(); 137 __cv_.notify_one(); 138 } 139 } 140 141 _LIBCPP_END_NAMESPACE_STD 142 143 _LIBCPP_POP_MACROS 144