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 981ad6265SDimitry Andric #include <__config> 1081ad6265SDimitry Andric 110b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 120b57cec5SDimitry Andric 13*06c3fb27SDimitry Andric #include <__thread/poll_with_backoff.h> 14*06c3fb27SDimitry Andric #include <__thread/timed_backoff_policy.h> 1581ad6265SDimitry Andric #include <exception> 1681ad6265SDimitry Andric #include <future> 1781ad6265SDimitry Andric #include <limits> 1881ad6265SDimitry Andric #include <thread> 1981ad6265SDimitry Andric #include <vector> 200b57cec5SDimitry Andric 215ffd83dbSDimitry Andric #if __has_include(<unistd.h>) 22e8d8bef9SDimitry Andric # include <unistd.h> // for sysconf 235ffd83dbSDimitry Andric #endif 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #if defined(__NetBSD__) 260b57cec5SDimitry Andric #pragma weak pthread_create // Do not create libpthread dependency 270b57cec5SDimitry Andric #endif 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #if defined(_LIBCPP_WIN32API) 300b57cec5SDimitry Andric #include <windows.h> 310b57cec5SDimitry Andric #endif 320b57cec5SDimitry Andric 33480093f4SDimitry Andric #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) 340b57cec5SDimitry Andric #pragma comment(lib, "pthread") 350b57cec5SDimitry Andric #endif 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric thread::~thread() 400b57cec5SDimitry Andric { 410b57cec5SDimitry Andric if (!__libcpp_thread_isnull(&__t_)) 420b57cec5SDimitry Andric terminate(); 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric void 460b57cec5SDimitry Andric thread::join() 470b57cec5SDimitry Andric { 480b57cec5SDimitry Andric int ec = EINVAL; 490b57cec5SDimitry Andric if (!__libcpp_thread_isnull(&__t_)) 500b57cec5SDimitry Andric { 510b57cec5SDimitry Andric ec = __libcpp_thread_join(&__t_); 520b57cec5SDimitry Andric if (ec == 0) 530b57cec5SDimitry Andric __t_ = _LIBCPP_NULL_THREAD; 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric if (ec) 570b57cec5SDimitry Andric __throw_system_error(ec, "thread::join failed"); 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric void 610b57cec5SDimitry Andric thread::detach() 620b57cec5SDimitry Andric { 630b57cec5SDimitry Andric int ec = EINVAL; 640b57cec5SDimitry Andric if (!__libcpp_thread_isnull(&__t_)) 650b57cec5SDimitry Andric { 660b57cec5SDimitry Andric ec = __libcpp_thread_detach(&__t_); 670b57cec5SDimitry Andric if (ec == 0) 680b57cec5SDimitry Andric __t_ = _LIBCPP_NULL_THREAD; 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric if (ec) 720b57cec5SDimitry Andric __throw_system_error(ec, "thread::detach failed"); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric unsigned 76fe6060f1SDimitry Andric thread::hardware_concurrency() noexcept 770b57cec5SDimitry Andric { 78e8d8bef9SDimitry Andric #if defined(_SC_NPROCESSORS_ONLN) 790b57cec5SDimitry Andric long result = sysconf(_SC_NPROCESSORS_ONLN); 800b57cec5SDimitry Andric // sysconf returns -1 if the name is invalid, the option does not exist or 810b57cec5SDimitry Andric // does not have a definite limit. 820b57cec5SDimitry Andric // if sysconf returns some other negative number, we have no idea 830b57cec5SDimitry Andric // what is going on. Default to something safe. 840b57cec5SDimitry Andric if (result < 0) 850b57cec5SDimitry Andric return 0; 860b57cec5SDimitry Andric return static_cast<unsigned>(result); 870b57cec5SDimitry Andric #elif defined(_LIBCPP_WIN32API) 880b57cec5SDimitry Andric SYSTEM_INFO info; 890b57cec5SDimitry Andric GetSystemInfo(&info); 900b57cec5SDimitry Andric return info.dwNumberOfProcessors; 910b57cec5SDimitry Andric #else // defined(CTL_HW) && defined(HW_NCPU) 920b57cec5SDimitry Andric // TODO: grovel through /proc or check cpuid on x86 and similar 930b57cec5SDimitry Andric // instructions on other architectures. 940b57cec5SDimitry Andric # if defined(_LIBCPP_WARNING) 950b57cec5SDimitry Andric _LIBCPP_WARNING("hardware_concurrency not yet implemented") 960b57cec5SDimitry Andric # else 970b57cec5SDimitry Andric # warning hardware_concurrency not yet implemented 980b57cec5SDimitry Andric # endif 990b57cec5SDimitry Andric return 0; // Means not computable [thread.thread.static] 1000b57cec5SDimitry Andric #endif // defined(CTL_HW) && defined(HW_NCPU) 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric namespace this_thread 1040b57cec5SDimitry Andric { 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric void 1070b57cec5SDimitry Andric sleep_for(const chrono::nanoseconds& ns) 1080b57cec5SDimitry Andric { 1090b57cec5SDimitry Andric if (ns > chrono::nanoseconds::zero()) 1100b57cec5SDimitry Andric { 1110b57cec5SDimitry Andric __libcpp_thread_sleep_for(ns); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric } // this_thread 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric __thread_specific_ptr<__thread_struct>& 1180b57cec5SDimitry Andric __thread_local_data() 1190b57cec5SDimitry Andric { 12081ad6265SDimitry Andric // Even though __thread_specific_ptr's destructor doesn't actually destroy 12181ad6265SDimitry Andric // anything (see comments there), we can't call it at all because threads may 12281ad6265SDimitry Andric // outlive the static variable and calling its destructor means accessing an 12381ad6265SDimitry Andric // object outside of its lifetime, which is UB. 12481ad6265SDimitry Andric alignas(__thread_specific_ptr<__thread_struct>) static char __b[sizeof(__thread_specific_ptr<__thread_struct>)]; 12581ad6265SDimitry Andric static __thread_specific_ptr<__thread_struct>* __p = new (__b) __thread_specific_ptr<__thread_struct>(); 12681ad6265SDimitry Andric return *__p; 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // __thread_struct_imp 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric template <class T> 1320b57cec5SDimitry Andric class _LIBCPP_HIDDEN __hidden_allocator 1330b57cec5SDimitry Andric { 1340b57cec5SDimitry Andric public: 1350b57cec5SDimitry Andric typedef T value_type; 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric T* allocate(size_t __n) 1380b57cec5SDimitry Andric {return static_cast<T*>(::operator new(__n * sizeof(T)));} 1390b57cec5SDimitry Andric void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));} 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric size_t max_size() const {return size_t(~0) / sizeof(T);} 1420b57cec5SDimitry Andric }; 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric class _LIBCPP_HIDDEN __thread_struct_imp 1450b57cec5SDimitry Andric { 1460b57cec5SDimitry Andric typedef vector<__assoc_sub_state*, 1470b57cec5SDimitry Andric __hidden_allocator<__assoc_sub_state*> > _AsyncStates; 1480b57cec5SDimitry Andric typedef vector<pair<condition_variable*, mutex*>, 1490b57cec5SDimitry Andric __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric _AsyncStates async_states_; 1520b57cec5SDimitry Andric _Notify notify_; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric __thread_struct_imp(const __thread_struct_imp&); 1550b57cec5SDimitry Andric __thread_struct_imp& operator=(const __thread_struct_imp&); 1560b57cec5SDimitry Andric public: 1570b57cec5SDimitry Andric __thread_struct_imp() {} 1580b57cec5SDimitry Andric ~__thread_struct_imp(); 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric void notify_all_at_thread_exit(condition_variable* cv, mutex* m); 1610b57cec5SDimitry Andric void __make_ready_at_thread_exit(__assoc_sub_state* __s); 1620b57cec5SDimitry Andric }; 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric __thread_struct_imp::~__thread_struct_imp() 1650b57cec5SDimitry Andric { 1660b57cec5SDimitry Andric for (_Notify::iterator i = notify_.begin(), e = notify_.end(); 1670b57cec5SDimitry Andric i != e; ++i) 1680b57cec5SDimitry Andric { 1690b57cec5SDimitry Andric i->first->notify_all(); 170bdd1243dSDimitry Andric i->second->unlock(); 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end(); 1730b57cec5SDimitry Andric i != e; ++i) 1740b57cec5SDimitry Andric { 1750b57cec5SDimitry Andric (*i)->__make_ready(); 1760b57cec5SDimitry Andric (*i)->__release_shared(); 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric void 1810b57cec5SDimitry Andric __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m) 1820b57cec5SDimitry Andric { 1830b57cec5SDimitry Andric notify_.push_back(pair<condition_variable*, mutex*>(cv, m)); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric void 1870b57cec5SDimitry Andric __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s) 1880b57cec5SDimitry Andric { 1890b57cec5SDimitry Andric async_states_.push_back(__s); 1900b57cec5SDimitry Andric __s->__add_shared(); 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric // __thread_struct 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric __thread_struct::__thread_struct() 1960b57cec5SDimitry Andric : __p_(new __thread_struct_imp) 1970b57cec5SDimitry Andric { 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric __thread_struct::~__thread_struct() 2010b57cec5SDimitry Andric { 2020b57cec5SDimitry Andric delete __p_; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric void 2060b57cec5SDimitry Andric __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m) 2070b57cec5SDimitry Andric { 2080b57cec5SDimitry Andric __p_->notify_all_at_thread_exit(cv, m); 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric void 2120b57cec5SDimitry Andric __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) 2130b57cec5SDimitry Andric { 2140b57cec5SDimitry Andric __p_->__make_ready_at_thread_exit(__s); 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS 220