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