1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
12 #include <system_error>
14 #include "include/atomic_support.h"
16 #ifndef _LIBCPP_HAS_NO_THREADS
17 # if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
18 # pragma comment(lib, "pthread")
23 #include <__undef_macros>
25 _LIBCPP_BEGIN_NAMESPACE_STD
27 #ifndef _LIBCPP_HAS_NO_THREADS
29 const defer_lock_t defer_lock
{};
30 const try_to_lock_t try_to_lock
{};
31 const adopt_lock_t adopt_lock
{};
33 // ~mutex is defined elsewhere
38 int ec
= __libcpp_mutex_lock(&__m_
);
40 __throw_system_error(ec
, "mutex lock failed");
44 mutex::try_lock() noexcept
46 return __libcpp_mutex_trylock(&__m_
);
50 mutex::unlock() noexcept
52 int ec
= __libcpp_mutex_unlock(&__m_
);
54 _LIBCPP_ASSERT(ec
== 0, "call to mutex::unlock failed");
59 recursive_mutex::recursive_mutex()
61 int ec
= __libcpp_recursive_mutex_init(&__m_
);
63 __throw_system_error(ec
, "recursive_mutex constructor failed");
66 recursive_mutex::~recursive_mutex()
68 int e
= __libcpp_recursive_mutex_destroy(&__m_
);
70 _LIBCPP_ASSERT(e
== 0, "call to ~recursive_mutex() failed");
74 recursive_mutex::lock()
76 int ec
= __libcpp_recursive_mutex_lock(&__m_
);
78 __throw_system_error(ec
, "recursive_mutex lock failed");
82 recursive_mutex::unlock() noexcept
84 int e
= __libcpp_recursive_mutex_unlock(&__m_
);
86 _LIBCPP_ASSERT(e
== 0, "call to recursive_mutex::unlock() failed");
90 recursive_mutex::try_lock() noexcept
92 return __libcpp_recursive_mutex_trylock(&__m_
);
97 timed_mutex::timed_mutex()
102 timed_mutex::~timed_mutex()
104 lock_guard
<mutex
> _(__m_
);
110 unique_lock
<mutex
> lk(__m_
);
117 timed_mutex::try_lock() noexcept
119 unique_lock
<mutex
> lk(__m_
, try_to_lock
);
120 if (lk
.owns_lock() && !__locked_
)
129 timed_mutex::unlock() noexcept
131 lock_guard
<mutex
> _(__m_
);
136 // recursive_timed_mutex
138 recursive_timed_mutex::recursive_timed_mutex()
144 recursive_timed_mutex::~recursive_timed_mutex()
146 lock_guard
<mutex
> _(__m_
);
150 recursive_timed_mutex::lock()
152 __thread_id id
= this_thread::get_id();
153 unique_lock
<mutex
> lk(__m_
);
156 if (__count_
== numeric_limits
<size_t>::max())
157 __throw_system_error(EAGAIN
, "recursive_timed_mutex lock limit reached");
161 while (__count_
!= 0)
168 recursive_timed_mutex::try_lock() noexcept
170 __thread_id id
= this_thread::get_id();
171 unique_lock
<mutex
> lk(__m_
, try_to_lock
);
172 if (lk
.owns_lock() && (__count_
== 0 || id
== __id_
))
174 if (__count_
== numeric_limits
<size_t>::max())
184 recursive_timed_mutex::unlock() noexcept
186 unique_lock
<mutex
> lk(__m_
);
195 #endif // !_LIBCPP_HAS_NO_THREADS
197 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
198 // without illegal macros (unexpected macros not beginning with _UpperCase or
199 // __lowercase), and if it stops spinning waiting threads, then call_once should
200 // call into dispatch_once_f instead of here. Relevant radar this code needs to
201 // keep in sync with: 7741191.
203 #ifndef _LIBCPP_HAS_NO_THREADS
204 static constinit __libcpp_mutex_t mut
= _LIBCPP_MUTEX_INITIALIZER
;
205 static constinit __libcpp_condvar_t cv
= _LIBCPP_CONDVAR_INITIALIZER
;
208 void __call_once(volatile once_flag::_State_type
& flag
, void* arg
,
211 #if defined(_LIBCPP_HAS_NO_THREADS)
214 #ifndef _LIBCPP_NO_EXCEPTIONS
217 #endif // _LIBCPP_NO_EXCEPTIONS
220 flag
= ~once_flag::_State_type(0);
221 #ifndef _LIBCPP_NO_EXCEPTIONS
228 #endif // _LIBCPP_NO_EXCEPTIONS
230 #else // !_LIBCPP_HAS_NO_THREADS
231 __libcpp_mutex_lock(&mut
);
233 __libcpp_condvar_wait(&cv
, &mut
);
236 #ifndef _LIBCPP_NO_EXCEPTIONS
239 #endif // _LIBCPP_NO_EXCEPTIONS
240 __libcpp_relaxed_store(&flag
, once_flag::_State_type(1));
241 __libcpp_mutex_unlock(&mut
);
243 __libcpp_mutex_lock(&mut
);
244 __libcpp_atomic_store(&flag
, ~once_flag::_State_type(0),
246 __libcpp_mutex_unlock(&mut
);
247 __libcpp_condvar_broadcast(&cv
);
248 #ifndef _LIBCPP_NO_EXCEPTIONS
252 __libcpp_mutex_lock(&mut
);
253 __libcpp_relaxed_store(&flag
, once_flag::_State_type(0));
254 __libcpp_mutex_unlock(&mut
);
255 __libcpp_condvar_broadcast(&cv
);
258 #endif // _LIBCPP_NO_EXCEPTIONS
261 __libcpp_mutex_unlock(&mut
);
262 #endif // !_LIBCPP_HAS_NO_THREADS
265 _LIBCPP_END_NAMESPACE_STD