1//===------------------------- thread.cpp----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10#ifndef _LIBCPP_HAS_NO_THREADS
11
12#include "thread"
13#include "exception"
14#include "vector"
15#include "future"
16#include "limits"
17#include <sys/types.h>
18
19#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
20# include <sys/param.h>
21# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
22# include <sys/sysctl.h>
23# endif
24#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
25
26#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__)
27# include <unistd.h>
28#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__)
29
30#if defined(__NetBSD__)
31#pragma weak pthread_create // Do not create libpthread dependency
32#endif
33
34#if defined(_LIBCPP_WIN32API)
35#include <windows.h>
36#endif
37
38_LIBCPP_BEGIN_NAMESPACE_STD
39
40thread::~thread()
41{
42 if (!__libcpp_thread_isnull(&__t_))
43 terminate();
44}
45
46void
47thread::join()
48{
49 int ec = EINVAL;
50 if (!__libcpp_thread_isnull(&__t_))
51 {
52 ec = __libcpp_thread_join(&__t_);
53 if (ec == 0)
54 __t_ = _LIBCPP_NULL_THREAD;
55 }
56
57 if (ec)
58 __throw_system_error(ec, "thread::join failed");
59}
60
61void
62thread::detach()
63{
64 int ec = EINVAL;
65 if (!__libcpp_thread_isnull(&__t_))
66 {
67 ec = __libcpp_thread_detach(&__t_);
68 if (ec == 0)
69 __t_ = _LIBCPP_NULL_THREAD;
70 }
71
72 if (ec)
73 __throw_system_error(ec, "thread::detach failed");
74}
75
76unsigned
77thread::hardware_concurrency() _NOEXCEPT
78{
79#if defined(CTL_HW) && defined(HW_NCPU)
80 unsigned n;
81 int mib[2] = {CTL_HW, HW_NCPU};
82 std::size_t s = sizeof(n);
83 sysctl(mib, 2, &n, &s, 0, 0);
84 return n;
85#elif defined(_SC_NPROCESSORS_ONLN)
86 long result = sysconf(_SC_NPROCESSORS_ONLN);
87 // sysconf returns -1 if the name is invalid, the option does not exist or
88 // does not have a definite limit.
89 // if sysconf returns some other negative number, we have no idea
90 // what is going on. Default to something safe.
91 if (result < 0)
92 return 0;
93 return static_cast<unsigned>(result);
94#elif defined(_LIBCPP_WIN32API)
95 SYSTEM_INFO info;
96 GetSystemInfo(&info);
97 return info.dwNumberOfProcessors;
98#else // defined(CTL_HW) && defined(HW_NCPU)
99 // TODO: grovel through /proc or check cpuid on x86 and similar
100 // instructions on other architectures.
101# if defined(_LIBCPP_WARNING)
102 _LIBCPP_WARNING("hardware_concurrency not yet implemented")
103# else
104# warning hardware_concurrency not yet implemented
105# endif
106 return 0; // Means not computable [thread.thread.static]
107#endif // defined(CTL_HW) && defined(HW_NCPU)
108}
109
110namespace this_thread
111{
112
113void
114sleep_for(const chrono::nanoseconds& ns)
115{
116 if (ns > chrono::nanoseconds::zero())
117 {
118 __libcpp_thread_sleep_for(ns);
119 }
120}
121
122} // this_thread
123
124__thread_specific_ptr<__thread_struct>&
125__thread_local_data()
126{
127 static __thread_specific_ptr<__thread_struct> __p;
128 return __p;
129}
130
131// __thread_struct_imp
132
133template <class T>
134class _LIBCPP_HIDDEN __hidden_allocator
135{
136public:
137 typedef T value_type;
138
139 T* allocate(size_t __n)
140 {return static_cast<T*>(::operator new(__n * sizeof(T)));}
141 void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}
142
143 size_t max_size() const {return size_t(~0) / sizeof(T);}
144};
145
146class _LIBCPP_HIDDEN __thread_struct_imp
147{
148 typedef vector<__assoc_sub_state*,
149 __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
150 typedef vector<pair<condition_variable*, mutex*>,
151 __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
152
153 _AsyncStates async_states_;
154 _Notify notify_;
155
156 __thread_struct_imp(const __thread_struct_imp&);
157 __thread_struct_imp& operator=(const __thread_struct_imp&);
158public:
159 __thread_struct_imp() {}
160 ~__thread_struct_imp();
161
162 void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
163 void __make_ready_at_thread_exit(__assoc_sub_state* __s);
164};
165
166__thread_struct_imp::~__thread_struct_imp()
167{
168 for (_Notify::iterator i = notify_.begin(), e = notify_.end();
169 i != e; ++i)
170 {
171 i->second->unlock();
172 i->first->notify_all();
173 }
174 for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
175 i != e; ++i)
176 {
177 (*i)->__make_ready();
178 (*i)->__release_shared();
179 }
180}
181
182void
183__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
184{
185 notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
186}
187
188void
189__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
190{
191 async_states_.push_back(__s);
192 __s->__add_shared();
193}
194
195// __thread_struct
196
197__thread_struct::__thread_struct()
198 : __p_(new __thread_struct_imp)
199{
200}
201
202__thread_struct::~__thread_struct()
203{
204 delete __p_;
205}
206
207void
208__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
209{
210 __p_->notify_all_at_thread_exit(cv, m);
211}
212
213void
214__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
215{
216 __p_->__make_ready_at_thread_exit(__s);
217}
218
219_LIBCPP_END_NAMESPACE_STD
220
221#endif // !_LIBCPP_HAS_NO_THREADS
222