]>
Commit | Line | Data |
---|---|---|
46e113bf CF |
1 | // <thread> -*- C++ -*- |
2 | ||
85ec4feb | 3 | // Copyright (C) 2008-2018 Free Software Foundation, Inc. |
46e113bf CF |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
748086b7 | 8 | // Free Software Foundation; either version 3, or (at your option) |
46e113bf CF |
9 | // any later version. |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
748086b7 JJ |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
46e113bf | 24 | |
f910786b | 25 | /** @file include/thread |
46e113bf CF |
26 | * This is a Standard C++ Library header. |
27 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_THREAD | |
30 | #define _GLIBCXX_THREAD 1 | |
31 | ||
32 | #pragma GCC system_header | |
33 | ||
734f5023 | 34 | #if __cplusplus < 201103L |
ab65a4c7 | 35 | # include <bits/c++0x_warning.h> |
46e113bf CF |
36 | #else |
37 | ||
38 | #include <chrono> | |
46e113bf | 39 | #include <memory> |
5579170b | 40 | #include <tuple> |
f022ab03 | 41 | #include <cerrno> |
46e113bf | 42 | #include <bits/functexcept.h> |
5c8db18a | 43 | #include <bits/functional_hash.h> |
5579170b | 44 | #include <bits/invoke.h> |
46e113bf CF |
45 | #include <bits/gthr.h> |
46 | ||
47 | #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) | |
48 | ||
12ffa228 BK |
49 | namespace std _GLIBCXX_VISIBILITY(default) |
50 | { | |
51 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
53dc5044 | 52 | |
5b9daa7e BK |
53 | /** |
54 | * @defgroup threads Threads | |
55 | * @ingroup concurrency | |
56 | * | |
57 | * Classes for thread support. | |
58 | * @{ | |
59 | */ | |
60 | ||
d7afcd2b | 61 | /// thread |
8644ecf5 | 62 | class thread |
46e113bf CF |
63 | { |
64 | public: | |
ce535a96 JW |
65 | // Abstract base class for types that wrap arbitrary functors to be |
66 | // invoked in the new thread of execution. | |
67 | struct _State | |
68 | { | |
69 | virtual ~_State(); | |
70 | virtual void _M_run() = 0; | |
71 | }; | |
72 | using _State_ptr = unique_ptr<_State>; | |
73 | ||
626dda69 | 74 | typedef __gthread_t native_handle_type; |
d7afcd2b BK |
75 | |
76 | /// thread::id | |
77 | class id | |
46e113bf | 78 | { |
626dda69 | 79 | native_handle_type _M_thread; |
d7afcd2b | 80 | |
46e113bf | 81 | public: |
7f0d79d5 | 82 | id() noexcept : _M_thread() { } |
d7afcd2b BK |
83 | |
84 | explicit | |
85 | id(native_handle_type __id) : _M_thread(__id) { } | |
86 | ||
87 | private: | |
88 | friend class thread; | |
5c8db18a | 89 | friend class hash<thread::id>; |
d7afcd2b BK |
90 | |
91 | friend bool | |
b05cf382 | 92 | operator==(thread::id __x, thread::id __y) noexcept; |
d7afcd2b BK |
93 | |
94 | friend bool | |
b05cf382 | 95 | operator<(thread::id __x, thread::id __y) noexcept; |
d7afcd2b BK |
96 | |
97 | template<class _CharT, class _Traits> | |
98 | friend basic_ostream<_CharT, _Traits>& | |
ff74fd13 | 99 | operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id); |
d7afcd2b BK |
100 | }; |
101 | ||
d7afcd2b | 102 | private: |
626dda69 | 103 | id _M_id; |
d7afcd2b BK |
104 | |
105 | public: | |
7f0d79d5 | 106 | thread() noexcept = default; |
1b5dc776 JW |
107 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
108 | // 2097. packaged_task constructors should be constrained | |
b2edc921 | 109 | thread(thread&) = delete; |
d7afcd2b | 110 | thread(const thread&) = delete; |
80efc507 | 111 | thread(const thread&&) = delete; |
d7afcd2b | 112 | |
7f0d79d5 | 113 | thread(thread&& __t) noexcept |
d7afcd2b BK |
114 | { swap(__t); } |
115 | ||
46e113bf | 116 | template<typename _Callable, typename... _Args> |
33ac58d5 | 117 | explicit |
46e113bf | 118 | thread(_Callable&& __f, _Args&&... __args) |
1b3fad81 | 119 | { |
c6b3f349 | 120 | #ifdef GTHR_ACTIVE_PROXY |
ce535a96 JW |
121 | // Create a reference to pthread_create, not just the gthr weak symbol. |
122 | auto __depend = reinterpret_cast<void(*)()>(&pthread_create); | |
c6b3f349 | 123 | #else |
ce535a96 | 124 | auto __depend = nullptr; |
c6b3f349 | 125 | #endif |
ce535a96 | 126 | _M_start_thread(_S_make_state( |
5579170b JW |
127 | __make_invoker(std::forward<_Callable>(__f), |
128 | std::forward<_Args>(__args)...)), | |
ce535a96 | 129 | __depend); |
1b3fad81 | 130 | } |
46e113bf | 131 | |
959d14e1 | 132 | ~thread() |
cbdab9c8 JW |
133 | { |
134 | if (joinable()) | |
cd3b0faf | 135 | std::terminate(); |
cbdab9c8 | 136 | } |
46e113bf | 137 | |
46e113bf | 138 | thread& operator=(const thread&) = delete; |
d7afcd2b | 139 | |
7f0d79d5 | 140 | thread& operator=(thread&& __t) noexcept |
78b580a9 JW |
141 | { |
142 | if (joinable()) | |
cd3b0faf | 143 | std::terminate(); |
78b580a9 JW |
144 | swap(__t); |
145 | return *this; | |
146 | } | |
46e113bf | 147 | |
d7afcd2b | 148 | void |
7f0d79d5 | 149 | swap(thread& __t) noexcept |
626dda69 | 150 | { std::swap(_M_id, __t._M_id); } |
46e113bf | 151 | |
d7afcd2b | 152 | bool |
7f0d79d5 | 153 | joinable() const noexcept |
626dda69 | 154 | { return !(_M_id == id()); } |
46e113bf | 155 | |
d7afcd2b | 156 | void |
46e113bf CF |
157 | join(); |
158 | ||
d7afcd2b | 159 | void |
46e113bf CF |
160 | detach(); |
161 | ||
959d14e1 | 162 | thread::id |
7f0d79d5 | 163 | get_id() const noexcept |
626dda69 | 164 | { return _M_id; } |
46e113bf | 165 | |
cbdab9c8 JW |
166 | /** @pre thread is joinable |
167 | */ | |
d7afcd2b | 168 | native_handle_type |
46e113bf | 169 | native_handle() |
626dda69 | 170 | { return _M_id._M_thread; } |
46e113bf | 171 | |
d7afcd2b BK |
172 | // Returns a value that hints at the number of hardware thread contexts. |
173 | static unsigned int | |
43653c33 | 174 | hardware_concurrency() noexcept; |
46e113bf | 175 | |
46e113bf | 176 | private: |
ce535a96 JW |
177 | template<typename _Callable> |
178 | struct _State_impl : public _State | |
179 | { | |
180 | _Callable _M_func; | |
181 | ||
182 | _State_impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f)) | |
183 | { } | |
184 | ||
185 | void | |
186 | _M_run() { _M_func(); } | |
187 | }; | |
c6b3f349 | 188 | |
626dda69 | 189 | void |
ce535a96 | 190 | _M_start_thread(_State_ptr, void (*)()); |
626dda69 | 191 | |
46e113bf | 192 | template<typename _Callable> |
ce535a96 JW |
193 | static _State_ptr |
194 | _S_make_state(_Callable&& __f) | |
8644ecf5 | 195 | { |
ce535a96 JW |
196 | using _Impl = _State_impl<_Callable>; |
197 | return _State_ptr{new _Impl{std::forward<_Callable>(__f)}}; | |
46e113bf | 198 | } |
ce535a96 JW |
199 | #if _GLIBCXX_THREAD_ABI_COMPAT |
200 | public: | |
201 | struct _Impl_base; | |
202 | typedef shared_ptr<_Impl_base> __shared_base_type; | |
203 | struct _Impl_base | |
204 | { | |
205 | __shared_base_type _M_this_ptr; | |
206 | virtual ~_Impl_base() = default; | |
207 | virtual void _M_run() = 0; | |
208 | }; | |
46e113bf | 209 | |
ce535a96 JW |
210 | private: |
211 | void | |
212 | _M_start_thread(__shared_base_type, void (*)()); | |
213 | ||
214 | void | |
215 | _M_start_thread(__shared_base_type); | |
216 | #endif | |
5579170b JW |
217 | |
218 | private: | |
219 | // A call wrapper that does INVOKE(forwarded tuple elements...) | |
220 | template<typename _Tuple> | |
221 | struct _Invoker | |
222 | { | |
223 | _Tuple _M_t; | |
224 | ||
225 | template<size_t _Index> | |
226 | static __tuple_element_t<_Index, _Tuple>&& | |
227 | _S_declval(); | |
228 | ||
229 | template<size_t... _Ind> | |
230 | auto | |
231 | _M_invoke(_Index_tuple<_Ind...>) | |
232 | noexcept(noexcept(std::__invoke(_S_declval<_Ind>()...))) | |
233 | -> decltype(std::__invoke(_S_declval<_Ind>()...)) | |
234 | { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); } | |
235 | ||
236 | using _Indices | |
237 | = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type; | |
238 | ||
a2284544 | 239 | auto |
5579170b | 240 | operator()() |
a2284544 JW |
241 | noexcept(noexcept(std::declval<_Invoker&>()._M_invoke(_Indices()))) |
242 | -> decltype(std::declval<_Invoker&>()._M_invoke(_Indices())) | |
5579170b | 243 | { return _M_invoke(_Indices()); } |
5579170b JW |
244 | }; |
245 | ||
5579170b | 246 | template<typename... _Tp> |
cc535146 | 247 | using __decayed_tuple = tuple<typename std::decay<_Tp>::type...>; |
5579170b JW |
248 | |
249 | public: | |
cc535146 JW |
250 | // Returns a call wrapper that stores |
251 | // tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}. | |
5579170b | 252 | template<typename _Callable, typename... _Args> |
cc535146 | 253 | static _Invoker<__decayed_tuple<_Callable, _Args...>> |
5579170b JW |
254 | __make_invoker(_Callable&& __callable, _Args&&... __args) |
255 | { | |
cc535146 JW |
256 | return { __decayed_tuple<_Callable, _Args...>{ |
257 | std::forward<_Callable>(__callable), std::forward<_Args>(__args)... | |
5579170b JW |
258 | } }; |
259 | } | |
ce535a96 | 260 | }; |
d5545744 | 261 | |
46e113bf | 262 | inline void |
7f0d79d5 | 263 | swap(thread& __x, thread& __y) noexcept |
46e113bf CF |
264 | { __x.swap(__y); } |
265 | ||
b05cf382 JW |
266 | inline bool |
267 | operator==(thread::id __x, thread::id __y) noexcept | |
268 | { | |
269 | // pthread_equal is undefined if either thread ID is not valid, so we | |
270 | // can't safely use __gthread_equal on default-constructed values (nor | |
271 | // the non-zero value returned by this_thread::get_id() for | |
272 | // single-threaded programs using GNU libc). Assume EqualityComparable. | |
273 | return __x._M_thread == __y._M_thread; | |
274 | } | |
275 | ||
d7afcd2b | 276 | inline bool |
7f0d79d5 | 277 | operator!=(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
278 | { return !(__x == __y); } |
279 | ||
b05cf382 JW |
280 | inline bool |
281 | operator<(thread::id __x, thread::id __y) noexcept | |
282 | { | |
283 | // Pthreads doesn't define any way to do this, so we just have to | |
284 | // assume native_handle_type is LessThanComparable. | |
285 | return __x._M_thread < __y._M_thread; | |
286 | } | |
287 | ||
d7afcd2b | 288 | inline bool |
7f0d79d5 | 289 | operator<=(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
290 | { return !(__y < __x); } |
291 | ||
292 | inline bool | |
7f0d79d5 | 293 | operator>(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
294 | { return __y < __x; } |
295 | ||
296 | inline bool | |
7f0d79d5 | 297 | operator>=(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
298 | { return !(__x < __y); } |
299 | ||
5c8db18a PC |
300 | // DR 889. |
301 | /// std::hash specialization for thread::id. | |
302 | template<> | |
303 | struct hash<thread::id> | |
5d64ee19 | 304 | : public __hash_base<size_t, thread::id> |
5c8db18a PC |
305 | { |
306 | size_t | |
72f1c34b | 307 | operator()(const thread::id& __id) const noexcept |
e7f72940 | 308 | { return std::_Hash_impl::hash(__id._M_thread); } |
5c8db18a PC |
309 | }; |
310 | ||
d7afcd2b BK |
311 | template<class _CharT, class _Traits> |
312 | inline basic_ostream<_CharT, _Traits>& | |
ff74fd13 | 313 | operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id) |
d7afcd2b BK |
314 | { |
315 | if (__id == thread::id()) | |
316 | return __out << "thread::id of a non-executing thread"; | |
317 | else | |
318 | return __out << __id._M_thread; | |
319 | } | |
320 | ||
5b9daa7e | 321 | /** @namespace std::this_thread |
9ab48d6e JW |
322 | * @brief ISO C++ 2011 entities sub-namespace for thread. |
323 | * 30.3.2 Namespace this_thread. | |
5b9daa7e | 324 | */ |
46e113bf CF |
325 | namespace this_thread |
326 | { | |
f7459b6c | 327 | /// get_id |
4a50cd93 | 328 | inline thread::id |
755be51d JW |
329 | get_id() noexcept |
330 | { | |
331 | #ifdef __GLIBC__ | |
332 | // For the GNU C library pthread_self() is usable without linking to | |
333 | // libpthread.so but returns 0, so we cannot use it in single-threaded | |
334 | // programs, because this_thread::get_id() != thread::id{} must be true. | |
335 | // We know that pthread_t is an integral type in the GNU C library. | |
336 | if (!__gthread_active_p()) | |
337 | return thread::id(1); | |
338 | #endif | |
339 | return thread::id(__gthread_self()); | |
340 | } | |
46e113bf | 341 | |
f7459b6c | 342 | /// yield |
959d14e1 | 343 | inline void |
7f0d79d5 | 344 | yield() noexcept |
aa66b299 JW |
345 | { |
346 | #ifdef _GLIBCXX_USE_SCHED_YIELD | |
347 | __gthread_yield(); | |
959d14e1 | 348 | #endif |
aa66b299 JW |
349 | } |
350 | ||
351 | void | |
352 | __sleep_for(chrono::seconds, chrono::nanoseconds); | |
46e113bf | 353 | |
f7459b6c | 354 | /// sleep_for |
46e113bf | 355 | template<typename _Rep, typename _Period> |
959d14e1 | 356 | inline void |
46e113bf CF |
357 | sleep_for(const chrono::duration<_Rep, _Period>& __rtime) |
358 | { | |
d1a74a28 JW |
359 | if (__rtime <= __rtime.zero()) |
360 | return; | |
aa66b299 JW |
361 | auto __s = chrono::duration_cast<chrono::seconds>(__rtime); |
362 | auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s); | |
363 | #ifdef _GLIBCXX_USE_NANOSLEEP | |
d7afcd2b | 364 | __gthread_time_t __ts = |
46e113bf CF |
365 | { |
366 | static_cast<std::time_t>(__s.count()), | |
367 | static_cast<long>(__ns.count()) | |
368 | }; | |
f55e699d JW |
369 | while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) |
370 | { } | |
aa66b299 JW |
371 | #else |
372 | __sleep_for(__s, __ns); | |
373 | #endif | |
46e113bf | 374 | } |
d1129441 JW |
375 | |
376 | /// sleep_until | |
377 | template<typename _Clock, typename _Duration> | |
378 | inline void | |
379 | sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) | |
d1a74a28 JW |
380 | { |
381 | auto __now = _Clock::now(); | |
f55e699d JW |
382 | if (_Clock::is_steady) |
383 | { | |
384 | if (__now < __atime) | |
385 | sleep_for(__atime - __now); | |
386 | return; | |
387 | } | |
388 | while (__now < __atime) | |
389 | { | |
390 | sleep_for(__atime - __now); | |
391 | __now = _Clock::now(); | |
392 | } | |
d1a74a28 | 393 | } |
46e113bf | 394 | } |
5b9daa7e BK |
395 | |
396 | // @} group threads | |
12ffa228 | 397 | |
4a15d842 | 398 | _GLIBCXX_END_NAMESPACE_VERSION |
12ffa228 | 399 | } // namespace |
46e113bf CF |
400 | |
401 | #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 | |
402 | ||
734f5023 | 403 | #endif // C++11 |
46e113bf CF |
404 | |
405 | #endif // _GLIBCXX_THREAD |