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