thread.cpp revision 227825
1//===------------------------- thread.cpp----------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "thread"
11#include "exception"
12#include "vector"
13#include "future"
14#include <sys/types.h>
15#if !_WIN32
16#include <sys/sysctl.h>
17#endif // _WIN32
18
19_LIBCPP_BEGIN_NAMESPACE_STD
20
21thread::~thread()
22{
23    if (__t_ != 0)
24        terminate();
25}
26
27void
28thread::join()
29{
30    int ec = pthread_join(__t_, 0);
31#ifndef _LIBCPP_NO_EXCEPTIONS
32    if (ec)
33        throw system_error(error_code(ec, system_category()), "thread::join failed");
34#endif  // _LIBCPP_NO_EXCEPTIONS
35    __t_ = 0;
36}
37
38void
39thread::detach()
40{
41    int ec = EINVAL;
42    if (__t_ != 0)
43    {
44        ec = pthread_detach(__t_);
45        if (ec == 0)
46            __t_ = 0;
47    }
48#ifndef _LIBCPP_NO_EXCEPTIONS
49    if (ec)
50        throw system_error(error_code(ec, system_category()), "thread::detach failed");
51#endif  // _LIBCPP_NO_EXCEPTIONS
52}
53
54unsigned
55thread::hardware_concurrency()
56{
57#if defined(CTL_HW) && defined(HW_NCPU)
58    int n;
59    int mib[2] = {CTL_HW, HW_NCPU};
60    std::size_t s = sizeof(n);
61    sysctl(mib, 2, &n, &s, 0, 0);
62    return n;
63#else  // defined(CTL_HW) && defined(HW_NCPU)
64    // TODO: grovel through /proc or check cpuid on x86 and similar
65    // instructions on other architectures.
66    return 0;  // Means not computable [thread.thread.static]
67#endif  // defined(CTL_HW) && defined(HW_NCPU)
68}
69
70namespace this_thread
71{
72
73void
74sleep_for(const chrono::nanoseconds& ns)
75{
76    using namespace chrono;
77    if (ns >= nanoseconds::zero())
78    {
79        timespec ts;
80        ts.tv_sec = static_cast<decltype(ts.tv_sec)>(duration_cast<seconds>(ns).count());
81        ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns - seconds(ts.tv_sec)).count());
82        nanosleep(&ts, 0);
83    }
84}
85
86}  // this_thread
87
88__thread_specific_ptr<__thread_struct>&
89__thread_local_data()
90{
91    static __thread_specific_ptr<__thread_struct> __p;
92    return __p;
93}
94
95// __thread_struct_imp
96
97template <class T>
98class _LIBCPP_HIDDEN __hidden_allocator
99{
100public:
101    typedef T  value_type;
102
103    T* allocate(size_t __n)
104        {return static_cast<T*>(::operator new(__n * sizeof(T)));}
105    void deallocate(T* __p, size_t) {::operator delete((void*)__p);}
106
107    size_t max_size() const {return size_t(~0) / sizeof(T);}
108};
109
110class _LIBCPP_HIDDEN __thread_struct_imp
111{
112    typedef vector<__assoc_sub_state*,
113                          __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
114    typedef vector<pair<condition_variable*, mutex*>,
115               __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
116
117    _AsyncStates async_states_;
118    _Notify notify_;
119
120    __thread_struct_imp(const __thread_struct_imp&);
121    __thread_struct_imp& operator=(const __thread_struct_imp&);
122public:
123    __thread_struct_imp() {}
124    ~__thread_struct_imp();
125
126    void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
127    void __make_ready_at_thread_exit(__assoc_sub_state* __s);
128};
129
130__thread_struct_imp::~__thread_struct_imp()
131{
132    for (_Notify::iterator i = notify_.begin(), e = notify_.end();
133            i != e; ++i)
134    {
135        i->second->unlock();
136        i->first->notify_all();
137    }
138    for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
139            i != e; ++i)
140    {
141        (*i)->__make_ready();
142        (*i)->__release_shared();
143    }
144}
145
146void
147__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
148{
149    notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
150}
151
152void
153__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
154{
155    async_states_.push_back(__s);
156    __s->__add_shared();
157}
158
159// __thread_struct
160
161__thread_struct::__thread_struct()
162    : __p_(new __thread_struct_imp)
163{
164}
165
166__thread_struct::~__thread_struct()
167{
168    delete __p_;
169}
170
171void
172__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
173{
174    __p_->notify_all_at_thread_exit(cv, m);
175}
176
177void
178__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
179{
180    __p_->__make_ready_at_thread_exit(__s);
181}
182
183_LIBCPP_END_NAMESPACE_STD
184