xref: /freebsd/contrib/llvm-project/libcxx/src/thread.cpp (revision cfd6422a5217410fbd66f7a7a8a64d9d85e61229)
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 __has_include(<unistd.h>)
27 #include <unistd.h>
28 #endif
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 #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
39 #pragma comment(lib, "pthread")
40 #endif
41 
42 _LIBCPP_BEGIN_NAMESPACE_STD
43 
44 thread::~thread()
45 {
46     if (!__libcpp_thread_isnull(&__t_))
47         terminate();
48 }
49 
50 void
51 thread::join()
52 {
53     int ec = EINVAL;
54     if (!__libcpp_thread_isnull(&__t_))
55     {
56         ec = __libcpp_thread_join(&__t_);
57         if (ec == 0)
58             __t_ = _LIBCPP_NULL_THREAD;
59     }
60 
61     if (ec)
62         __throw_system_error(ec, "thread::join failed");
63 }
64 
65 void
66 thread::detach()
67 {
68     int ec = EINVAL;
69     if (!__libcpp_thread_isnull(&__t_))
70     {
71         ec = __libcpp_thread_detach(&__t_);
72         if (ec == 0)
73             __t_ = _LIBCPP_NULL_THREAD;
74     }
75 
76     if (ec)
77         __throw_system_error(ec, "thread::detach failed");
78 }
79 
80 unsigned
81 thread::hardware_concurrency() _NOEXCEPT
82 {
83 #if defined(CTL_HW) && defined(HW_NCPU)
84     unsigned n;
85     int mib[2] = {CTL_HW, HW_NCPU};
86     std::size_t s = sizeof(n);
87     sysctl(mib, 2, &n, &s, 0, 0);
88     return n;
89 #elif defined(_SC_NPROCESSORS_ONLN)
90     long result = sysconf(_SC_NPROCESSORS_ONLN);
91     // sysconf returns -1 if the name is invalid, the option does not exist or
92     // does not have a definite limit.
93     // if sysconf returns some other negative number, we have no idea
94     // what is going on. Default to something safe.
95     if (result < 0)
96         return 0;
97     return static_cast<unsigned>(result);
98 #elif defined(_LIBCPP_WIN32API)
99     SYSTEM_INFO info;
100     GetSystemInfo(&info);
101     return info.dwNumberOfProcessors;
102 #else  // defined(CTL_HW) && defined(HW_NCPU)
103     // TODO: grovel through /proc or check cpuid on x86 and similar
104     // instructions on other architectures.
105 #   if defined(_LIBCPP_WARNING)
106         _LIBCPP_WARNING("hardware_concurrency not yet implemented")
107 #   else
108 #       warning hardware_concurrency not yet implemented
109 #   endif
110     return 0;  // Means not computable [thread.thread.static]
111 #endif  // defined(CTL_HW) && defined(HW_NCPU)
112 }
113 
114 namespace this_thread
115 {
116 
117 void
118 sleep_for(const chrono::nanoseconds& ns)
119 {
120     if (ns > chrono::nanoseconds::zero())
121     {
122         __libcpp_thread_sleep_for(ns);
123     }
124 }
125 
126 }  // this_thread
127 
128 __thread_specific_ptr<__thread_struct>&
129 __thread_local_data()
130 {
131     static __thread_specific_ptr<__thread_struct> __p;
132     return __p;
133 }
134 
135 // __thread_struct_imp
136 
137 template <class T>
138 class _LIBCPP_HIDDEN __hidden_allocator
139 {
140 public:
141     typedef T  value_type;
142 
143     T* allocate(size_t __n)
144         {return static_cast<T*>(::operator new(__n * sizeof(T)));}
145     void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}
146 
147     size_t max_size() const {return size_t(~0) / sizeof(T);}
148 };
149 
150 class _LIBCPP_HIDDEN __thread_struct_imp
151 {
152     typedef vector<__assoc_sub_state*,
153                           __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
154     typedef vector<pair<condition_variable*, mutex*>,
155                __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
156 
157     _AsyncStates async_states_;
158     _Notify notify_;
159 
160     __thread_struct_imp(const __thread_struct_imp&);
161     __thread_struct_imp& operator=(const __thread_struct_imp&);
162 public:
163     __thread_struct_imp() {}
164     ~__thread_struct_imp();
165 
166     void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
167     void __make_ready_at_thread_exit(__assoc_sub_state* __s);
168 };
169 
170 __thread_struct_imp::~__thread_struct_imp()
171 {
172     for (_Notify::iterator i = notify_.begin(), e = notify_.end();
173             i != e; ++i)
174     {
175         i->second->unlock();
176         i->first->notify_all();
177     }
178     for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
179             i != e; ++i)
180     {
181         (*i)->__make_ready();
182         (*i)->__release_shared();
183     }
184 }
185 
186 void
187 __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
188 {
189     notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
190 }
191 
192 void
193 __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
194 {
195     async_states_.push_back(__s);
196     __s->__add_shared();
197 }
198 
199 // __thread_struct
200 
201 __thread_struct::__thread_struct()
202     : __p_(new __thread_struct_imp)
203 {
204 }
205 
206 __thread_struct::~__thread_struct()
207 {
208     delete __p_;
209 }
210 
211 void
212 __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
213 {
214     __p_->notify_all_at_thread_exit(cv, m);
215 }
216 
217 void
218 __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
219 {
220     __p_->__make_ready_at_thread_exit(__s);
221 }
222 
223 _LIBCPP_END_NAMESPACE_STD
224 
225 #endif // !_LIBCPP_HAS_NO_THREADS
226