root / lab4 / .minix-src / include / c++ / thread @ 14
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 |