1227825Stheraven//===------------------------- thread.cpp----------------------------------===//
2227825Stheraven//
3227825Stheraven//                     The LLVM Compiler Infrastructure
4227825Stheraven//
5227825Stheraven// This file is dual licensed under the MIT and the University of Illinois Open
6227825Stheraven// Source Licenses. See LICENSE.TXT for details.
7227825Stheraven//
8227825Stheraven//===----------------------------------------------------------------------===//
9227825Stheraven
10278724Sdim#include "__config"
11278724Sdim#ifndef _LIBCPP_HAS_NO_THREADS
12278724Sdim
13227825Stheraven#include "thread"
14227825Stheraven#include "exception"
15227825Stheraven#include "vector"
16227825Stheraven#include "future"
17241903Sdim#include "limits"
18227825Stheraven#include <sys/types.h>
19249998Sdim#if !defined(_WIN32)
20278724Sdim# if !defined(__sun__) && !defined(__linux__) && !defined(_AIX) && !defined(__native_client__)
21278724Sdim#   include <sys/sysctl.h>
22278724Sdim# endif // !defined(__sun__) && !defined(__linux__) && !defined(_AIX) && !defined(__native_client__)
23278724Sdim# include <unistd.h>
24241903Sdim#endif // !_WIN32
25227825Stheraven
26253159Stheraven#if defined(__NetBSD__)
27253159Stheraven#pragma weak pthread_create // Do not create libpthread dependency
28253159Stheraven#endif
29253159Stheraven#if defined(_WIN32)
30253159Stheraven#include <windows.h>
31253159Stheraven#endif
32253159Stheraven
33227825Stheraven_LIBCPP_BEGIN_NAMESPACE_STD
34227825Stheraven
35227825Stheraventhread::~thread()
36227825Stheraven{
37227825Stheraven    if (__t_ != 0)
38227825Stheraven        terminate();
39227825Stheraven}
40227825Stheraven
41227825Stheravenvoid
42227825Stheraventhread::join()
43227825Stheraven{
44227825Stheraven    int ec = pthread_join(__t_, 0);
45227825Stheraven#ifndef _LIBCPP_NO_EXCEPTIONS
46227825Stheraven    if (ec)
47227825Stheraven        throw system_error(error_code(ec, system_category()), "thread::join failed");
48249998Sdim#else
49249998Sdim    (void)ec;
50227825Stheraven#endif  // _LIBCPP_NO_EXCEPTIONS
51227825Stheraven    __t_ = 0;
52227825Stheraven}
53227825Stheraven
54227825Stheravenvoid
55227825Stheraventhread::detach()
56227825Stheraven{
57227825Stheraven    int ec = EINVAL;
58227825Stheraven    if (__t_ != 0)
59227825Stheraven    {
60227825Stheraven        ec = pthread_detach(__t_);
61227825Stheraven        if (ec == 0)
62227825Stheraven            __t_ = 0;
63227825Stheraven    }
64227825Stheraven#ifndef _LIBCPP_NO_EXCEPTIONS
65227825Stheraven    if (ec)
66227825Stheraven        throw system_error(error_code(ec, system_category()), "thread::detach failed");
67227825Stheraven#endif  // _LIBCPP_NO_EXCEPTIONS
68227825Stheraven}
69227825Stheraven
70227825Stheravenunsigned
71241903Sdimthread::hardware_concurrency() _NOEXCEPT
72227825Stheraven{
73227825Stheraven#if defined(CTL_HW) && defined(HW_NCPU)
74232950Stheraven    unsigned n;
75227825Stheraven    int mib[2] = {CTL_HW, HW_NCPU};
76227825Stheraven    std::size_t s = sizeof(n);
77227825Stheraven    sysctl(mib, 2, &n, &s, 0, 0);
78227825Stheraven    return n;
79253159Stheraven#elif defined(_SC_NPROCESSORS_ONLN)
80241903Sdim    long result = sysconf(_SC_NPROCESSORS_ONLN);
81246487Stheraven    // sysconf returns -1 if the name is invalid, the option does not exist or
82246487Stheraven    // does not have a definite limit.
83249998Sdim    // if sysconf returns some other negative number, we have no idea
84249998Sdim    // what is going on. Default to something safe.
85249998Sdim    if (result < 0)
86246487Stheraven        return 0;
87249998Sdim    return static_cast<unsigned>(result);
88253159Stheraven#elif defined(_WIN32)
89253159Stheraven    SYSTEM_INFO info;
90253159Stheraven    GetSystemInfo(&info);
91253159Stheraven    return info.dwNumberOfProcessors;
92227825Stheraven#else  // defined(CTL_HW) && defined(HW_NCPU)
93227825Stheraven    // TODO: grovel through /proc or check cpuid on x86 and similar
94227825Stheraven    // instructions on other architectures.
95262801Sdim#   if defined(_MSC_VER) && ! defined(__clang__)
96262801Sdim        _LIBCPP_WARNING("hardware_concurrency not yet implemented")
97262801Sdim#   else
98262801Sdim#       warning hardware_concurrency not yet implemented
99262801Sdim#   endif
100227825Stheraven    return 0;  // Means not computable [thread.thread.static]
101227825Stheraven#endif  // defined(CTL_HW) && defined(HW_NCPU)
102227825Stheraven}
103227825Stheraven
104227825Stheravennamespace this_thread
105227825Stheraven{
106227825Stheraven
107227825Stheravenvoid
108227825Stheravensleep_for(const chrono::nanoseconds& ns)
109227825Stheraven{
110227825Stheraven    using namespace chrono;
111241903Sdim    if (ns > nanoseconds::zero())
112227825Stheraven    {
113241903Sdim        seconds s = duration_cast<seconds>(ns);
114227825Stheraven        timespec ts;
115241903Sdim        typedef decltype(ts.tv_sec) ts_sec;
116241903Sdim        _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
117241903Sdim        if (s.count() < ts_sec_max)
118241903Sdim        {
119241903Sdim            ts.tv_sec = static_cast<ts_sec>(s.count());
120241903Sdim            ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count());
121241903Sdim        }
122241903Sdim        else
123241903Sdim        {
124241903Sdim            ts.tv_sec = ts_sec_max;
125241903Sdim            ts.tv_nsec = giga::num - 1;
126241903Sdim        }
127278724Sdim
128278724Sdim        while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
129278724Sdim            ;
130227825Stheraven    }
131227825Stheraven}
132227825Stheraven
133227825Stheraven}  // this_thread
134227825Stheraven
135227825Stheraven__thread_specific_ptr<__thread_struct>&
136227825Stheraven__thread_local_data()
137227825Stheraven{
138227825Stheraven    static __thread_specific_ptr<__thread_struct> __p;
139227825Stheraven    return __p;
140227825Stheraven}
141227825Stheraven
142227825Stheraven// __thread_struct_imp
143227825Stheraven
144227825Stheraventemplate <class T>
145227825Stheravenclass _LIBCPP_HIDDEN __hidden_allocator
146227825Stheraven{
147227825Stheravenpublic:
148227825Stheraven    typedef T  value_type;
149227825Stheraven
150227825Stheraven    T* allocate(size_t __n)
151227825Stheraven        {return static_cast<T*>(::operator new(__n * sizeof(T)));}
152278724Sdim    void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}
153227825Stheraven
154227825Stheraven    size_t max_size() const {return size_t(~0) / sizeof(T);}
155227825Stheraven};
156227825Stheraven
157227825Stheravenclass _LIBCPP_HIDDEN __thread_struct_imp
158227825Stheraven{
159227825Stheraven    typedef vector<__assoc_sub_state*,
160227825Stheraven                          __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
161227825Stheraven    typedef vector<pair<condition_variable*, mutex*>,
162227825Stheraven               __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
163227825Stheraven
164227825Stheraven    _AsyncStates async_states_;
165227825Stheraven    _Notify notify_;
166227825Stheraven
167227825Stheraven    __thread_struct_imp(const __thread_struct_imp&);
168227825Stheraven    __thread_struct_imp& operator=(const __thread_struct_imp&);
169227825Stheravenpublic:
170227825Stheraven    __thread_struct_imp() {}
171227825Stheraven    ~__thread_struct_imp();
172227825Stheraven
173227825Stheraven    void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
174227825Stheraven    void __make_ready_at_thread_exit(__assoc_sub_state* __s);
175227825Stheraven};
176227825Stheraven
177227825Stheraven__thread_struct_imp::~__thread_struct_imp()
178227825Stheraven{
179227825Stheraven    for (_Notify::iterator i = notify_.begin(), e = notify_.end();
180227825Stheraven            i != e; ++i)
181227825Stheraven    {
182227825Stheraven        i->second->unlock();
183227825Stheraven        i->first->notify_all();
184227825Stheraven    }
185227825Stheraven    for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
186227825Stheraven            i != e; ++i)
187227825Stheraven    {
188227825Stheraven        (*i)->__make_ready();
189227825Stheraven        (*i)->__release_shared();
190227825Stheraven    }
191227825Stheraven}
192227825Stheraven
193227825Stheravenvoid
194227825Stheraven__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
195227825Stheraven{
196227825Stheraven    notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
197227825Stheraven}
198227825Stheraven
199227825Stheravenvoid
200227825Stheraven__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
201227825Stheraven{
202227825Stheraven    async_states_.push_back(__s);
203227825Stheraven    __s->__add_shared();
204227825Stheraven}
205227825Stheraven
206227825Stheraven// __thread_struct
207227825Stheraven
208227825Stheraven__thread_struct::__thread_struct()
209227825Stheraven    : __p_(new __thread_struct_imp)
210227825Stheraven{
211227825Stheraven}
212227825Stheraven
213227825Stheraven__thread_struct::~__thread_struct()
214227825Stheraven{
215227825Stheraven    delete __p_;
216227825Stheraven}
217227825Stheraven
218227825Stheravenvoid
219227825Stheraven__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
220227825Stheraven{
221227825Stheraven    __p_->notify_all_at_thread_exit(cv, m);
222227825Stheraven}
223227825Stheraven
224227825Stheravenvoid
225227825Stheraven__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
226227825Stheraven{
227227825Stheraven    __p_->__make_ready_at_thread_exit(__s);
228227825Stheraven}
229227825Stheraven
230227825Stheraven_LIBCPP_END_NAMESPACE_STD
231278724Sdim
232278724Sdim#endif // !_LIBCPP_HAS_NO_THREADS
233