root / lab4 / .minix-src / include / c++ / thread @ 13
History | View | Annotate | Download (12 KB)
1 |
// -*- C++ -*- |
---|---|
2 |
//===--------------------------- thread -----------------------------------===// |
3 |
// |
4 |
// The LLVM Compiler Infrastructure |
5 |
// |
6 |
// This file is dual licensed under the MIT and the University of Illinois Open |
7 |
// Source Licenses. See LICENSE.TXT for details. |
8 |
// |
9 |
//===----------------------------------------------------------------------===// |
10 | |
11 |
#ifndef _LIBCPP_THREAD |
12 |
#define _LIBCPP_THREAD |
13 | |
14 |
/* |
15 | |
16 |
thread synopsis |
17 | |
18 |
#define __STDCPP_THREADS__ __cplusplus |
19 | |
20 |
namespace std |
21 |
{ |
22 | |
23 |
class thread |
24 |
{ |
25 |
public: |
26 |
class id; |
27 |
typedef pthread_t native_handle_type; |
28 | |
29 |
thread() noexcept; |
30 |
template <class F, class ...Args> explicit thread(F&& f, Args&&... args); |
31 |
~thread(); |
32 | |
33 |
thread(const thread&) = delete; |
34 |
thread(thread&& t) noexcept; |
35 | |
36 |
thread& operator=(const thread&) = delete; |
37 |
thread& operator=(thread&& t) noexcept; |
38 | |
39 |
void swap(thread& t) noexcept; |
40 | |
41 |
bool joinable() const noexcept; |
42 |
void join(); |
43 |
void detach(); |
44 |
id get_id() const noexcept; |
45 |
native_handle_type native_handle(); |
46 | |
47 |
static unsigned hardware_concurrency() noexcept; |
48 |
}; |
49 | |
50 |
void swap(thread& x, thread& y) noexcept; |
51 | |
52 |
class thread::id |
53 |
{ |
54 |
public: |
55 |
id() noexcept; |
56 |
}; |
57 | |
58 |
bool operator==(thread::id x, thread::id y) noexcept; |
59 |
bool operator!=(thread::id x, thread::id y) noexcept; |
60 |
bool operator< (thread::id x, thread::id y) noexcept; |
61 |
bool operator<=(thread::id x, thread::id y) noexcept; |
62 |
bool operator> (thread::id x, thread::id y) noexcept; |
63 |
bool operator>=(thread::id x, thread::id y) noexcept; |
64 | |
65 |
template<class charT, class traits> |
66 |
basic_ostream<charT, traits>& |
67 |
operator<<(basic_ostream<charT, traits>& out, thread::id id); |
68 | |
69 |
namespace this_thread |
70 |
{ |
71 | |
72 |
thread::id get_id() noexcept; |
73 | |
74 |
void yield() noexcept; |
75 | |
76 |
template <class Clock, class Duration> |
77 |
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); |
78 | |
79 |
template <class Rep, class Period> |
80 |
void sleep_for(const chrono::duration<Rep, Period>& rel_time); |
81 | |
82 |
} // this_thread |
83 | |
84 |
} // std |
85 | |
86 |
*/ |
87 | |
88 |
#include <__config> |
89 |
#include <iosfwd> |
90 |
#include <__functional_base> |
91 |
#include <type_traits> |
92 |
#include <cstddef> |
93 |
#include <functional> |
94 |
#include <memory> |
95 |
#include <system_error> |
96 |
#include <chrono> |
97 |
#include <__mutex_base> |
98 |
#ifndef _LIBCPP_HAS_NO_VARIADICS |
99 |
#include <tuple> |
100 |
#endif |
101 |
#include <pthread.h> |
102 |
#include <sched.h> |
103 | |
104 |
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
105 |
#pragma GCC system_header |
106 |
#endif |
107 | |
108 |
#define __STDCPP_THREADS__ __cplusplus |
109 | |
110 |
#ifdef _LIBCPP_HAS_NO_THREADS |
111 |
#error <thread> is not supported on this single threaded system |
112 |
#else // !_LIBCPP_HAS_NO_THREADS |
113 | |
114 |
_LIBCPP_BEGIN_NAMESPACE_STD |
115 | |
116 |
template <class _Tp> class __thread_specific_ptr; |
117 |
class _LIBCPP_TYPE_VIS __thread_struct; |
118 |
class _LIBCPP_HIDDEN __thread_struct_imp; |
119 |
class __assoc_sub_state; |
120 | |
121 |
_LIBCPP_FUNC_VIS __thread_specific_ptr<__thread_struct>& __thread_local_data(); |
122 | |
123 |
class _LIBCPP_TYPE_VIS __thread_struct |
124 |
{ |
125 |
__thread_struct_imp* __p_; |
126 | |
127 |
__thread_struct(const __thread_struct&); |
128 |
__thread_struct& operator=(const __thread_struct&); |
129 |
public: |
130 |
__thread_struct(); |
131 |
~__thread_struct(); |
132 | |
133 |
void notify_all_at_thread_exit(condition_variable*, mutex*); |
134 |
void __make_ready_at_thread_exit(__assoc_sub_state*); |
135 |
}; |
136 | |
137 |
template <class _Tp> |
138 |
class __thread_specific_ptr |
139 |
{ |
140 |
pthread_key_t __key_; |
141 | |
142 |
// Only __thread_local_data() may construct a __thread_specific_ptr |
143 |
// and only with _Tp == __thread_struct. |
144 |
static_assert((is_same<_Tp, __thread_struct>::value), ""); |
145 |
__thread_specific_ptr(); |
146 |
friend _LIBCPP_FUNC_VIS __thread_specific_ptr<__thread_struct>& __thread_local_data(); |
147 | |
148 |
__thread_specific_ptr(const __thread_specific_ptr&); |
149 |
__thread_specific_ptr& operator=(const __thread_specific_ptr&); |
150 | |
151 |
static void __at_thread_exit(void*); |
152 |
public: |
153 |
typedef _Tp* pointer; |
154 | |
155 |
~__thread_specific_ptr(); |
156 | |
157 |
_LIBCPP_INLINE_VISIBILITY |
158 |
pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));} |
159 |
_LIBCPP_INLINE_VISIBILITY |
160 |
pointer operator*() const {return *get();} |
161 |
_LIBCPP_INLINE_VISIBILITY |
162 |
pointer operator->() const {return get();} |
163 |
pointer release(); |
164 |
void reset(pointer __p = nullptr); |
165 |
}; |
166 | |
167 |
template <class _Tp> |
168 |
void |
169 |
__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) |
170 |
{ |
171 |
delete static_cast<pointer>(__p); |
172 |
} |
173 | |
174 |
template <class _Tp> |
175 |
__thread_specific_ptr<_Tp>::__thread_specific_ptr() |
176 |
{ |
177 |
int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit); |
178 |
#ifndef _LIBCPP_NO_EXCEPTIONS |
179 |
if (__ec) |
180 |
throw system_error(error_code(__ec, system_category()), |
181 |
"__thread_specific_ptr construction failed"); |
182 |
#endif |
183 |
} |
184 | |
185 |
template <class _Tp> |
186 |
__thread_specific_ptr<_Tp>::~__thread_specific_ptr() |
187 |
{ |
188 |
// __thread_specific_ptr is only created with a static storage duration |
189 |
// so this destructor is only invoked during program termination. Invoking |
190 |
// pthread_key_delete(__key_) may prevent other threads from deleting their |
191 |
// thread local data. For this reason we leak the key. |
192 |
} |
193 | |
194 |
template <class _Tp> |
195 |
typename __thread_specific_ptr<_Tp>::pointer |
196 |
__thread_specific_ptr<_Tp>::release() |
197 |
{ |
198 |
pointer __p = get(); |
199 |
pthread_setspecific(__key_, 0); |
200 |
return __p; |
201 |
} |
202 | |
203 |
template <class _Tp> |
204 |
void |
205 |
__thread_specific_ptr<_Tp>::reset(pointer __p) |
206 |
{ |
207 |
pointer __p_old = get(); |
208 |
pthread_setspecific(__key_, __p); |
209 |
delete __p_old; |
210 |
} |
211 | |
212 |
class _LIBCPP_TYPE_VIS thread; |
213 |
class _LIBCPP_TYPE_VIS __thread_id; |
214 | |
215 |
namespace this_thread |
216 |
{ |
217 | |
218 |
_LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; |
219 | |
220 |
} // this_thread |
221 | |
222 |
template<> struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id>; |
223 | |
224 |
class _LIBCPP_TYPE_VIS_ONLY __thread_id |
225 |
{ |
226 |
// FIXME: pthread_t is a pointer on Darwin but a long on Linux. |
227 |
// NULL is the no-thread value on Darwin. Someone needs to check |
228 |
// on other platforms. We assume 0 works everywhere for now. |
229 |
pthread_t __id_; |
230 | |
231 |
public: |
232 |
_LIBCPP_INLINE_VISIBILITY |
233 |
__thread_id() _NOEXCEPT : __id_(0) {} |
234 | |
235 |
friend _LIBCPP_INLINE_VISIBILITY |
236 |
bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT |
237 |
{return __x.__id_ == __y.__id_;} |
238 |
friend _LIBCPP_INLINE_VISIBILITY |
239 |
bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT |
240 |
{return !(__x == __y);} |
241 |
friend _LIBCPP_INLINE_VISIBILITY |
242 |
bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT |
243 |
{return __x.__id_ < __y.__id_;} |
244 |
friend _LIBCPP_INLINE_VISIBILITY |
245 |
bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT |
246 |
{return !(__y < __x);} |
247 |
friend _LIBCPP_INLINE_VISIBILITY |
248 |
bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT |
249 |
{return __y < __x ;} |
250 |
friend _LIBCPP_INLINE_VISIBILITY |
251 |
bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT |
252 |
{return !(__x < __y);} |
253 | |
254 |
template<class _CharT, class _Traits> |
255 |
friend |
256 |
_LIBCPP_INLINE_VISIBILITY |
257 |
basic_ostream<_CharT, _Traits>& |
258 |
operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) |
259 |
{return __os << __id.__id_;} |
260 | |
261 |
private: |
262 |
_LIBCPP_INLINE_VISIBILITY |
263 |
__thread_id(pthread_t __id) : __id_(__id) {} |
264 | |
265 |
friend __thread_id this_thread::get_id() _NOEXCEPT; |
266 |
friend class _LIBCPP_TYPE_VIS thread; |
267 |
friend struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id>; |
268 |
}; |
269 | |
270 |
template<> |
271 |
struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id> |
272 |
: public unary_function<__thread_id, size_t> |
273 |
{ |
274 |
_LIBCPP_INLINE_VISIBILITY |
275 |
size_t operator()(__thread_id __v) const |
276 |
{ |
277 |
return hash<pthread_t>()(__v.__id_); |
278 |
} |
279 |
}; |
280 | |
281 |
namespace this_thread |
282 |
{ |
283 | |
284 |
inline _LIBCPP_INLINE_VISIBILITY |
285 |
__thread_id |
286 |
get_id() _NOEXCEPT |
287 |
{ |
288 |
return pthread_self(); |
289 |
} |
290 | |
291 |
} // this_thread |
292 | |
293 |
class _LIBCPP_TYPE_VIS thread |
294 |
{ |
295 |
pthread_t __t_; |
296 | |
297 |
thread(const thread&); |
298 |
thread& operator=(const thread&); |
299 |
public: |
300 |
typedef __thread_id id; |
301 |
typedef pthread_t native_handle_type; |
302 | |
303 |
_LIBCPP_INLINE_VISIBILITY |
304 |
thread() _NOEXCEPT : __t_(0) {} |
305 |
#ifndef _LIBCPP_HAS_NO_VARIADICS |
306 |
template <class _Fp, class ..._Args, |
307 |
class = typename enable_if |
308 |
< |
309 |
!is_same<typename decay<_Fp>::type, thread>::value |
310 |
>::type |
311 |
> |
312 |
explicit thread(_Fp&& __f, _Args&&... __args); |
313 |
#else // _LIBCPP_HAS_NO_VARIADICS |
314 |
template <class _Fp> explicit thread(_Fp __f); |
315 |
#endif |
316 |
~thread(); |
317 | |
318 |
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES |
319 |
_LIBCPP_INLINE_VISIBILITY |
320 |
thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) {__t.__t_ = 0;} |
321 |
thread& operator=(thread&& __t) _NOEXCEPT; |
322 |
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES |
323 | |
324 |
_LIBCPP_INLINE_VISIBILITY |
325 |
void swap(thread& __t) _NOEXCEPT {_VSTD::swap(__t_, __t.__t_);} |
326 | |
327 |
_LIBCPP_INLINE_VISIBILITY |
328 |
bool joinable() const _NOEXCEPT {return __t_ != 0;} |
329 |
void join(); |
330 |
void detach(); |
331 |
_LIBCPP_INLINE_VISIBILITY |
332 |
id get_id() const _NOEXCEPT {return __t_;} |
333 |
_LIBCPP_INLINE_VISIBILITY |
334 |
native_handle_type native_handle() _NOEXCEPT {return __t_;} |
335 | |
336 |
static unsigned hardware_concurrency() _NOEXCEPT; |
337 |
}; |
338 | |
339 |
#ifndef _LIBCPP_HAS_NO_VARIADICS |
340 | |
341 |
template <class _Fp, class ..._Args, size_t ..._Indices> |
342 |
inline _LIBCPP_INLINE_VISIBILITY |
343 |
void |
344 |
__thread_execute(tuple<_Fp, _Args...>& __t, __tuple_indices<_Indices...>) |
345 |
{ |
346 |
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...); |
347 |
} |
348 | |
349 |
template <class _Fp> |
350 |
void* |
351 |
__thread_proxy(void* __vp) |
352 |
{ |
353 |
__thread_local_data().reset(new __thread_struct); |
354 |
std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
355 |
typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index; |
356 |
__thread_execute(*__p, _Index()); |
357 |
return nullptr; |
358 |
} |
359 | |
360 |
template <class _Fp, class ..._Args, |
361 |
class |
362 |
> |
363 |
thread::thread(_Fp&& __f, _Args&&... __args) |
364 |
{ |
365 |
typedef tuple<typename decay<_Fp>::type, typename decay<_Args>::type...> _Gp; |
366 |
_VSTD::unique_ptr<_Gp> __p(new _Gp(__decay_copy(_VSTD::forward<_Fp>(__f)), |
367 |
__decay_copy(_VSTD::forward<_Args>(__args))...)); |
368 |
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get()); |
369 |
if (__ec == 0) |
370 |
__p.release(); |
371 |
else |
372 |
__throw_system_error(__ec, "thread constructor failed"); |
373 |
} |
374 | |
375 |
#else // _LIBCPP_HAS_NO_VARIADICS |
376 | |
377 |
template <class _Fp> |
378 |
void* |
379 |
__thread_proxy(void* __vp) |
380 |
{ |
381 |
__thread_local_data().reset(new __thread_struct); |
382 |
std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
383 |
(*__p)(); |
384 |
return nullptr; |
385 |
} |
386 | |
387 |
template <class _Fp> |
388 |
thread::thread(_Fp __f) |
389 |
{ |
390 |
std::unique_ptr<_Fp> __p(new _Fp(__f)); |
391 |
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Fp>, __p.get()); |
392 |
if (__ec == 0) |
393 |
__p.release(); |
394 |
else |
395 |
__throw_system_error(__ec, "thread constructor failed"); |
396 |
} |
397 | |
398 |
#endif // _LIBCPP_HAS_NO_VARIADICS |
399 | |
400 |
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES |
401 | |
402 |
inline _LIBCPP_INLINE_VISIBILITY |
403 |
thread& |
404 |
thread::operator=(thread&& __t) _NOEXCEPT |
405 |
{ |
406 |
if (__t_ != 0) |
407 |
terminate(); |
408 |
__t_ = __t.__t_; |
409 |
__t.__t_ = 0; |
410 |
return *this; |
411 |
} |
412 | |
413 |
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES |
414 | |
415 |
inline _LIBCPP_INLINE_VISIBILITY |
416 |
void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);} |
417 | |
418 |
namespace this_thread |
419 |
{ |
420 | |
421 |
_LIBCPP_FUNC_VIS void sleep_for(const chrono::nanoseconds& ns); |
422 | |
423 |
template <class _Rep, class _Period> |
424 |
void |
425 |
sleep_for(const chrono::duration<_Rep, _Period>& __d) |
426 |
{ |
427 |
using namespace chrono; |
428 |
if (__d > duration<_Rep, _Period>::zero()) |
429 |
{ |
430 |
_LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max(); |
431 |
nanoseconds __ns; |
432 |
if (__d < _Max) |
433 |
{ |
434 |
__ns = duration_cast<nanoseconds>(__d); |
435 |
if (__ns < __d) |
436 |
++__ns; |
437 |
} |
438 |
else |
439 |
__ns = nanoseconds::max(); |
440 |
sleep_for(__ns); |
441 |
} |
442 |
} |
443 | |
444 |
template <class _Clock, class _Duration> |
445 |
void |
446 |
sleep_until(const chrono::time_point<_Clock, _Duration>& __t) |
447 |
{ |
448 |
using namespace chrono; |
449 |
mutex __mut; |
450 |
condition_variable __cv; |
451 |
unique_lock<mutex> __lk(__mut); |
452 |
while (_Clock::now() < __t) |
453 |
__cv.wait_until(__lk, __t); |
454 |
} |
455 | |
456 |
template <class _Duration> |
457 |
inline _LIBCPP_INLINE_VISIBILITY |
458 |
void |
459 |
sleep_until(const chrono::time_point<chrono::steady_clock, _Duration>& __t) |
460 |
{ |
461 |
using namespace chrono; |
462 |
sleep_for(__t - steady_clock::now()); |
463 |
} |
464 | |
465 |
inline _LIBCPP_INLINE_VISIBILITY |
466 |
void yield() _NOEXCEPT {sched_yield();} |
467 | |
468 |
} // this_thread |
469 | |
470 |
_LIBCPP_END_NAMESPACE_STD |
471 | |
472 |
#endif // !_LIBCPP_HAS_NO_THREADS |
473 | |
474 |
#endif // _LIBCPP_THREAD |