1 //===------------------------- thread.cpp----------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include <__thread/poll_with_backoff.h>
10 #include <__thread/timed_backoff_policy.h>
17 #if __has_include(<unistd.h>)
18 # include <unistd.h> // for sysconf
21 #if defined(__NetBSD__)
22 # pragma weak pthread_create // Do not create libpthread dependency
25 #if defined(_LIBCPP_WIN32API)
29 #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
30 # pragma comment(lib, "pthread")
33 _LIBCPP_BEGIN_NAMESPACE_STD
36 if (!__libcpp_thread_isnull(&__t_
))
42 if (!__libcpp_thread_isnull(&__t_
)) {
43 ec
= __libcpp_thread_join(&__t_
);
45 __t_
= _LIBCPP_NULL_THREAD
;
49 __throw_system_error(ec
, "thread::join failed");
52 void thread::detach() {
54 if (!__libcpp_thread_isnull(&__t_
)) {
55 ec
= __libcpp_thread_detach(&__t_
);
57 __t_
= _LIBCPP_NULL_THREAD
;
61 __throw_system_error(ec
, "thread::detach failed");
64 unsigned thread::hardware_concurrency() noexcept
{
65 #if defined(_SC_NPROCESSORS_ONLN)
66 long result
= sysconf(_SC_NPROCESSORS_ONLN
);
67 // sysconf returns -1 if the name is invalid, the option does not exist or
68 // does not have a definite limit.
69 // if sysconf returns some other negative number, we have no idea
70 // what is going on. Default to something safe.
73 return static_cast<unsigned>(result
);
74 #elif defined(_LIBCPP_WIN32API)
77 return info
.dwNumberOfProcessors
;
78 #else // defined(CTL_HW) && defined(HW_NCPU)
79 // TODO: grovel through /proc or check cpuid on x86 and similar
80 // instructions on other architectures.
81 # if defined(_LIBCPP_WARNING)
82 _LIBCPP_WARNING("hardware_concurrency not yet implemented")
84 # warning hardware_concurrency not yet implemented
86 return 0; // Means not computable [thread.thread.static]
87 #endif // defined(CTL_HW) && defined(HW_NCPU)
90 namespace this_thread
{
92 void sleep_for(const chrono::nanoseconds
& ns
) {
93 if (ns
> chrono::nanoseconds::zero()) {
94 __libcpp_thread_sleep_for(ns
);
98 } // namespace this_thread
100 __thread_specific_ptr
<__thread_struct
>& __thread_local_data() {
101 // Even though __thread_specific_ptr's destructor doesn't actually destroy
102 // anything (see comments there), we can't call it at all because threads may
103 // outlive the static variable and calling its destructor means accessing an
104 // object outside of its lifetime, which is UB.
105 alignas(__thread_specific_ptr
<__thread_struct
>) static char __b
[sizeof(__thread_specific_ptr
<__thread_struct
>)];
106 static __thread_specific_ptr
<__thread_struct
>* __p
= new (__b
) __thread_specific_ptr
<__thread_struct
>();
110 // __thread_struct_imp
113 class _LIBCPP_HIDDEN __hidden_allocator
{
115 typedef T value_type
;
117 T
* allocate(size_t __n
) { return static_cast<T
*>(::operator new(__n
* sizeof(T
))); }
118 void deallocate(T
* __p
, size_t) { ::operator delete(static_cast<void*>(__p
)); }
120 size_t max_size() const { return size_t(~0) / sizeof(T
); }
123 class _LIBCPP_HIDDEN __thread_struct_imp
{
124 typedef vector
<__assoc_sub_state
*, __hidden_allocator
<__assoc_sub_state
*> > _AsyncStates
;
125 typedef vector
<pair
<condition_variable
*, mutex
*>, __hidden_allocator
<pair
<condition_variable
*, mutex
*> > > _Notify
;
127 _AsyncStates async_states_
;
130 __thread_struct_imp(const __thread_struct_imp
&);
131 __thread_struct_imp
& operator=(const __thread_struct_imp
&);
134 __thread_struct_imp() {}
135 ~__thread_struct_imp();
137 void notify_all_at_thread_exit(condition_variable
* cv
, mutex
* m
);
138 void __make_ready_at_thread_exit(__assoc_sub_state
* __s
);
141 __thread_struct_imp::~__thread_struct_imp() {
142 for (_Notify::iterator i
= notify_
.begin(), e
= notify_
.end(); i
!= e
; ++i
) {
143 i
->first
->notify_all();
146 for (_AsyncStates::iterator i
= async_states_
.begin(), e
= async_states_
.end(); i
!= e
; ++i
) {
147 (*i
)->__make_ready();
148 (*i
)->__release_shared();
152 void __thread_struct_imp::notify_all_at_thread_exit(condition_variable
* cv
, mutex
* m
) {
153 notify_
.push_back(pair
<condition_variable
*, mutex
*>(cv
, m
));
156 void __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state
* __s
) {
157 async_states_
.push_back(__s
);
163 __thread_struct::__thread_struct() : __p_(new __thread_struct_imp
) {}
165 __thread_struct::~__thread_struct() { delete __p_
; }
167 void __thread_struct::notify_all_at_thread_exit(condition_variable
* cv
, mutex
* m
) {
168 __p_
->notify_all_at_thread_exit(cv
, m
);
171 void __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state
* __s
) { __p_
->__make_ready_at_thread_exit(__s
); }
173 _LIBCPP_END_NAMESPACE_STD