xref: /freebsd/contrib/llvm-project/libcxx/src/thread.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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