Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / src / mutex.cpp
blobb165b1bc9debfc54c0144c62d6d6a6255f19de87
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 //===----------------------------------------------------------------------===//
9 #include <__assert>
10 #include <__thread/id.h>
11 #include <__utility/exception_guard.h>
12 #include <limits>
13 #include <mutex>
15 #include "include/atomic_support.h"
17 #ifndef _LIBCPP_HAS_NO_THREADS
18 # if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
19 # pragma comment(lib, "pthread")
20 # endif
21 #endif
23 _LIBCPP_PUSH_MACROS
24 #include <__undef_macros>
26 _LIBCPP_BEGIN_NAMESPACE_STD
28 #ifndef _LIBCPP_HAS_NO_THREADS
30 // ~mutex is defined elsewhere
32 void
33 mutex::lock()
35 int ec = __libcpp_mutex_lock(&__m_);
36 if (ec)
37 __throw_system_error(ec, "mutex lock failed");
40 bool
41 mutex::try_lock() noexcept
43 return __libcpp_mutex_trylock(&__m_);
46 void
47 mutex::unlock() noexcept
49 int ec = __libcpp_mutex_unlock(&__m_);
50 (void)ec;
51 _LIBCPP_ASSERT_UNCATEGORIZED(ec == 0, "call to mutex::unlock failed");
54 // recursive_mutex
56 recursive_mutex::recursive_mutex()
58 int ec = __libcpp_recursive_mutex_init(&__m_);
59 if (ec)
60 __throw_system_error(ec, "recursive_mutex constructor failed");
63 recursive_mutex::~recursive_mutex()
65 int e = __libcpp_recursive_mutex_destroy(&__m_);
66 (void)e;
67 _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to ~recursive_mutex() failed");
70 void
71 recursive_mutex::lock()
73 int ec = __libcpp_recursive_mutex_lock(&__m_);
74 if (ec)
75 __throw_system_error(ec, "recursive_mutex lock failed");
78 void
79 recursive_mutex::unlock() noexcept
81 int e = __libcpp_recursive_mutex_unlock(&__m_);
82 (void)e;
83 _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to recursive_mutex::unlock() failed");
86 bool
87 recursive_mutex::try_lock() noexcept
89 return __libcpp_recursive_mutex_trylock(&__m_);
92 // timed_mutex
94 timed_mutex::timed_mutex()
95 : __locked_(false)
99 timed_mutex::~timed_mutex()
101 lock_guard<mutex> _(__m_);
104 void
105 timed_mutex::lock()
107 unique_lock<mutex> lk(__m_);
108 while (__locked_)
109 __cv_.wait(lk);
110 __locked_ = true;
113 bool
114 timed_mutex::try_lock() noexcept
116 unique_lock<mutex> lk(__m_, try_to_lock);
117 if (lk.owns_lock() && !__locked_)
119 __locked_ = true;
120 return true;
122 return false;
125 void
126 timed_mutex::unlock() noexcept
128 lock_guard<mutex> _(__m_);
129 __locked_ = false;
130 __cv_.notify_one();
133 // recursive_timed_mutex
135 recursive_timed_mutex::recursive_timed_mutex()
136 : __count_(0),
137 __id_{}
141 recursive_timed_mutex::~recursive_timed_mutex()
143 lock_guard<mutex> _(__m_);
146 void
147 recursive_timed_mutex::lock()
149 __thread_id id = this_thread::get_id();
150 unique_lock<mutex> lk(__m_);
151 if (id ==__id_)
153 if (__count_ == numeric_limits<size_t>::max())
154 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
155 ++__count_;
156 return;
158 while (__count_ != 0)
159 __cv_.wait(lk);
160 __count_ = 1;
161 __id_ = id;
164 bool
165 recursive_timed_mutex::try_lock() noexcept
167 __thread_id id = this_thread::get_id();
168 unique_lock<mutex> lk(__m_, try_to_lock);
169 if (lk.owns_lock() && (__count_ == 0 || id == __id_))
171 if (__count_ == numeric_limits<size_t>::max())
172 return false;
173 ++__count_;
174 __id_ = id;
175 return true;
177 return false;
180 void
181 recursive_timed_mutex::unlock() noexcept
183 unique_lock<mutex> lk(__m_);
184 if (--__count_ == 0)
186 __id_.__reset();
187 lk.unlock();
188 __cv_.notify_one();
192 #endif // !_LIBCPP_HAS_NO_THREADS
194 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
195 // without illegal macros (unexpected macros not beginning with _UpperCase or
196 // __lowercase), and if it stops spinning waiting threads, then call_once should
197 // call into dispatch_once_f instead of here. Relevant radar this code needs to
198 // keep in sync with: 7741191.
200 #ifndef _LIBCPP_HAS_NO_THREADS
201 static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
202 static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
203 #endif
205 void __call_once(volatile once_flag::_State_type& flag, void* arg,
206 void (*func)(void*))
208 #if defined(_LIBCPP_HAS_NO_THREADS)
210 if (flag == once_flag::_Unset) {
211 auto guard = std::__make_exception_guard([&flag] { flag = once_flag::_Unset; });
212 flag = once_flag::_Pending;
213 func(arg);
214 flag = once_flag::_Complete;
215 guard.__complete();
218 #else // !_LIBCPP_HAS_NO_THREADS
220 __libcpp_mutex_lock(&mut);
221 while (flag == once_flag::_Pending)
222 __libcpp_condvar_wait(&cv, &mut);
223 if (flag == once_flag::_Unset) {
224 auto guard = std::__make_exception_guard([&flag] {
225 __libcpp_mutex_lock(&mut);
226 __libcpp_relaxed_store(&flag, once_flag::_Unset);
227 __libcpp_mutex_unlock(&mut);
228 __libcpp_condvar_broadcast(&cv);
231 __libcpp_relaxed_store(&flag, once_flag::_Pending);
232 __libcpp_mutex_unlock(&mut);
233 func(arg);
234 __libcpp_mutex_lock(&mut);
235 __libcpp_atomic_store(&flag, once_flag::_Complete, _AO_Release);
236 __libcpp_mutex_unlock(&mut);
237 __libcpp_condvar_broadcast(&cv);
238 guard.__complete();
239 } else {
240 __libcpp_mutex_unlock(&mut);
243 #endif // !_LIBCPP_HAS_NO_THREADS
246 _LIBCPP_END_NAMESPACE_STD
248 _LIBCPP_POP_MACROS