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