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 //===----------------------------------------------------------------------===//
10 #include <__thread/id.h>
11 #include <__utility/exception_guard.h>
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")
24 #include <__undef_macros>
26 _LIBCPP_BEGIN_NAMESPACE_STD
28 #ifndef _LIBCPP_HAS_NO_THREADS
30 // ~mutex is defined elsewhere
35 int ec
= __libcpp_mutex_lock(&__m_
);
37 __throw_system_error(ec
, "mutex lock failed");
41 mutex::try_lock() noexcept
43 return __libcpp_mutex_trylock(&__m_
);
47 mutex::unlock() noexcept
49 int ec
= __libcpp_mutex_unlock(&__m_
);
51 _LIBCPP_ASSERT_UNCATEGORIZED(ec
== 0, "call to mutex::unlock failed");
56 recursive_mutex::recursive_mutex()
58 int ec
= __libcpp_recursive_mutex_init(&__m_
);
60 __throw_system_error(ec
, "recursive_mutex constructor failed");
63 recursive_mutex::~recursive_mutex()
65 int e
= __libcpp_recursive_mutex_destroy(&__m_
);
67 _LIBCPP_ASSERT_UNCATEGORIZED(e
== 0, "call to ~recursive_mutex() failed");
71 recursive_mutex::lock()
73 int ec
= __libcpp_recursive_mutex_lock(&__m_
);
75 __throw_system_error(ec
, "recursive_mutex lock failed");
79 recursive_mutex::unlock() noexcept
81 int e
= __libcpp_recursive_mutex_unlock(&__m_
);
83 _LIBCPP_ASSERT_UNCATEGORIZED(e
== 0, "call to recursive_mutex::unlock() failed");
87 recursive_mutex::try_lock() noexcept
89 return __libcpp_recursive_mutex_trylock(&__m_
);
94 timed_mutex::timed_mutex()
99 timed_mutex::~timed_mutex()
101 lock_guard
<mutex
> _(__m_
);
107 unique_lock
<mutex
> lk(__m_
);
114 timed_mutex::try_lock() noexcept
116 unique_lock
<mutex
> lk(__m_
, try_to_lock
);
117 if (lk
.owns_lock() && !__locked_
)
126 timed_mutex::unlock() noexcept
128 lock_guard
<mutex
> _(__m_
);
133 // recursive_timed_mutex
135 recursive_timed_mutex::recursive_timed_mutex()
141 recursive_timed_mutex::~recursive_timed_mutex()
143 lock_guard
<mutex
> _(__m_
);
147 recursive_timed_mutex::lock()
149 __thread_id id
= this_thread::get_id();
150 unique_lock
<mutex
> lk(__m_
);
153 if (__count_
== numeric_limits
<size_t>::max())
154 __throw_system_error(EAGAIN
, "recursive_timed_mutex lock limit reached");
158 while (__count_
!= 0)
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())
181 recursive_timed_mutex::unlock() noexcept
183 unique_lock
<mutex
> lk(__m_
);
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
;
205 void __call_once(volatile once_flag::_State_type
& flag
, void* arg
,
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
;
214 flag
= once_flag::_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
);
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
);
240 __libcpp_mutex_unlock(&mut
);
243 #endif // !_LIBCPP_HAS_NO_THREADS
246 _LIBCPP_END_NAMESPACE_STD