OLD | NEW |
(Empty) | |
| 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 |
| 103 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| 104 #pragma GCC system_header |
| 105 #endif |
| 106 |
| 107 #define __STDCPP_THREADS__ __cplusplus |
| 108 |
| 109 _LIBCPP_BEGIN_NAMESPACE_STD |
| 110 |
| 111 template <class _Tp> |
| 112 class __thread_specific_ptr |
| 113 { |
| 114 pthread_key_t __key_; |
| 115 |
| 116 __thread_specific_ptr(const __thread_specific_ptr&); |
| 117 __thread_specific_ptr& operator=(const __thread_specific_ptr&); |
| 118 |
| 119 static void __at_thread_exit(void*); |
| 120 public: |
| 121 typedef _Tp* pointer; |
| 122 |
| 123 __thread_specific_ptr(); |
| 124 ~__thread_specific_ptr(); |
| 125 |
| 126 _LIBCPP_INLINE_VISIBILITY |
| 127 pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));} |
| 128 _LIBCPP_INLINE_VISIBILITY |
| 129 pointer operator*() const {return *get();} |
| 130 _LIBCPP_INLINE_VISIBILITY |
| 131 pointer operator->() const {return get();} |
| 132 pointer release(); |
| 133 void reset(pointer __p = nullptr); |
| 134 }; |
| 135 |
| 136 template <class _Tp> |
| 137 void |
| 138 __thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) |
| 139 { |
| 140 delete static_cast<pointer>(__p); |
| 141 } |
| 142 |
| 143 template <class _Tp> |
| 144 __thread_specific_ptr<_Tp>::__thread_specific_ptr() |
| 145 { |
| 146 int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_e
xit); |
| 147 #ifndef _LIBCPP_NO_EXCEPTIONS |
| 148 if (__ec) |
| 149 throw system_error(error_code(__ec, system_category()), |
| 150 "__thread_specific_ptr construction failed"); |
| 151 #endif |
| 152 } |
| 153 |
| 154 template <class _Tp> |
| 155 __thread_specific_ptr<_Tp>::~__thread_specific_ptr() |
| 156 { |
| 157 pthread_key_delete(__key_); |
| 158 } |
| 159 |
| 160 template <class _Tp> |
| 161 typename __thread_specific_ptr<_Tp>::pointer |
| 162 __thread_specific_ptr<_Tp>::release() |
| 163 { |
| 164 pointer __p = get(); |
| 165 pthread_setspecific(__key_, 0); |
| 166 return __p; |
| 167 } |
| 168 |
| 169 template <class _Tp> |
| 170 void |
| 171 __thread_specific_ptr<_Tp>::reset(pointer __p) |
| 172 { |
| 173 pointer __p_old = get(); |
| 174 pthread_setspecific(__key_, __p); |
| 175 delete __p_old; |
| 176 } |
| 177 |
| 178 class _LIBCPP_TYPE_VIS thread; |
| 179 class _LIBCPP_TYPE_VIS __thread_id; |
| 180 |
| 181 namespace this_thread |
| 182 { |
| 183 |
| 184 _LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; |
| 185 |
| 186 } // this_thread |
| 187 |
| 188 template<> struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id>; |
| 189 |
| 190 class _LIBCPP_TYPE_VIS_ONLY __thread_id |
| 191 { |
| 192 // FIXME: pthread_t is a pointer on Darwin but a long on Linux. |
| 193 // NULL is the no-thread value on Darwin. Someone needs to check |
| 194 // on other platforms. We assume 0 works everywhere for now. |
| 195 pthread_t __id_; |
| 196 |
| 197 public: |
| 198 _LIBCPP_INLINE_VISIBILITY |
| 199 __thread_id() _NOEXCEPT : __id_(0) {} |
| 200 |
| 201 friend _LIBCPP_INLINE_VISIBILITY |
| 202 bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT |
| 203 {return __x.__id_ == __y.__id_;} |
| 204 friend _LIBCPP_INLINE_VISIBILITY |
| 205 bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT |
| 206 {return !(__x == __y);} |
| 207 friend _LIBCPP_INLINE_VISIBILITY |
| 208 bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT |
| 209 {return __x.__id_ < __y.__id_;} |
| 210 friend _LIBCPP_INLINE_VISIBILITY |
| 211 bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT |
| 212 {return !(__y < __x);} |
| 213 friend _LIBCPP_INLINE_VISIBILITY |
| 214 bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT |
| 215 {return __y < __x ;} |
| 216 friend _LIBCPP_INLINE_VISIBILITY |
| 217 bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT |
| 218 {return !(__x < __y);} |
| 219 |
| 220 template<class _CharT, class _Traits> |
| 221 friend |
| 222 _LIBCPP_INLINE_VISIBILITY |
| 223 basic_ostream<_CharT, _Traits>& |
| 224 operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) |
| 225 {return __os << __id.__id_;} |
| 226 |
| 227 private: |
| 228 _LIBCPP_INLINE_VISIBILITY |
| 229 __thread_id(pthread_t __id) : __id_(__id) {} |
| 230 |
| 231 friend __thread_id this_thread::get_id() _NOEXCEPT; |
| 232 friend class _LIBCPP_TYPE_VIS thread; |
| 233 friend struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id>; |
| 234 }; |
| 235 |
| 236 template<> |
| 237 struct _LIBCPP_TYPE_VIS_ONLY hash<__thread_id> |
| 238 : public unary_function<__thread_id, size_t> |
| 239 { |
| 240 _LIBCPP_INLINE_VISIBILITY |
| 241 size_t operator()(__thread_id __v) const |
| 242 { |
| 243 return hash<pthread_t>()(__v.__id_); |
| 244 } |
| 245 }; |
| 246 |
| 247 namespace this_thread |
| 248 { |
| 249 |
| 250 inline _LIBCPP_INLINE_VISIBILITY |
| 251 __thread_id |
| 252 get_id() _NOEXCEPT |
| 253 { |
| 254 return pthread_self(); |
| 255 } |
| 256 |
| 257 } // this_thread |
| 258 |
| 259 class _LIBCPP_TYPE_VIS thread |
| 260 { |
| 261 pthread_t __t_; |
| 262 |
| 263 thread(const thread&); |
| 264 thread& operator=(const thread&); |
| 265 public: |
| 266 typedef __thread_id id; |
| 267 typedef pthread_t native_handle_type; |
| 268 |
| 269 _LIBCPP_INLINE_VISIBILITY |
| 270 thread() _NOEXCEPT : __t_(0) {} |
| 271 #ifndef _LIBCPP_HAS_NO_VARIADICS |
| 272 template <class _Fp, class ..._Args, |
| 273 class = typename enable_if |
| 274 < |
| 275 !is_same<typename decay<_Fp>::type, thread>::value |
| 276 >::type |
| 277 > |
| 278 explicit thread(_Fp&& __f, _Args&&... __args); |
| 279 #else // _LIBCPP_HAS_NO_VARIADICS |
| 280 template <class _Fp> explicit thread(_Fp __f); |
| 281 #endif |
| 282 ~thread(); |
| 283 |
| 284 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES |
| 285 _LIBCPP_INLINE_VISIBILITY |
| 286 thread(thread&& __t) _NOEXCEPT : __t_(__t.__t_) {__t.__t_ = 0;} |
| 287 thread& operator=(thread&& __t) _NOEXCEPT; |
| 288 #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES |
| 289 |
| 290 _LIBCPP_INLINE_VISIBILITY |
| 291 void swap(thread& __t) _NOEXCEPT {_VSTD::swap(__t_, __t.__t_);} |
| 292 |
| 293 _LIBCPP_INLINE_VISIBILITY |
| 294 bool joinable() const _NOEXCEPT {return __t_ != 0;} |
| 295 void join(); |
| 296 void detach(); |
| 297 _LIBCPP_INLINE_VISIBILITY |
| 298 id get_id() const _NOEXCEPT {return __t_;} |
| 299 _LIBCPP_INLINE_VISIBILITY |
| 300 native_handle_type native_handle() _NOEXCEPT {return __t_;} |
| 301 |
| 302 static unsigned hardware_concurrency() _NOEXCEPT; |
| 303 }; |
| 304 |
| 305 class __assoc_sub_state; |
| 306 |
| 307 class _LIBCPP_HIDDEN __thread_struct_imp; |
| 308 |
| 309 class _LIBCPP_TYPE_VIS __thread_struct |
| 310 { |
| 311 __thread_struct_imp* __p_; |
| 312 |
| 313 __thread_struct(const __thread_struct&); |
| 314 __thread_struct& operator=(const __thread_struct&); |
| 315 public: |
| 316 __thread_struct(); |
| 317 ~__thread_struct(); |
| 318 |
| 319 void notify_all_at_thread_exit(condition_variable*, mutex*); |
| 320 void __make_ready_at_thread_exit(__assoc_sub_state*); |
| 321 }; |
| 322 |
| 323 _LIBCPP_FUNC_VIS __thread_specific_ptr<__thread_struct>& __thread_local_data(); |
| 324 |
| 325 #ifndef _LIBCPP_HAS_NO_VARIADICS |
| 326 |
| 327 template <class _Fp, class ..._Args, size_t ..._Indices> |
| 328 inline _LIBCPP_INLINE_VISIBILITY |
| 329 void |
| 330 __thread_execute(tuple<_Fp, _Args...>& __t, __tuple_indices<_Indices...>) |
| 331 { |
| 332 __invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(_
_t))...); |
| 333 } |
| 334 |
| 335 template <class _Fp> |
| 336 void* |
| 337 __thread_proxy(void* __vp) |
| 338 { |
| 339 __thread_local_data().reset(new __thread_struct); |
| 340 std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
| 341 typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Inde
x; |
| 342 __thread_execute(*__p, _Index()); |
| 343 return nullptr; |
| 344 } |
| 345 |
| 346 template <class _Fp, class ..._Args, |
| 347 class |
| 348 > |
| 349 thread::thread(_Fp&& __f, _Args&&... __args) |
| 350 { |
| 351 typedef tuple<typename decay<_Fp>::type, typename decay<_Args>::type...> _Gp
; |
| 352 _VSTD::unique_ptr<_Gp> __p(new _Gp(__decay_copy(_VSTD::forward<_Fp>(__f)), |
| 353 __decay_copy(_VSTD::forward<_Args>(__args))...))
; |
| 354 int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get()); |
| 355 if (__ec == 0) |
| 356 __p.release(); |
| 357 else |
| 358 __throw_system_error(__ec, "thread constructor failed"); |
| 359 } |
| 360 |
| 361 #else // _LIBCPP_HAS_NO_VARIADICS |
| 362 |
| 363 template <class _Fp> |
| 364 void* |
| 365 __thread_proxy(void* __vp) |
| 366 { |
| 367 __thread_local_data().reset(new __thread_struct); |
| 368 std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); |
| 369 (*__p)(); |
| 370 return nullptr; |
| 371 } |
| 372 |
| 373 template <class _Fp> |
| 374 thread::thread(_Fp __f) |
| 375 { |
| 376 std::unique_ptr<_Fp> __p(new _Fp(__f)); |
| 377 int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Fp>, __p.get()); |
| 378 if (__ec == 0) |
| 379 __p.release(); |
| 380 else |
| 381 __throw_system_error(__ec, "thread constructor failed"); |
| 382 } |
| 383 |
| 384 #endif // _LIBCPP_HAS_NO_VARIADICS |
| 385 |
| 386 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES |
| 387 |
| 388 inline _LIBCPP_INLINE_VISIBILITY |
| 389 thread& |
| 390 thread::operator=(thread&& __t) _NOEXCEPT |
| 391 { |
| 392 if (__t_ != 0) |
| 393 terminate(); |
| 394 __t_ = __t.__t_; |
| 395 __t.__t_ = 0; |
| 396 return *this; |
| 397 } |
| 398 |
| 399 #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES |
| 400 |
| 401 inline _LIBCPP_INLINE_VISIBILITY |
| 402 void swap(thread& __x, thread& __y) _NOEXCEPT {__x.swap(__y);} |
| 403 |
| 404 namespace this_thread |
| 405 { |
| 406 |
| 407 _LIBCPP_FUNC_VIS void sleep_for(const chrono::nanoseconds& ns); |
| 408 |
| 409 template <class _Rep, class _Period> |
| 410 void |
| 411 sleep_for(const chrono::duration<_Rep, _Period>& __d) |
| 412 { |
| 413 using namespace chrono; |
| 414 if (__d > duration<_Rep, _Period>::zero()) |
| 415 { |
| 416 _LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max(); |
| 417 nanoseconds __ns; |
| 418 if (__d < _Max) |
| 419 { |
| 420 __ns = duration_cast<nanoseconds>(__d); |
| 421 if (__ns < __d) |
| 422 ++__ns; |
| 423 } |
| 424 else |
| 425 __ns = nanoseconds::max(); |
| 426 sleep_for(__ns); |
| 427 } |
| 428 } |
| 429 |
| 430 template <class _Clock, class _Duration> |
| 431 void |
| 432 sleep_until(const chrono::time_point<_Clock, _Duration>& __t) |
| 433 { |
| 434 using namespace chrono; |
| 435 mutex __mut; |
| 436 condition_variable __cv; |
| 437 unique_lock<mutex> __lk(__mut); |
| 438 while (_Clock::now() < __t) |
| 439 __cv.wait_until(__lk, __t); |
| 440 } |
| 441 |
| 442 template <class _Duration> |
| 443 inline _LIBCPP_INLINE_VISIBILITY |
| 444 void |
| 445 sleep_until(const chrono::time_point<chrono::steady_clock, _Duration>& __t) |
| 446 { |
| 447 using namespace chrono; |
| 448 sleep_for(__t - steady_clock::now()); |
| 449 } |
| 450 |
| 451 inline _LIBCPP_INLINE_VISIBILITY |
| 452 void yield() _NOEXCEPT {sched_yield();} |
| 453 |
| 454 } // this_thread |
| 455 |
| 456 _LIBCPP_END_NAMESPACE_STD |
| 457 |
| 458 #endif // _LIBCPP_THREAD |
OLD | NEW |