]>
Commit | Line | Data |
---|---|---|
46e113bf CF |
1 | // <thread> -*- C++ -*- |
2 | ||
818ab71a | 3 | // Copyright (C) 2008-2016 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 BK |
110 | thread(const thread&) = delete; |
111 | ||
7f0d79d5 | 112 | thread(thread&& __t) noexcept |
d7afcd2b BK |
113 | { swap(__t); } |
114 | ||
46e113bf | 115 | template<typename _Callable, typename... _Args> |
33ac58d5 | 116 | explicit |
46e113bf | 117 | thread(_Callable&& __f, _Args&&... __args) |
1b3fad81 | 118 | { |
c6b3f349 | 119 | #ifdef GTHR_ACTIVE_PROXY |
ce535a96 JW |
120 | // Create a reference to pthread_create, not just the gthr weak symbol. |
121 | auto __depend = reinterpret_cast<void(*)()>(&pthread_create); | |
c6b3f349 | 122 | #else |
ce535a96 | 123 | auto __depend = nullptr; |
c6b3f349 | 124 | #endif |
ce535a96 | 125 | _M_start_thread(_S_make_state( |
5579170b JW |
126 | __make_invoker(std::forward<_Callable>(__f), |
127 | std::forward<_Args>(__args)...)), | |
ce535a96 | 128 | __depend); |
1b3fad81 | 129 | } |
46e113bf | 130 | |
959d14e1 | 131 | ~thread() |
cbdab9c8 JW |
132 | { |
133 | if (joinable()) | |
cd3b0faf | 134 | std::terminate(); |
cbdab9c8 | 135 | } |
46e113bf | 136 | |
46e113bf | 137 | thread& operator=(const thread&) = delete; |
d7afcd2b | 138 | |
7f0d79d5 | 139 | thread& operator=(thread&& __t) noexcept |
78b580a9 JW |
140 | { |
141 | if (joinable()) | |
cd3b0faf | 142 | std::terminate(); |
78b580a9 JW |
143 | swap(__t); |
144 | return *this; | |
145 | } | |
46e113bf | 146 | |
d7afcd2b | 147 | void |
7f0d79d5 | 148 | swap(thread& __t) noexcept |
626dda69 | 149 | { std::swap(_M_id, __t._M_id); } |
46e113bf | 150 | |
d7afcd2b | 151 | bool |
7f0d79d5 | 152 | joinable() const noexcept |
626dda69 | 153 | { return !(_M_id == id()); } |
46e113bf | 154 | |
d7afcd2b | 155 | void |
46e113bf CF |
156 | join(); |
157 | ||
d7afcd2b | 158 | void |
46e113bf CF |
159 | detach(); |
160 | ||
959d14e1 | 161 | thread::id |
7f0d79d5 | 162 | get_id() const noexcept |
626dda69 | 163 | { return _M_id; } |
46e113bf | 164 | |
cbdab9c8 JW |
165 | /** @pre thread is joinable |
166 | */ | |
d7afcd2b | 167 | native_handle_type |
46e113bf | 168 | native_handle() |
626dda69 | 169 | { return _M_id._M_thread; } |
46e113bf | 170 | |
d7afcd2b BK |
171 | // Returns a value that hints at the number of hardware thread contexts. |
172 | static unsigned int | |
43653c33 | 173 | hardware_concurrency() noexcept; |
46e113bf | 174 | |
46e113bf | 175 | private: |
ce535a96 JW |
176 | template<typename _Callable> |
177 | struct _State_impl : public _State | |
178 | { | |
179 | _Callable _M_func; | |
180 | ||
181 | _State_impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f)) | |
182 | { } | |
183 | ||
184 | void | |
185 | _M_run() { _M_func(); } | |
186 | }; | |
c6b3f349 | 187 | |
626dda69 | 188 | void |
ce535a96 | 189 | _M_start_thread(_State_ptr, void (*)()); |
626dda69 | 190 | |
46e113bf | 191 | template<typename _Callable> |
ce535a96 JW |
192 | static _State_ptr |
193 | _S_make_state(_Callable&& __f) | |
8644ecf5 | 194 | { |
ce535a96 JW |
195 | using _Impl = _State_impl<_Callable>; |
196 | return _State_ptr{new _Impl{std::forward<_Callable>(__f)}}; | |
46e113bf | 197 | } |
ce535a96 JW |
198 | #if _GLIBCXX_THREAD_ABI_COMPAT |
199 | public: | |
200 | struct _Impl_base; | |
201 | typedef shared_ptr<_Impl_base> __shared_base_type; | |
202 | struct _Impl_base | |
203 | { | |
204 | __shared_base_type _M_this_ptr; | |
205 | virtual ~_Impl_base() = default; | |
206 | virtual void _M_run() = 0; | |
207 | }; | |
46e113bf | 208 | |
ce535a96 JW |
209 | private: |
210 | void | |
211 | _M_start_thread(__shared_base_type, void (*)()); | |
212 | ||
213 | void | |
214 | _M_start_thread(__shared_base_type); | |
215 | #endif | |
5579170b JW |
216 | |
217 | private: | |
218 | // A call wrapper that does INVOKE(forwarded tuple elements...) | |
219 | template<typename _Tuple> | |
220 | struct _Invoker | |
221 | { | |
222 | _Tuple _M_t; | |
223 | ||
224 | template<size_t _Index> | |
225 | static __tuple_element_t<_Index, _Tuple>&& | |
226 | _S_declval(); | |
227 | ||
228 | template<size_t... _Ind> | |
229 | auto | |
230 | _M_invoke(_Index_tuple<_Ind...>) | |
231 | noexcept(noexcept(std::__invoke(_S_declval<_Ind>()...))) | |
232 | -> decltype(std::__invoke(_S_declval<_Ind>()...)) | |
233 | { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); } | |
234 | ||
235 | using _Indices | |
236 | = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type; | |
237 | ||
a2284544 | 238 | auto |
5579170b | 239 | operator()() |
a2284544 JW |
240 | noexcept(noexcept(std::declval<_Invoker&>()._M_invoke(_Indices()))) |
241 | -> decltype(std::declval<_Invoker&>()._M_invoke(_Indices())) | |
5579170b | 242 | { return _M_invoke(_Indices()); } |
5579170b JW |
243 | }; |
244 | ||
245 | // Alias for _Invoker<tuple<DECAY_COPY(_Tp)...>> | |
246 | template<typename... _Tp> | |
247 | using __invoker_type | |
248 | = _Invoker<decltype(std::make_tuple(std::declval<_Tp>()...))>; | |
249 | ||
250 | public: | |
251 | // Returns a call wrapper that does | |
252 | // INVOKE(DECAY_COPY(__callable), DECAY_COPY(__args)). | |
253 | template<typename _Callable, typename... _Args> | |
254 | static __invoker_type<_Callable, _Args...> | |
255 | __make_invoker(_Callable&& __callable, _Args&&... __args) | |
256 | { | |
257 | return { { | |
258 | std::make_tuple(std::forward<_Callable>(__callable), | |
259 | std::forward<_Args>(__args)...) | |
260 | } }; | |
261 | } | |
ce535a96 | 262 | }; |
d5545744 | 263 | |
46e113bf | 264 | inline void |
7f0d79d5 | 265 | swap(thread& __x, thread& __y) noexcept |
46e113bf CF |
266 | { __x.swap(__y); } |
267 | ||
b05cf382 JW |
268 | inline bool |
269 | operator==(thread::id __x, thread::id __y) noexcept | |
270 | { | |
271 | // pthread_equal is undefined if either thread ID is not valid, so we | |
272 | // can't safely use __gthread_equal on default-constructed values (nor | |
273 | // the non-zero value returned by this_thread::get_id() for | |
274 | // single-threaded programs using GNU libc). Assume EqualityComparable. | |
275 | return __x._M_thread == __y._M_thread; | |
276 | } | |
277 | ||
d7afcd2b | 278 | inline bool |
7f0d79d5 | 279 | operator!=(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
280 | { return !(__x == __y); } |
281 | ||
b05cf382 JW |
282 | inline bool |
283 | operator<(thread::id __x, thread::id __y) noexcept | |
284 | { | |
285 | // Pthreads doesn't define any way to do this, so we just have to | |
286 | // assume native_handle_type is LessThanComparable. | |
287 | return __x._M_thread < __y._M_thread; | |
288 | } | |
289 | ||
d7afcd2b | 290 | inline bool |
7f0d79d5 | 291 | operator<=(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
292 | { return !(__y < __x); } |
293 | ||
294 | inline bool | |
7f0d79d5 | 295 | operator>(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
296 | { return __y < __x; } |
297 | ||
298 | inline bool | |
7f0d79d5 | 299 | operator>=(thread::id __x, thread::id __y) noexcept |
d7afcd2b BK |
300 | { return !(__x < __y); } |
301 | ||
5c8db18a PC |
302 | // DR 889. |
303 | /// std::hash specialization for thread::id. | |
304 | template<> | |
305 | struct hash<thread::id> | |
5d64ee19 | 306 | : public __hash_base<size_t, thread::id> |
5c8db18a PC |
307 | { |
308 | size_t | |
72f1c34b | 309 | operator()(const thread::id& __id) const noexcept |
e7f72940 | 310 | { return std::_Hash_impl::hash(__id._M_thread); } |
5c8db18a PC |
311 | }; |
312 | ||
d7afcd2b BK |
313 | template<class _CharT, class _Traits> |
314 | inline basic_ostream<_CharT, _Traits>& | |
ff74fd13 | 315 | operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id) |
d7afcd2b BK |
316 | { |
317 | if (__id == thread::id()) | |
318 | return __out << "thread::id of a non-executing thread"; | |
319 | else | |
320 | return __out << __id._M_thread; | |
321 | } | |
322 | ||
12ffa228 BK |
323 | _GLIBCXX_END_NAMESPACE_VERSION |
324 | ||
5b9daa7e | 325 | /** @namespace std::this_thread |
9ab48d6e JW |
326 | * @brief ISO C++ 2011 entities sub-namespace for thread. |
327 | * 30.3.2 Namespace this_thread. | |
5b9daa7e | 328 | */ |
46e113bf CF |
329 | namespace this_thread |
330 | { | |
12ffa228 BK |
331 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
332 | ||
f7459b6c | 333 | /// get_id |
4a50cd93 | 334 | inline thread::id |
755be51d JW |
335 | get_id() noexcept |
336 | { | |
337 | #ifdef __GLIBC__ | |
338 | // For the GNU C library pthread_self() is usable without linking to | |
339 | // libpthread.so but returns 0, so we cannot use it in single-threaded | |
340 | // programs, because this_thread::get_id() != thread::id{} must be true. | |
341 | // We know that pthread_t is an integral type in the GNU C library. | |
342 | if (!__gthread_active_p()) | |
343 | return thread::id(1); | |
344 | #endif | |
345 | return thread::id(__gthread_self()); | |
346 | } | |
46e113bf | 347 | |
f7459b6c | 348 | /// yield |
959d14e1 | 349 | inline void |
7f0d79d5 | 350 | yield() noexcept |
aa66b299 JW |
351 | { |
352 | #ifdef _GLIBCXX_USE_SCHED_YIELD | |
353 | __gthread_yield(); | |
959d14e1 | 354 | #endif |
aa66b299 JW |
355 | } |
356 | ||
357 | void | |
358 | __sleep_for(chrono::seconds, chrono::nanoseconds); | |
46e113bf | 359 | |
f7459b6c | 360 | /// sleep_for |
46e113bf | 361 | template<typename _Rep, typename _Period> |
959d14e1 | 362 | inline void |
46e113bf CF |
363 | sleep_for(const chrono::duration<_Rep, _Period>& __rtime) |
364 | { | |
d1a74a28 JW |
365 | if (__rtime <= __rtime.zero()) |
366 | return; | |
aa66b299 JW |
367 | auto __s = chrono::duration_cast<chrono::seconds>(__rtime); |
368 | auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s); | |
369 | #ifdef _GLIBCXX_USE_NANOSLEEP | |
d7afcd2b | 370 | __gthread_time_t __ts = |
46e113bf CF |
371 | { |
372 | static_cast<std::time_t>(__s.count()), | |
373 | static_cast<long>(__ns.count()) | |
374 | }; | |
f55e699d JW |
375 | while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) |
376 | { } | |
aa66b299 JW |
377 | #else |
378 | __sleep_for(__s, __ns); | |
379 | #endif | |
46e113bf | 380 | } |
d1129441 JW |
381 | |
382 | /// sleep_until | |
383 | template<typename _Clock, typename _Duration> | |
384 | inline void | |
385 | sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) | |
d1a74a28 JW |
386 | { |
387 | auto __now = _Clock::now(); | |
f55e699d JW |
388 | if (_Clock::is_steady) |
389 | { | |
390 | if (__now < __atime) | |
391 | sleep_for(__atime - __now); | |
392 | return; | |
393 | } | |
394 | while (__now < __atime) | |
395 | { | |
396 | sleep_for(__atime - __now); | |
397 | __now = _Clock::now(); | |
398 | } | |
d1a74a28 | 399 | } |
12ffa228 BK |
400 | |
401 | _GLIBCXX_END_NAMESPACE_VERSION | |
46e113bf | 402 | } |
5b9daa7e BK |
403 | |
404 | // @} group threads | |
12ffa228 BK |
405 | |
406 | } // namespace | |
46e113bf CF |
407 | |
408 | #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 | |
409 | ||
734f5023 | 410 | #endif // C++11 |
46e113bf CF |
411 | |
412 | #endif // _GLIBCXX_THREAD |