Skip to content

Commit e655d8a

Browse files
committed
[libc++] Granularize __mutex_base
This also updates the moved code to the current style. (i.e. `_VSTD` -> `std`, `_LIBCPP_INLINE_VISIBILITY` -> `_LIBCPP_HIDE_FROM_ABI`, clang-format). Reviewed By: Mordante, #libc, EricWF Spies: arichardson, libcxx-commits, mikhail.ramalho Differential Revision: https://reviews.llvm.org/D146228
1 parent 6afcc54 commit e655d8a

File tree

59 files changed

+757
-73
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+757
-73
lines changed

libcxx/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ Deprecations and Removals
6262
includes are removed based on the language version used. Incidental transitive
6363
inclusions of the following headers have been removed:
6464

65-
- C++2b: ``atomic``, ``bit``, ``cstring``, ``type_traits``
65+
- C++2b: ``atomic``, ``bit``, ``cstdint``, ``cstdlib``, ``cstring``, ``initializer_list``, ``new``, ``stdexcept``,
66+
``type_traits``, ``typeinfo``
6667

6768
- The headers ``<experimental/algorithm>`` and ``<experimental/functional>`` have been removed, since all the contents
6869
have been implemented in namespace ``std`` for at least two releases.

libcxx/include/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ set(files
294294
__concepts/semiregular.h
295295
__concepts/swappable.h
296296
__concepts/totally_ordered.h
297+
__condition_variable/condition_variable.h
297298
__config
298299
__coroutine/coroutine_handle.h
299300
__coroutine/coroutine_traits.h
@@ -474,7 +475,10 @@ set(files
474475
__memory_resource/pool_options.h
475476
__memory_resource/synchronized_pool_resource.h
476477
__memory_resource/unsynchronized_pool_resource.h
477-
__mutex_base
478+
__mutex/lock_guard.h
479+
__mutex/mutex.h
480+
__mutex/tag_types.h
481+
__mutex/unique_lock.h
478482
__node_handle
479483
__numeric/accumulate.h
480484
__numeric/adjacent_difference.h
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
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+
#ifndef _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
10+
#define _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
11+
12+
#include <__chrono/steady_clock.h>
13+
#include <__chrono/system_clock.h>
14+
#include <__chrono/time_point.h>
15+
#include <__config>
16+
#include <__mutex/mutex.h>
17+
#include <__mutex/unique_lock.h>
18+
#include <__threading_support>
19+
#include <__type_traits/enable_if.h>
20+
#include <__type_traits/is_floating_point.h>
21+
#include <__utility/move.h>
22+
#include <ratio>
23+
#include <system_error>
24+
25+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26+
# pragma GCC system_header
27+
#endif
28+
29+
_LIBCPP_PUSH_MACROS
30+
#include <__undef_macros>
31+
32+
#ifndef _LIBCPP_HAS_NO_THREADS
33+
34+
_LIBCPP_BEGIN_NAMESPACE_STD
35+
36+
// enum class cv_status
37+
_LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout};
38+
_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status)
39+
40+
class _LIBCPP_TYPE_VIS condition_variable {
41+
__libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
42+
43+
public:
44+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default;
45+
46+
# ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
47+
~condition_variable() = default;
48+
# else
49+
~condition_variable();
50+
# endif
51+
52+
condition_variable(const condition_variable&) = delete;
53+
condition_variable& operator=(const condition_variable&) = delete;
54+
55+
void notify_one() _NOEXCEPT;
56+
void notify_all() _NOEXCEPT;
57+
58+
void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
59+
template <class _Predicate>
60+
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock<mutex>& __lk, _Predicate __pred);
61+
62+
template <class _Clock, class _Duration>
63+
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
64+
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t);
65+
66+
template <class _Clock, class _Duration, class _Predicate>
67+
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
68+
wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred);
69+
70+
template <class _Rep, class _Period>
71+
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status
72+
wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d);
73+
74+
template <class _Rep, class _Period, class _Predicate>
75+
bool _LIBCPP_HIDE_FROM_ABI
76+
wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred);
77+
78+
typedef __libcpp_condvar_t* native_handle_type;
79+
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; }
80+
81+
private:
82+
void
83+
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
84+
# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
85+
void
86+
__do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds>) _NOEXCEPT;
87+
# endif
88+
template <class _Clock>
89+
void __do_timed_wait(unique_lock<mutex>& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT;
90+
};
91+
#endif // !_LIBCPP_HAS_NO_THREADS
92+
93+
template <class _Rep, class _Period>
94+
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<is_floating_point<_Rep>::value, chrono::nanoseconds>
95+
__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
96+
using namespace chrono;
97+
using __ratio = ratio_divide<_Period, nano>;
98+
using __ns_rep = nanoseconds::rep;
99+
_Rep __result_float = __d.count() * __ratio::num / __ratio::den;
100+
101+
_Rep __result_max = numeric_limits<__ns_rep>::max();
102+
if (__result_float >= __result_max) {
103+
return nanoseconds::max();
104+
}
105+
106+
_Rep __result_min = numeric_limits<__ns_rep>::min();
107+
if (__result_float <= __result_min) {
108+
return nanoseconds::min();
109+
}
110+
111+
return nanoseconds(static_cast<__ns_rep>(__result_float));
112+
}
113+
114+
template <class _Rep, class _Period>
115+
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!is_floating_point<_Rep>::value, chrono::nanoseconds>
116+
__safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) {
117+
using namespace chrono;
118+
if (__d.count() == 0) {
119+
return nanoseconds(0);
120+
}
121+
122+
using __ratio = ratio_divide<_Period, nano>;
123+
using __ns_rep = nanoseconds::rep;
124+
__ns_rep __result_max = numeric_limits<__ns_rep>::max();
125+
if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) {
126+
return nanoseconds::max();
127+
}
128+
129+
__ns_rep __result_min = numeric_limits<__ns_rep>::min();
130+
if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) {
131+
return nanoseconds::min();
132+
}
133+
134+
__ns_rep __result = __d.count() * __ratio::num / __ratio::den;
135+
if (__result == 0) {
136+
return nanoseconds(1);
137+
}
138+
139+
return nanoseconds(__result);
140+
}
141+
142+
#ifndef _LIBCPP_HAS_NO_THREADS
143+
template <class _Predicate>
144+
void condition_variable::wait(unique_lock<mutex>& __lk, _Predicate __pred) {
145+
while (!__pred())
146+
wait(__lk);
147+
}
148+
149+
template <class _Clock, class _Duration>
150+
cv_status condition_variable::wait_until(unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t) {
151+
using namespace chrono;
152+
using __clock_tp_ns = time_point<_Clock, nanoseconds>;
153+
154+
typename _Clock::time_point __now = _Clock::now();
155+
if (__t <= __now)
156+
return cv_status::timeout;
157+
158+
__clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch()));
159+
160+
__do_timed_wait(__lk, __t_ns);
161+
return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
162+
}
163+
164+
template <class _Clock, class _Duration, class _Predicate>
165+
bool condition_variable::wait_until(
166+
unique_lock<mutex>& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) {
167+
while (!__pred()) {
168+
if (wait_until(__lk, __t) == cv_status::timeout)
169+
return __pred();
170+
}
171+
return true;
172+
}
173+
174+
template <class _Rep, class _Period>
175+
cv_status condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d) {
176+
using namespace chrono;
177+
if (__d <= __d.zero())
178+
return cv_status::timeout;
179+
using __ns_rep = nanoseconds::rep;
180+
steady_clock::time_point __c_now = steady_clock::now();
181+
182+
# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
183+
using __clock_tp_ns = time_point<steady_clock, nanoseconds>;
184+
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count();
185+
# else
186+
using __clock_tp_ns = time_point<system_clock, nanoseconds>;
187+
__ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count();
188+
# endif
189+
190+
__ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count();
191+
192+
if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) {
193+
__do_timed_wait(__lk, __clock_tp_ns::max());
194+
} else {
195+
__do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count)));
196+
}
197+
198+
return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout;
199+
}
200+
201+
template <class _Rep, class _Period, class _Predicate>
202+
inline bool
203+
condition_variable::wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) {
204+
return wait_until(__lk, chrono::steady_clock::now() + __d, std::move(__pred));
205+
}
206+
207+
# if defined(_LIBCPP_HAS_COND_CLOCKWAIT)
208+
inline void condition_variable::__do_timed_wait(
209+
unique_lock<mutex>& __lk, chrono::time_point<chrono::steady_clock, chrono::nanoseconds> __tp) _NOEXCEPT {
210+
using namespace chrono;
211+
if (!__lk.owns_lock())
212+
__throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked");
213+
nanoseconds __d = __tp.time_since_epoch();
214+
timespec __ts;
215+
seconds __s = duration_cast<seconds>(__d);
216+
using __ts_sec = decltype(__ts.tv_sec);
217+
const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max();
218+
if (__s.count() < __ts_sec_max) {
219+
__ts.tv_sec = static_cast<__ts_sec>(__s.count());
220+
__ts.tv_nsec = (__d - __s).count();
221+
} else {
222+
__ts.tv_sec = __ts_sec_max;
223+
__ts.tv_nsec = giga::num - 1;
224+
}
225+
int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts);
226+
if (__ec != 0 && __ec != ETIMEDOUT)
227+
__throw_system_error(__ec, "condition_variable timed_wait failed");
228+
}
229+
# endif // _LIBCPP_HAS_COND_CLOCKWAIT
230+
231+
template <class _Clock>
232+
inline void condition_variable::__do_timed_wait(unique_lock<mutex>& __lk,
233+
chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT {
234+
wait_for(__lk, __tp - _Clock::now());
235+
}
236+
237+
_LIBCPP_END_NAMESPACE_STD
238+
239+
#endif // _LIBCPP_HAS_NO_THREADS
240+
241+
_LIBCPP_POP_MACROS
242+
243+
#endif // _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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+
#ifndef _LIBCPP___MUTEX_LOCK_GUARD_H
10+
#define _LIBCPP___MUTEX_LOCK_GUARD_H
11+
12+
#include <__config>
13+
#include <__mutex/tag_types.h>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
#ifndef _LIBCPP_HAS_NO_THREADS
20+
21+
_LIBCPP_BEGIN_NAMESPACE_STD
22+
23+
template <class _Mutex>
24+
class _LIBCPP_TEMPLATE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) lock_guard {
25+
public:
26+
typedef _Mutex mutex_type;
27+
28+
private:
29+
mutex_type& __m_;
30+
31+
public:
32+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI explicit lock_guard(mutex_type& __m)
33+
_LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
34+
: __m_(__m) {
35+
__m_.lock();
36+
}
37+
38+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI lock_guard(mutex_type& __m, adopt_lock_t)
39+
_LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
40+
: __m_(__m) {}
41+
_LIBCPP_HIDE_FROM_ABI ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { __m_.unlock(); }
42+
43+
private:
44+
lock_guard(lock_guard const&) = delete;
45+
lock_guard& operator=(lock_guard const&) = delete;
46+
};
47+
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(lock_guard);
48+
49+
_LIBCPP_END_NAMESPACE_STD
50+
51+
#endif // _LIBCPP_HAS_NO_THREADS
52+
53+
#endif // _LIBCPP___MUTEX_LOCK_GUARD_H

libcxx/include/__mutex/mutex.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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+
#ifndef _LIBCPP___MUTEX_MUTEX_H
10+
#define _LIBCPP___MUTEX_MUTEX_H
11+
12+
#include <__config>
13+
#include <__threading_support>
14+
#include <__type_traits/is_nothrow_default_constructible.h>
15+
16+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
17+
# pragma GCC system_header
18+
#endif
19+
20+
#ifndef _LIBCPP_HAS_NO_THREADS
21+
22+
_LIBCPP_BEGIN_NAMESPACE_STD
23+
24+
class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex {
25+
__libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
26+
27+
public:
28+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR mutex() = default;
29+
30+
mutex(const mutex&) = delete;
31+
mutex& operator=(const mutex&) = delete;
32+
33+
# if defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
34+
~mutex() = default;
35+
# else
36+
~mutex() _NOEXCEPT;
37+
# endif
38+
39+
void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
40+
bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
41+
void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
42+
43+
typedef __libcpp_mutex_t* native_handle_type;
44+
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; }
45+
};
46+
47+
static_assert(is_nothrow_default_constructible<mutex>::value, "the default constructor for std::mutex must be nothrow");
48+
49+
_LIBCPP_END_NAMESPACE_STD
50+
51+
#endif // _LIBCPP_HAS_NO_THREADS
52+
53+
#endif // _LIBCPP___MUTEX_MUTEX_H

0 commit comments

Comments
 (0)