1 | //===------------------------- thread.cpp----------------------------------===// |
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 | #include "__config" |
10 | #ifndef _LIBCPP_HAS_NO_THREADS |
11 | |
12 | #include "thread" |
13 | #include "exception" |
14 | #include "vector" |
15 | #include "future" |
16 | #include "limits" |
17 | #include <sys/types.h> |
18 | |
19 | #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) |
20 | # include <sys/param.h> |
21 | # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) |
22 | # include <sys/sysctl.h> |
23 | # endif |
24 | #endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) |
25 | |
26 | #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__) |
27 | # include <unistd.h> |
28 | #endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__) |
29 | |
30 | #if defined(__NetBSD__) |
31 | #pragma weak pthread_create // Do not create libpthread dependency |
32 | #endif |
33 | |
34 | #if defined(_LIBCPP_WIN32API) |
35 | #include <windows.h> |
36 | #endif |
37 | |
38 | #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) |
39 | #pragma comment(lib, "pthread") |
40 | #endif |
41 | |
42 | _LIBCPP_BEGIN_NAMESPACE_STD |
43 | |
44 | thread::~thread() |
45 | { |
46 | if (!__libcpp_thread_isnull(&__t_)) |
47 | terminate(); |
48 | } |
49 | |
50 | void |
51 | thread::join() |
52 | { |
53 | int ec = EINVAL; |
54 | if (!__libcpp_thread_isnull(&__t_)) |
55 | { |
56 | ec = __libcpp_thread_join(&__t_); |
57 | if (ec == 0) |
58 | __t_ = _LIBCPP_NULL_THREAD; |
59 | } |
60 | |
61 | if (ec) |
62 | __throw_system_error(ec, "thread::join failed" ); |
63 | } |
64 | |
65 | void |
66 | thread::detach() |
67 | { |
68 | int ec = EINVAL; |
69 | if (!__libcpp_thread_isnull(&__t_)) |
70 | { |
71 | ec = __libcpp_thread_detach(&__t_); |
72 | if (ec == 0) |
73 | __t_ = _LIBCPP_NULL_THREAD; |
74 | } |
75 | |
76 | if (ec) |
77 | __throw_system_error(ec, "thread::detach failed" ); |
78 | } |
79 | |
80 | unsigned |
81 | thread::hardware_concurrency() _NOEXCEPT |
82 | { |
83 | #if defined(CTL_HW) && defined(HW_NCPU) |
84 | unsigned n; |
85 | int mib[2] = {CTL_HW, HW_NCPU}; |
86 | std::size_t s = sizeof(n); |
87 | sysctl(mib, 2, &n, &s, 0, 0); |
88 | return n; |
89 | #elif defined(_SC_NPROCESSORS_ONLN) |
90 | long result = sysconf(_SC_NPROCESSORS_ONLN); |
91 | // sysconf returns -1 if the name is invalid, the option does not exist or |
92 | // does not have a definite limit. |
93 | // if sysconf returns some other negative number, we have no idea |
94 | // what is going on. Default to something safe. |
95 | if (result < 0) |
96 | return 0; |
97 | return static_cast<unsigned>(result); |
98 | #elif defined(_LIBCPP_WIN32API) |
99 | SYSTEM_INFO info; |
100 | GetSystemInfo(&info); |
101 | return info.dwNumberOfProcessors; |
102 | #else // defined(CTL_HW) && defined(HW_NCPU) |
103 | // TODO: grovel through /proc or check cpuid on x86 and similar |
104 | // instructions on other architectures. |
105 | # if defined(_LIBCPP_WARNING) |
106 | _LIBCPP_WARNING("hardware_concurrency not yet implemented" ) |
107 | # else |
108 | # warning hardware_concurrency not yet implemented |
109 | # endif |
110 | return 0; // Means not computable [thread.thread.static] |
111 | #endif // defined(CTL_HW) && defined(HW_NCPU) |
112 | } |
113 | |
114 | namespace this_thread |
115 | { |
116 | |
117 | void |
118 | sleep_for(const chrono::nanoseconds& ns) |
119 | { |
120 | if (ns > chrono::nanoseconds::zero()) |
121 | { |
122 | __libcpp_thread_sleep_for(ns); |
123 | } |
124 | } |
125 | |
126 | } // this_thread |
127 | |
128 | __thread_specific_ptr<__thread_struct>& |
129 | __thread_local_data() |
130 | { |
131 | static __thread_specific_ptr<__thread_struct> __p; |
132 | return __p; |
133 | } |
134 | |
135 | // __thread_struct_imp |
136 | |
137 | template <class T> |
138 | class _LIBCPP_HIDDEN __hidden_allocator |
139 | { |
140 | public: |
141 | typedef T value_type; |
142 | |
143 | T* allocate(size_t __n) |
144 | {return static_cast<T*>(::operator new(__n * sizeof(T)));} |
145 | void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));} |
146 | |
147 | size_t max_size() const {return size_t(~0) / sizeof(T);} |
148 | }; |
149 | |
150 | class _LIBCPP_HIDDEN __thread_struct_imp |
151 | { |
152 | typedef vector<__assoc_sub_state*, |
153 | __hidden_allocator<__assoc_sub_state*> > _AsyncStates; |
154 | typedef vector<pair<condition_variable*, mutex*>, |
155 | __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify; |
156 | |
157 | _AsyncStates async_states_; |
158 | _Notify notify_; |
159 | |
160 | __thread_struct_imp(const __thread_struct_imp&); |
161 | __thread_struct_imp& operator=(const __thread_struct_imp&); |
162 | public: |
163 | __thread_struct_imp() {} |
164 | ~__thread_struct_imp(); |
165 | |
166 | void notify_all_at_thread_exit(condition_variable* cv, mutex* m); |
167 | void __make_ready_at_thread_exit(__assoc_sub_state* __s); |
168 | }; |
169 | |
170 | __thread_struct_imp::~__thread_struct_imp() |
171 | { |
172 | for (_Notify::iterator i = notify_.begin(), e = notify_.end(); |
173 | i != e; ++i) |
174 | { |
175 | i->second->unlock(); |
176 | i->first->notify_all(); |
177 | } |
178 | for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end(); |
179 | i != e; ++i) |
180 | { |
181 | (*i)->__make_ready(); |
182 | (*i)->__release_shared(); |
183 | } |
184 | } |
185 | |
186 | void |
187 | __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m) |
188 | { |
189 | notify_.push_back(pair<condition_variable*, mutex*>(cv, m)); |
190 | } |
191 | |
192 | void |
193 | __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s) |
194 | { |
195 | async_states_.push_back(__s); |
196 | __s->__add_shared(); |
197 | } |
198 | |
199 | // __thread_struct |
200 | |
201 | __thread_struct::__thread_struct() |
202 | : __p_(new __thread_struct_imp) |
203 | { |
204 | } |
205 | |
206 | __thread_struct::~__thread_struct() |
207 | { |
208 | delete __p_; |
209 | } |
210 | |
211 | void |
212 | __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m) |
213 | { |
214 | __p_->notify_all_at_thread_exit(cv, m); |
215 | } |
216 | |
217 | void |
218 | __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) |
219 | { |
220 | __p_->__make_ready_at_thread_exit(__s); |
221 | } |
222 | |
223 | _LIBCPP_END_NAMESPACE_STD |
224 | |
225 | #endif // !_LIBCPP_HAS_NO_THREADS |
226 | |