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