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_VALID_EXTERNAL_API_CALL( |
40 | ec == 0, "call to mutex::unlock failed. A possible reason is that the mutex wasn't locked" ); |
41 | } |
42 | |
43 | // recursive_mutex |
44 | |
45 | recursive_mutex::recursive_mutex() { |
46 | int ec = __libcpp_recursive_mutex_init(&__m_); |
47 | if (ec) |
48 | __throw_system_error(ec, "recursive_mutex constructor failed" ); |
49 | } |
50 | |
51 | recursive_mutex::~recursive_mutex() { |
52 | int e = __libcpp_recursive_mutex_destroy(&__m_); |
53 | (void)e; |
54 | _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(e == 0, "call to ~recursive_mutex() failed" ); |
55 | } |
56 | |
57 | void recursive_mutex::lock() { |
58 | int ec = __libcpp_recursive_mutex_lock(&__m_); |
59 | if (ec) |
60 | __throw_system_error(ec, "recursive_mutex lock failed" ); |
61 | } |
62 | |
63 | void recursive_mutex::unlock() noexcept { |
64 | int e = __libcpp_recursive_mutex_unlock(&__m_); |
65 | (void)e; |
66 | _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL( |
67 | e == 0, "call to recursive_mutex::unlock() failed. A possible reason is that the mutex wasn't locked" ); |
68 | } |
69 | |
70 | bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); } |
71 | |
72 | // timed_mutex |
73 | |
74 | timed_mutex::timed_mutex() : __locked_(false) {} |
75 | |
76 | timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); } |
77 | |
78 | void timed_mutex::lock() { |
79 | unique_lock<mutex> lk(__m_); |
80 | while (__locked_) |
81 | __cv_.wait(lk); |
82 | __locked_ = true; |
83 | } |
84 | |
85 | bool timed_mutex::try_lock() noexcept { |
86 | unique_lock<mutex> lk(__m_, try_to_lock); |
87 | if (lk.owns_lock() && !__locked_) { |
88 | __locked_ = true; |
89 | return true; |
90 | } |
91 | return false; |
92 | } |
93 | |
94 | void timed_mutex::unlock() noexcept { |
95 | lock_guard<mutex> _(__m_); |
96 | __locked_ = false; |
97 | __cv_.notify_one(); |
98 | } |
99 | |
100 | // recursive_timed_mutex |
101 | |
102 | recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {} |
103 | |
104 | recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); } |
105 | |
106 | void recursive_timed_mutex::lock() { |
107 | __thread_id id = this_thread::get_id(); |
108 | unique_lock<mutex> lk(__m_); |
109 | if (id == __id_) { |
110 | if (__count_ == numeric_limits<size_t>::max()) |
111 | __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached" ); |
112 | ++__count_; |
113 | return; |
114 | } |
115 | while (__count_ != 0) |
116 | __cv_.wait(lk); |
117 | __count_ = 1; |
118 | __id_ = id; |
119 | } |
120 | |
121 | bool recursive_timed_mutex::try_lock() noexcept { |
122 | __thread_id id = this_thread::get_id(); |
123 | unique_lock<mutex> lk(__m_, try_to_lock); |
124 | if (lk.owns_lock() && (__count_ == 0 || id == __id_)) { |
125 | if (__count_ == numeric_limits<size_t>::max()) |
126 | return false; |
127 | ++__count_; |
128 | __id_ = id; |
129 | return true; |
130 | } |
131 | return false; |
132 | } |
133 | |
134 | void recursive_timed_mutex::unlock() noexcept { |
135 | unique_lock<mutex> lk(__m_); |
136 | if (--__count_ == 0) { |
137 | __id_.__reset(); |
138 | lk.unlock(); |
139 | __cv_.notify_one(); |
140 | } |
141 | } |
142 | |
143 | _LIBCPP_END_NAMESPACE_STD |
144 | |
145 | _LIBCPP_POP_MACROS |
146 | |