14684ddb6SLionel Sambuc //===------------------------- thread.cpp----------------------------------===//
24684ddb6SLionel Sambuc //
34684ddb6SLionel Sambuc // The LLVM Compiler Infrastructure
44684ddb6SLionel Sambuc //
54684ddb6SLionel Sambuc // This file is dual licensed under the MIT and the University of Illinois Open
64684ddb6SLionel Sambuc // Source Licenses. See LICENSE.TXT for details.
74684ddb6SLionel Sambuc //
84684ddb6SLionel Sambuc //===----------------------------------------------------------------------===//
94684ddb6SLionel Sambuc
10*0a6a1f1dSLionel Sambuc #include "__config"
11*0a6a1f1dSLionel Sambuc #ifndef _LIBCPP_HAS_NO_THREADS
12*0a6a1f1dSLionel Sambuc
134684ddb6SLionel Sambuc #include "thread"
144684ddb6SLionel Sambuc #include "exception"
154684ddb6SLionel Sambuc #include "vector"
164684ddb6SLionel Sambuc #include "future"
174684ddb6SLionel Sambuc #include "limits"
184684ddb6SLionel Sambuc #include <sys/types.h>
194684ddb6SLionel Sambuc #if !defined(_WIN32)
20*0a6a1f1dSLionel Sambuc # if !defined(__sun__) && !defined(__linux__) && !defined(_AIX) && !defined(__native_client__) && !defined(__CloudABI__)
214684ddb6SLionel Sambuc # include <sys/sysctl.h>
22*0a6a1f1dSLionel Sambuc # endif // !defined(__sun__) && !defined(__linux__) && !defined(_AIX) && !defined(__native_client__) && !defined(__CloudABI__)
234684ddb6SLionel Sambuc # include <unistd.h>
244684ddb6SLionel Sambuc #endif // !_WIN32
254684ddb6SLionel Sambuc
264684ddb6SLionel Sambuc #if defined(__NetBSD__) || defined(__minix)
274684ddb6SLionel Sambuc #pragma weak pthread_create // Do not create libpthread dependency
284684ddb6SLionel Sambuc #endif
294684ddb6SLionel Sambuc #if defined(_WIN32)
304684ddb6SLionel Sambuc #include <windows.h>
314684ddb6SLionel Sambuc #endif
324684ddb6SLionel Sambuc
334684ddb6SLionel Sambuc _LIBCPP_BEGIN_NAMESPACE_STD
344684ddb6SLionel Sambuc
~thread()354684ddb6SLionel Sambuc thread::~thread()
364684ddb6SLionel Sambuc {
374684ddb6SLionel Sambuc if (__t_ != 0)
384684ddb6SLionel Sambuc terminate();
394684ddb6SLionel Sambuc }
404684ddb6SLionel Sambuc
414684ddb6SLionel Sambuc void
join()424684ddb6SLionel Sambuc thread::join()
434684ddb6SLionel Sambuc {
444684ddb6SLionel Sambuc int ec = pthread_join(__t_, 0);
454684ddb6SLionel Sambuc #ifndef _LIBCPP_NO_EXCEPTIONS
464684ddb6SLionel Sambuc if (ec)
474684ddb6SLionel Sambuc throw system_error(error_code(ec, system_category()), "thread::join failed");
484684ddb6SLionel Sambuc #else
494684ddb6SLionel Sambuc (void)ec;
504684ddb6SLionel Sambuc #endif // _LIBCPP_NO_EXCEPTIONS
514684ddb6SLionel Sambuc __t_ = 0;
524684ddb6SLionel Sambuc }
534684ddb6SLionel Sambuc
544684ddb6SLionel Sambuc void
detach()554684ddb6SLionel Sambuc thread::detach()
564684ddb6SLionel Sambuc {
574684ddb6SLionel Sambuc int ec = EINVAL;
584684ddb6SLionel Sambuc if (__t_ != 0)
594684ddb6SLionel Sambuc {
604684ddb6SLionel Sambuc ec = pthread_detach(__t_);
614684ddb6SLionel Sambuc if (ec == 0)
624684ddb6SLionel Sambuc __t_ = 0;
634684ddb6SLionel Sambuc }
644684ddb6SLionel Sambuc #ifndef _LIBCPP_NO_EXCEPTIONS
654684ddb6SLionel Sambuc if (ec)
664684ddb6SLionel Sambuc throw system_error(error_code(ec, system_category()), "thread::detach failed");
674684ddb6SLionel Sambuc #endif // _LIBCPP_NO_EXCEPTIONS
684684ddb6SLionel Sambuc }
694684ddb6SLionel Sambuc
704684ddb6SLionel Sambuc unsigned
hardware_concurrency()714684ddb6SLionel Sambuc thread::hardware_concurrency() _NOEXCEPT
724684ddb6SLionel Sambuc {
734684ddb6SLionel Sambuc #if defined(CTL_HW) && defined(HW_NCPU)
744684ddb6SLionel Sambuc unsigned n;
754684ddb6SLionel Sambuc int mib[2] = {CTL_HW, HW_NCPU};
764684ddb6SLionel Sambuc std::size_t s = sizeof(n);
774684ddb6SLionel Sambuc sysctl(mib, 2, &n, &s, 0, 0);
784684ddb6SLionel Sambuc return n;
794684ddb6SLionel Sambuc #elif defined(_SC_NPROCESSORS_ONLN)
804684ddb6SLionel Sambuc long result = sysconf(_SC_NPROCESSORS_ONLN);
814684ddb6SLionel Sambuc // sysconf returns -1 if the name is invalid, the option does not exist or
824684ddb6SLionel Sambuc // does not have a definite limit.
834684ddb6SLionel Sambuc // if sysconf returns some other negative number, we have no idea
844684ddb6SLionel Sambuc // what is going on. Default to something safe.
854684ddb6SLionel Sambuc if (result < 0)
864684ddb6SLionel Sambuc return 0;
874684ddb6SLionel Sambuc return static_cast<unsigned>(result);
884684ddb6SLionel Sambuc #elif defined(_WIN32)
894684ddb6SLionel Sambuc SYSTEM_INFO info;
904684ddb6SLionel Sambuc GetSystemInfo(&info);
914684ddb6SLionel Sambuc return info.dwNumberOfProcessors;
924684ddb6SLionel Sambuc #else // defined(CTL_HW) && defined(HW_NCPU)
934684ddb6SLionel Sambuc // TODO: grovel through /proc or check cpuid on x86 and similar
944684ddb6SLionel Sambuc // instructions on other architectures.
954684ddb6SLionel Sambuc # if defined(_MSC_VER) && ! defined(__clang__)
964684ddb6SLionel Sambuc _LIBCPP_WARNING("hardware_concurrency not yet implemented")
974684ddb6SLionel Sambuc # else
984684ddb6SLionel Sambuc # warning hardware_concurrency not yet implemented
994684ddb6SLionel Sambuc # endif
1004684ddb6SLionel Sambuc return 0; // Means not computable [thread.thread.static]
1014684ddb6SLionel Sambuc #endif // defined(CTL_HW) && defined(HW_NCPU)
1024684ddb6SLionel Sambuc }
1034684ddb6SLionel Sambuc
1044684ddb6SLionel Sambuc namespace this_thread
1054684ddb6SLionel Sambuc {
1064684ddb6SLionel Sambuc
1074684ddb6SLionel Sambuc void
sleep_for(const chrono::nanoseconds & ns)1084684ddb6SLionel Sambuc sleep_for(const chrono::nanoseconds& ns)
1094684ddb6SLionel Sambuc {
1104684ddb6SLionel Sambuc using namespace chrono;
1114684ddb6SLionel Sambuc if (ns > nanoseconds::zero())
1124684ddb6SLionel Sambuc {
1134684ddb6SLionel Sambuc seconds s = duration_cast<seconds>(ns);
1144684ddb6SLionel Sambuc timespec ts;
1154684ddb6SLionel Sambuc typedef decltype(ts.tv_sec) ts_sec;
1164684ddb6SLionel Sambuc _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
1174684ddb6SLionel Sambuc if (s.count() < ts_sec_max)
1184684ddb6SLionel Sambuc {
1194684ddb6SLionel Sambuc ts.tv_sec = static_cast<ts_sec>(s.count());
1204684ddb6SLionel Sambuc ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count());
1214684ddb6SLionel Sambuc }
1224684ddb6SLionel Sambuc else
1234684ddb6SLionel Sambuc {
1244684ddb6SLionel Sambuc ts.tv_sec = ts_sec_max;
1254684ddb6SLionel Sambuc ts.tv_nsec = giga::num - 1;
1264684ddb6SLionel Sambuc }
127*0a6a1f1dSLionel Sambuc
128*0a6a1f1dSLionel Sambuc while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
129*0a6a1f1dSLionel Sambuc ;
1304684ddb6SLionel Sambuc }
1314684ddb6SLionel Sambuc }
1324684ddb6SLionel Sambuc
1334684ddb6SLionel Sambuc } // this_thread
1344684ddb6SLionel Sambuc
1354684ddb6SLionel Sambuc __thread_specific_ptr<__thread_struct>&
__thread_local_data()1364684ddb6SLionel Sambuc __thread_local_data()
1374684ddb6SLionel Sambuc {
1384684ddb6SLionel Sambuc static __thread_specific_ptr<__thread_struct> __p;
1394684ddb6SLionel Sambuc return __p;
1404684ddb6SLionel Sambuc }
1414684ddb6SLionel Sambuc
1424684ddb6SLionel Sambuc // __thread_struct_imp
1434684ddb6SLionel Sambuc
1444684ddb6SLionel Sambuc template <class T>
1454684ddb6SLionel Sambuc class _LIBCPP_HIDDEN __hidden_allocator
1464684ddb6SLionel Sambuc {
1474684ddb6SLionel Sambuc public:
1484684ddb6SLionel Sambuc typedef T value_type;
1494684ddb6SLionel Sambuc
allocate(size_t __n)1504684ddb6SLionel Sambuc T* allocate(size_t __n)
1514684ddb6SLionel Sambuc {return static_cast<T*>(::operator new(__n * sizeof(T)));}
deallocate(T * __p,size_t)152*0a6a1f1dSLionel Sambuc void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}
1534684ddb6SLionel Sambuc
max_size() const1544684ddb6SLionel Sambuc size_t max_size() const {return size_t(~0) / sizeof(T);}
1554684ddb6SLionel Sambuc };
1564684ddb6SLionel Sambuc
1574684ddb6SLionel Sambuc class _LIBCPP_HIDDEN __thread_struct_imp
1584684ddb6SLionel Sambuc {
1594684ddb6SLionel Sambuc typedef vector<__assoc_sub_state*,
1604684ddb6SLionel Sambuc __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
1614684ddb6SLionel Sambuc typedef vector<pair<condition_variable*, mutex*>,
1624684ddb6SLionel Sambuc __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
1634684ddb6SLionel Sambuc
1644684ddb6SLionel Sambuc _AsyncStates async_states_;
1654684ddb6SLionel Sambuc _Notify notify_;
1664684ddb6SLionel Sambuc
1674684ddb6SLionel Sambuc __thread_struct_imp(const __thread_struct_imp&);
1684684ddb6SLionel Sambuc __thread_struct_imp& operator=(const __thread_struct_imp&);
1694684ddb6SLionel Sambuc public:
__thread_struct_imp()1704684ddb6SLionel Sambuc __thread_struct_imp() {}
1714684ddb6SLionel Sambuc ~__thread_struct_imp();
1724684ddb6SLionel Sambuc
1734684ddb6SLionel Sambuc void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
1744684ddb6SLionel Sambuc void __make_ready_at_thread_exit(__assoc_sub_state* __s);
1754684ddb6SLionel Sambuc };
1764684ddb6SLionel Sambuc
~__thread_struct_imp()1774684ddb6SLionel Sambuc __thread_struct_imp::~__thread_struct_imp()
1784684ddb6SLionel Sambuc {
1794684ddb6SLionel Sambuc for (_Notify::iterator i = notify_.begin(), e = notify_.end();
1804684ddb6SLionel Sambuc i != e; ++i)
1814684ddb6SLionel Sambuc {
1824684ddb6SLionel Sambuc i->second->unlock();
1834684ddb6SLionel Sambuc i->first->notify_all();
1844684ddb6SLionel Sambuc }
1854684ddb6SLionel Sambuc for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
1864684ddb6SLionel Sambuc i != e; ++i)
1874684ddb6SLionel Sambuc {
1884684ddb6SLionel Sambuc (*i)->__make_ready();
1894684ddb6SLionel Sambuc (*i)->__release_shared();
1904684ddb6SLionel Sambuc }
1914684ddb6SLionel Sambuc }
1924684ddb6SLionel Sambuc
1934684ddb6SLionel Sambuc void
notify_all_at_thread_exit(condition_variable * cv,mutex * m)1944684ddb6SLionel Sambuc __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
1954684ddb6SLionel Sambuc {
1964684ddb6SLionel Sambuc notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
1974684ddb6SLionel Sambuc }
1984684ddb6SLionel Sambuc
1994684ddb6SLionel Sambuc void
__make_ready_at_thread_exit(__assoc_sub_state * __s)2004684ddb6SLionel Sambuc __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
2014684ddb6SLionel Sambuc {
2024684ddb6SLionel Sambuc async_states_.push_back(__s);
2034684ddb6SLionel Sambuc __s->__add_shared();
2044684ddb6SLionel Sambuc }
2054684ddb6SLionel Sambuc
2064684ddb6SLionel Sambuc // __thread_struct
2074684ddb6SLionel Sambuc
__thread_struct()2084684ddb6SLionel Sambuc __thread_struct::__thread_struct()
2094684ddb6SLionel Sambuc : __p_(new __thread_struct_imp)
2104684ddb6SLionel Sambuc {
2114684ddb6SLionel Sambuc }
2124684ddb6SLionel Sambuc
~__thread_struct()2134684ddb6SLionel Sambuc __thread_struct::~__thread_struct()
2144684ddb6SLionel Sambuc {
2154684ddb6SLionel Sambuc delete __p_;
2164684ddb6SLionel Sambuc }
2174684ddb6SLionel Sambuc
2184684ddb6SLionel Sambuc void
notify_all_at_thread_exit(condition_variable * cv,mutex * m)2194684ddb6SLionel Sambuc __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
2204684ddb6SLionel Sambuc {
2214684ddb6SLionel Sambuc __p_->notify_all_at_thread_exit(cv, m);
2224684ddb6SLionel Sambuc }
2234684ddb6SLionel Sambuc
2244684ddb6SLionel Sambuc void
__make_ready_at_thread_exit(__assoc_sub_state * __s)2254684ddb6SLionel Sambuc __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
2264684ddb6SLionel Sambuc {
2274684ddb6SLionel Sambuc __p_->__make_ready_at_thread_exit(__s);
2284684ddb6SLionel Sambuc }
2294684ddb6SLionel Sambuc
2304684ddb6SLionel Sambuc _LIBCPP_END_NAMESPACE_STD
231*0a6a1f1dSLionel Sambuc
232*0a6a1f1dSLionel Sambuc #endif // !_LIBCPP_HAS_NO_THREADS
233