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