10b57cec5SDimitry Andric //===------------------------- thread.cpp----------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 906c3fb27SDimitry Andric #include <__thread/poll_with_backoff.h> 1006c3fb27SDimitry Andric #include <__thread/timed_backoff_policy.h> 1181ad6265SDimitry Andric #include <exception> 1281ad6265SDimitry Andric #include <future> 1381ad6265SDimitry Andric #include <limits> 1481ad6265SDimitry Andric #include <thread> 1581ad6265SDimitry Andric #include <vector> 160b57cec5SDimitry Andric 175ffd83dbSDimitry Andric #if __has_include(<unistd.h>) 18e8d8bef9SDimitry Andric # include <unistd.h> // for sysconf 195ffd83dbSDimitry Andric #endif 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric #if defined(__NetBSD__) 220b57cec5SDimitry Andric # pragma weak pthread_create // Do not create libpthread dependency 230b57cec5SDimitry Andric #endif 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #if defined(_LIBCPP_WIN32API) 260b57cec5SDimitry Andric # include <windows.h> 270b57cec5SDimitry Andric #endif 280b57cec5SDimitry Andric 29480093f4SDimitry Andric #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) 300b57cec5SDimitry Andric # pragma comment(lib, "pthread") 310b57cec5SDimitry Andric #endif 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 340b57cec5SDimitry Andric 35*cb14a3feSDimitry Andric thread::~thread() { 360b57cec5SDimitry Andric if (!__libcpp_thread_isnull(&__t_)) 370b57cec5SDimitry Andric terminate(); 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric 40*cb14a3feSDimitry Andric void thread::join() { 410b57cec5SDimitry Andric int ec = EINVAL; 42*cb14a3feSDimitry Andric if (!__libcpp_thread_isnull(&__t_)) { 430b57cec5SDimitry Andric ec = __libcpp_thread_join(&__t_); 440b57cec5SDimitry Andric if (ec == 0) 450b57cec5SDimitry Andric __t_ = _LIBCPP_NULL_THREAD; 460b57cec5SDimitry Andric } 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric if (ec) 490b57cec5SDimitry Andric __throw_system_error(ec, "thread::join failed"); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 52*cb14a3feSDimitry Andric void thread::detach() { 530b57cec5SDimitry Andric int ec = EINVAL; 54*cb14a3feSDimitry Andric if (!__libcpp_thread_isnull(&__t_)) { 550b57cec5SDimitry Andric ec = __libcpp_thread_detach(&__t_); 560b57cec5SDimitry Andric if (ec == 0) 570b57cec5SDimitry Andric __t_ = _LIBCPP_NULL_THREAD; 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric if (ec) 610b57cec5SDimitry Andric __throw_system_error(ec, "thread::detach failed"); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 64*cb14a3feSDimitry Andric unsigned thread::hardware_concurrency() noexcept { 65e8d8bef9SDimitry Andric #if defined(_SC_NPROCESSORS_ONLN) 660b57cec5SDimitry Andric long result = sysconf(_SC_NPROCESSORS_ONLN); 670b57cec5SDimitry Andric // sysconf returns -1 if the name is invalid, the option does not exist or 680b57cec5SDimitry Andric // does not have a definite limit. 690b57cec5SDimitry Andric // if sysconf returns some other negative number, we have no idea 700b57cec5SDimitry Andric // what is going on. Default to something safe. 710b57cec5SDimitry Andric if (result < 0) 720b57cec5SDimitry Andric return 0; 730b57cec5SDimitry Andric return static_cast<unsigned>(result); 740b57cec5SDimitry Andric #elif defined(_LIBCPP_WIN32API) 750b57cec5SDimitry Andric SYSTEM_INFO info; 760b57cec5SDimitry Andric GetSystemInfo(&info); 770b57cec5SDimitry Andric return info.dwNumberOfProcessors; 780b57cec5SDimitry Andric #else // defined(CTL_HW) && defined(HW_NCPU) 790b57cec5SDimitry Andric // TODO: grovel through /proc or check cpuid on x86 and similar 800b57cec5SDimitry Andric // instructions on other architectures. 810b57cec5SDimitry Andric # if defined(_LIBCPP_WARNING) 820b57cec5SDimitry Andric _LIBCPP_WARNING("hardware_concurrency not yet implemented") 830b57cec5SDimitry Andric # else 840b57cec5SDimitry Andric # warning hardware_concurrency not yet implemented 850b57cec5SDimitry Andric # endif 860b57cec5SDimitry Andric return 0; // Means not computable [thread.thread.static] 870b57cec5SDimitry Andric #endif // defined(CTL_HW) && defined(HW_NCPU) 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 90*cb14a3feSDimitry Andric namespace this_thread { 910b57cec5SDimitry Andric 92*cb14a3feSDimitry Andric void sleep_for(const chrono::nanoseconds& ns) { 93*cb14a3feSDimitry Andric if (ns > chrono::nanoseconds::zero()) { 940b57cec5SDimitry Andric __libcpp_thread_sleep_for(ns); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 98*cb14a3feSDimitry Andric } // namespace this_thread 990b57cec5SDimitry Andric 100*cb14a3feSDimitry Andric __thread_specific_ptr<__thread_struct>& __thread_local_data() { 10181ad6265SDimitry Andric // Even though __thread_specific_ptr's destructor doesn't actually destroy 10281ad6265SDimitry Andric // anything (see comments there), we can't call it at all because threads may 10381ad6265SDimitry Andric // outlive the static variable and calling its destructor means accessing an 10481ad6265SDimitry Andric // object outside of its lifetime, which is UB. 10581ad6265SDimitry Andric alignas(__thread_specific_ptr<__thread_struct>) static char __b[sizeof(__thread_specific_ptr<__thread_struct>)]; 10681ad6265SDimitry Andric static __thread_specific_ptr<__thread_struct>* __p = new (__b) __thread_specific_ptr<__thread_struct>(); 10781ad6265SDimitry Andric return *__p; 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // __thread_struct_imp 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric template <class T> 113*cb14a3feSDimitry Andric class _LIBCPP_HIDDEN __hidden_allocator { 1140b57cec5SDimitry Andric public: 1150b57cec5SDimitry Andric typedef T value_type; 1160b57cec5SDimitry Andric 117*cb14a3feSDimitry Andric T* allocate(size_t __n) { return static_cast<T*>(::operator new(__n * sizeof(T))); } 1180b57cec5SDimitry Andric void deallocate(T* __p, size_t) { ::operator delete(static_cast<void*>(__p)); } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric size_t max_size() const { return size_t(~0) / sizeof(T); } 1210b57cec5SDimitry Andric }; 1220b57cec5SDimitry Andric 123*cb14a3feSDimitry Andric class _LIBCPP_HIDDEN __thread_struct_imp { 124*cb14a3feSDimitry Andric typedef vector<__assoc_sub_state*, __hidden_allocator<__assoc_sub_state*> > _AsyncStates; 125*cb14a3feSDimitry Andric typedef vector<pair<condition_variable*, mutex*>, __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric _AsyncStates async_states_; 1280b57cec5SDimitry Andric _Notify notify_; 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric __thread_struct_imp(const __thread_struct_imp&); 1310b57cec5SDimitry Andric __thread_struct_imp& operator=(const __thread_struct_imp&); 132*cb14a3feSDimitry Andric 1330b57cec5SDimitry Andric public: 1340b57cec5SDimitry Andric __thread_struct_imp() {} 1350b57cec5SDimitry Andric ~__thread_struct_imp(); 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric void notify_all_at_thread_exit(condition_variable* cv, mutex* m); 1380b57cec5SDimitry Andric void __make_ready_at_thread_exit(__assoc_sub_state* __s); 1390b57cec5SDimitry Andric }; 1400b57cec5SDimitry Andric 141*cb14a3feSDimitry Andric __thread_struct_imp::~__thread_struct_imp() { 142*cb14a3feSDimitry Andric for (_Notify::iterator i = notify_.begin(), e = notify_.end(); i != e; ++i) { 1430b57cec5SDimitry Andric i->first->notify_all(); 144bdd1243dSDimitry Andric i->second->unlock(); 1450b57cec5SDimitry Andric } 146*cb14a3feSDimitry Andric for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end(); i != e; ++i) { 1470b57cec5SDimitry Andric (*i)->__make_ready(); 1480b57cec5SDimitry Andric (*i)->__release_shared(); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 152*cb14a3feSDimitry Andric void __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m) { 1530b57cec5SDimitry Andric notify_.push_back(pair<condition_variable*, mutex*>(cv, m)); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 156*cb14a3feSDimitry Andric void __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s) { 1570b57cec5SDimitry Andric async_states_.push_back(__s); 1580b57cec5SDimitry Andric __s->__add_shared(); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric // __thread_struct 1620b57cec5SDimitry Andric 163*cb14a3feSDimitry Andric __thread_struct::__thread_struct() : __p_(new __thread_struct_imp) {} 1640b57cec5SDimitry Andric 165*cb14a3feSDimitry Andric __thread_struct::~__thread_struct() { delete __p_; } 1660b57cec5SDimitry Andric 167*cb14a3feSDimitry Andric void __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m) { 1680b57cec5SDimitry Andric __p_->notify_all_at_thread_exit(cv, m); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 171*cb14a3feSDimitry Andric void __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) { __p_->__make_ready_at_thread_exit(__s); } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 174