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