]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/src/c++11/thread.cc
[PATCH] RISC-V: Fix unresolved mcpu-[67].c tests
[thirdparty/gcc.git] / libstdc++-v3 / src / c++11 / thread.cc
1 // thread -*- C++ -*-
2
3 // Copyright (C) 2008-2024 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24
25
26 #define _GLIBCXX_THREAD_ABI_COMPAT 1
27 #define _GLIBCXX_THREAD_IMPL 1
28 #include <memory> // include this first so <thread> can use shared_ptr
29 #include <thread>
30 #include <system_error>
31 #include <cerrno>
32 #include <cxxabi_forced.h>
33
34 #ifndef _GLIBCXX_USE_NANOSLEEP
35 # ifdef _GLIBCXX_HAVE_SLEEP
36 # include <unistd.h>
37 # elif defined(_GLIBCXX_USE_WIN32_SLEEP)
38 # define WIN32_LEAN_AND_MEAN
39 # include <windows.h>
40 # elif defined _GLIBCXX_NO_SLEEP && defined _GLIBCXX_HAS_GTHREADS
41 // We expect to be able to sleep for targets that support multiple threads:
42 # error "No sleep function known for this target"
43 # endif
44 #endif
45
46 #ifdef _GLIBCXX_HAS_GTHREADS
47
48 #if defined(_GLIBCXX_USE_GET_NPROCS)
49 # include <sys/sysinfo.h>
50 # define _GLIBCXX_NPROCS get_nprocs()
51 #elif defined(_GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP)
52 # define _GLIBCXX_NPROCS pthread_num_processors_np()
53 #elif defined(_GLIBCXX_USE_SYSCTL_HW_NCPU)
54 # include <stddef.h>
55 # include <sys/sysctl.h>
56 static inline int get_nprocs()
57 {
58 int count;
59 size_t size = sizeof(count);
60 int mib[] = { CTL_HW, HW_NCPU };
61 if (!sysctl(mib, 2, &count, &size, NULL, 0))
62 return count;
63 return 0;
64 }
65 # define _GLIBCXX_NPROCS get_nprocs()
66 #elif defined(_GLIBCXX_USE_GET_NPROCS_WIN32)
67 # define WIN32_LEAN_AND_MEAN
68 # include <windows.h>
69 static inline int get_nprocs()
70 {
71 SYSTEM_INFO sysinfo;
72 GetSystemInfo (&sysinfo);
73 return (int)sysinfo.dwNumberOfProcessors;
74 }
75 # define _GLIBCXX_NPROCS get_nprocs()
76 #elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN)
77 # include <unistd.h>
78 # define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN)
79 #elif defined(_GLIBCXX_USE_SC_NPROC_ONLN)
80 # include <unistd.h>
81 # define _GLIBCXX_NPROCS sysconf(_SC_NPROC_ONLN)
82 #elif defined(_WIN32)
83 # define WIN32_LEAN_AND_MEAN
84 # include <windows.h>
85 static inline int get_nprocs()
86 {
87 SYSTEM_INFO sysinfo;
88 GetSystemInfo(&sysinfo);
89 return (int) sysinfo.dwNumberOfProcessors;
90 }
91 # define _GLIBCXX_NPROCS get_nprocs()
92 #else
93 # define _GLIBCXX_NPROCS 0
94 #endif
95
96 namespace std _GLIBCXX_VISIBILITY(default)
97 {
98 extern "C"
99 {
100 static void*
101 execute_native_thread_routine(void* __p)
102 {
103 thread::_State_ptr __t{ static_cast<thread::_State*>(__p) };
104 __t->_M_run();
105 return nullptr;
106 }
107
108 #if _GLIBCXX_THREAD_ABI_COMPAT
109 static void*
110 execute_native_thread_routine_compat(void* __p)
111 {
112 thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
113 thread::__shared_base_type __local;
114 // Now that a new thread has been created we can transfer ownership of
115 // the thread state to a local object, breaking the reference cycle
116 // created in thread::_M_start_thread.
117 __local.swap(__t->_M_this_ptr);
118 __t->_M_run();
119 return nullptr;
120 }
121 #endif
122 } // extern "C"
123
124 _GLIBCXX_BEGIN_NAMESPACE_VERSION
125
126 thread::_State::~_State() = default;
127
128 void
129 thread::join()
130 {
131 int __e = EINVAL;
132
133 if (_M_id != id())
134 __e = __gthread_join(_M_id._M_thread, 0);
135
136 if (__e)
137 __throw_system_error(__e);
138
139 _M_id = id();
140 }
141
142 void
143 thread::detach()
144 {
145 int __e = EINVAL;
146
147 if (_M_id != id())
148 __e = __gthread_detach(_M_id._M_thread);
149
150 if (__e)
151 __throw_system_error(__e);
152
153 _M_id = id();
154 }
155
156 void
157 thread::_M_start_thread(_State_ptr state, void (*depend)())
158 {
159 // Make sure it's not optimized out, not even with LTO.
160 asm ("" : : "rm" (depend));
161
162 if (!__gthread_active_p())
163 {
164 #if __cpp_exceptions
165 throw system_error(make_error_code(errc::operation_not_permitted),
166 "Enable multithreading to use std::thread");
167 #else
168 __builtin_abort();
169 #endif
170 }
171
172 const int err = __gthread_create(&_M_id._M_thread,
173 &execute_native_thread_routine,
174 state.get());
175 if (err)
176 __throw_system_error(err);
177 state.release();
178 }
179
180 #if _GLIBCXX_THREAD_ABI_COMPAT
181 void
182 thread::_M_start_thread(__shared_base_type __b)
183 {
184 if (!__gthread_active_p())
185 #if __cpp_exceptions
186 throw system_error(make_error_code(errc::operation_not_permitted),
187 "Enable multithreading to use std::thread");
188 #else
189 __throw_system_error(int(errc::operation_not_permitted));
190 #endif
191
192 _M_start_thread(std::move(__b), nullptr);
193 }
194
195 void
196 thread::_M_start_thread(__shared_base_type __b, void (*depend)())
197 {
198 // Make sure it's not optimized out, not even with LTO.
199 asm ("" : : "rm" (depend));
200
201 auto ptr = __b.get();
202 // Create a reference cycle that will be broken in the new thread.
203 ptr->_M_this_ptr = std::move(__b);
204 int __e = __gthread_create(&_M_id._M_thread,
205 &execute_native_thread_routine_compat, ptr);
206 if (__e)
207 {
208 ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr.
209 __throw_system_error(__e);
210 }
211 }
212 #endif
213
214 unsigned int
215 thread::hardware_concurrency() noexcept
216 {
217 int __n = _GLIBCXX_NPROCS;
218 if (__n < 0)
219 __n = 0;
220 return __n;
221 }
222
223 _GLIBCXX_END_NAMESPACE_VERSION
224 } // namespace std
225
226 #endif // _GLIBCXX_HAS_GTHREADS
227
228 #ifndef _GLIBCXX_NO_SLEEP
229 namespace std _GLIBCXX_VISIBILITY(default)
230 {
231 _GLIBCXX_BEGIN_NAMESPACE_VERSION
232 namespace this_thread
233 {
234 void
235 __sleep_for(chrono::seconds __s, chrono::nanoseconds __ns)
236 {
237 #ifdef _GLIBCXX_USE_NANOSLEEP
238 struct ::timespec __ts =
239 {
240 static_cast<std::time_t>(__s.count()),
241 static_cast<long>(__ns.count())
242 };
243 while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
244 { }
245 #elif defined(_GLIBCXX_HAVE_SLEEP)
246 const auto target = chrono::steady_clock::now() + __s + __ns;
247 while (true)
248 {
249 unsigned secs = __s.count();
250 if (__ns.count() > 0)
251 {
252 # ifdef _GLIBCXX_HAVE_USLEEP
253 long us = __ns.count() / 1000;
254 if (us == 0)
255 us = 1;
256 ::usleep(us);
257 # else
258 if (__ns.count() > 1000000 || secs == 0)
259 ++secs; // No sub-second sleep function, so round up.
260 # endif
261 }
262
263 if (secs > 0)
264 {
265 // Sleep in a loop to handle interruption by signals:
266 while ((secs = ::sleep(secs)))
267 { }
268 }
269 const auto now = chrono::steady_clock::now();
270 if (now >= target)
271 break;
272 __s = chrono::duration_cast<chrono::seconds>(target - now);
273 __ns = chrono::duration_cast<chrono::nanoseconds>(target - (now + __s));
274 }
275 #elif defined(_GLIBCXX_USE_WIN32_SLEEP)
276 unsigned long ms = __ns.count() / 1000000;
277 if (__ns.count() > 0 && ms == 0)
278 ms = 1;
279 ::Sleep(chrono::milliseconds(__s).count() + ms);
280 #endif
281 }
282 }
283 _GLIBCXX_END_NAMESPACE_VERSION
284 } // namespace std
285 #endif // ! NO_SLEEP