]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/src/c++11/thread.cc
libstdc++: Make std::this_thread functions work without gthreads
[thirdparty/gcc.git] / libstdc++-v3 / src / c++11 / thread.cc
CommitLineData
46e113bf
CF
1// thread -*- C++ -*-
2
8d9254fc 3// Copyright (C) 2008-2020 Free Software Foundation, Inc.
46e113bf
CF
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
748086b7 8// Free Software Foundation; either version 3, or (at your option)
46e113bf
CF
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
748086b7
JJ
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
46e113bf 25
ce535a96 26#define _GLIBCXX_THREAD_ABI_COMPAT 1
46e113bf 27#include <thread>
4880236e 28#include <system_error>
cbdab9c8 29#include <cerrno>
5f2862cf 30#include <cxxabi_forced.h>
46e113bf 31
5bbb1f30
JW
32#ifndef _GLIBCXX_USE_NANOSLEEP
33# ifdef _GLIBCXX_HAVE_SLEEP
34# include <unistd.h>
35# elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
36# include <windows.h>
37# else
38# error "No sleep function known for this target"
39# endif
40#endif
41
8ba7f29e 42#ifdef _GLIBCXX_HAS_GTHREADS
aa66b299 43
43653c33
JW
44#if defined(_GLIBCXX_USE_GET_NPROCS)
45# include <sys/sysinfo.h>
46# define _GLIBCXX_NPROCS get_nprocs()
5ee360d0
JW
47#elif defined(_GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP)
48# define _GLIBCXX_NPROCS pthread_num_processors_np()
49#elif defined(_GLIBCXX_USE_SYSCTL_HW_NCPU)
50# include <stddef.h>
51# include <sys/sysctl.h>
52static inline int get_nprocs()
53{
54 int count;
55 size_t size = sizeof(count);
56 int mib[] = { CTL_HW, HW_NCPU };
57 if (!sysctl(mib, 2, &count, &size, NULL, 0))
58 return count;
59 return 0;
60}
61# define _GLIBCXX_NPROCS get_nprocs()
43653c33
JW
62#elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN)
63# include <unistd.h>
64# define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN)
5ee360d0
JW
65#elif defined(_GLIBCXX_USE_SC_NPROC_ONLN)
66# include <unistd.h>
67# define _GLIBCXX_NPROCS sysconf(_SC_NPROC_ONLN)
43653c33
JW
68#else
69# define _GLIBCXX_NPROCS 0
70#endif
71
12ffa228
BK
72namespace std _GLIBCXX_VISIBILITY(default)
73{
87cec93e 74 extern "C"
46e113bf 75 {
87cec93e 76 static void*
d7afcd2b 77 execute_native_thread_routine(void* __p)
ce535a96
JW
78 {
79 thread::_State_ptr __t{ static_cast<thread::_State*>(__p) };
754d67d5 80 __t->_M_run();
ce535a96
JW
81 return nullptr;
82 }
83
84#if _GLIBCXX_THREAD_ABI_COMPAT
87cec93e 85 static void*
ce535a96 86 execute_native_thread_routine_compat(void* __p)
46e113bf 87 {
d7afcd2b
BK
88 thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
89 thread::__shared_base_type __local;
ce535a96
JW
90 // Now that a new thread has been created we can transfer ownership of
91 // the thread state to a local object, breaking the reference cycle
92 // created in thread::_M_start_thread.
d7afcd2b 93 __local.swap(__t->_M_this_ptr);
754d67d5 94 __t->_M_run();
0dc3cba1 95 return nullptr;
46e113bf 96 }
ce535a96 97#endif
87cec93e 98 } // extern "C"
46e113bf 99
12ffa228
BK
100_GLIBCXX_BEGIN_NAMESPACE_VERSION
101
ce535a96
JW
102 thread::_State::~_State() = default;
103
46e113bf
CF
104 void
105 thread::join()
106 {
cbdab9c8 107 int __e = EINVAL;
46e113bf 108
626dda69 109 if (_M_id != id())
8fc81078 110 __e = __gthread_join(_M_id._M_thread, 0);
cbdab9c8
JW
111
112 if (__e)
113 __throw_system_error(__e);
114
626dda69 115 _M_id = id();
46e113bf
CF
116 }
117
118 void
119 thread::detach()
d7afcd2b 120 {
cbdab9c8 121 int __e = EINVAL;
46e113bf 122
626dda69
CF
123 if (_M_id != id())
124 __e = __gthread_detach(_M_id._M_thread);
cbdab9c8
JW
125
126 if (__e)
127 __throw_system_error(__e);
128
626dda69 129 _M_id = id();
46e113bf
CF
130 }
131
ce535a96
JW
132 void
133 thread::_M_start_thread(_State_ptr state, void (*)())
134 {
135 const int err = __gthread_create(&_M_id._M_thread,
136 &execute_native_thread_routine,
137 state.get());
138 if (err)
139 __throw_system_error(err);
140 state.release();
141 }
142
143#if _GLIBCXX_THREAD_ABI_COMPAT
d7afcd2b 144 void
626dda69 145 thread::_M_start_thread(__shared_base_type __b)
46e113bf 146 {
45ed58a8 147 if (!__gthread_active_p())
0f3d27f0 148#if __cpp_exceptions
3722862e
JW
149 throw system_error(make_error_code(errc::operation_not_permitted),
150 "Enable multithreading to use std::thread");
151#else
45ed58a8 152 __throw_system_error(int(errc::operation_not_permitted));
3722862e 153#endif
45ed58a8 154
0dc3cba1 155 _M_start_thread(std::move(__b), nullptr);
c6b3f349
JW
156 }
157
158 void
159 thread::_M_start_thread(__shared_base_type __b, void (*)())
160 {
0dc3cba1 161 auto ptr = __b.get();
ce535a96 162 // Create a reference cycle that will be broken in the new thread.
0dc3cba1 163 ptr->_M_this_ptr = std::move(__b);
626dda69 164 int __e = __gthread_create(&_M_id._M_thread,
ce535a96 165 &execute_native_thread_routine_compat, ptr);
cbdab9c8
JW
166 if (__e)
167 {
ce535a96 168 ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr.
46e113bf 169 __throw_system_error(__e);
cbdab9c8 170 }
46e113bf 171 }
ce535a96 172#endif
53dc5044 173
43653c33
JW
174 unsigned int
175 thread::hardware_concurrency() noexcept
176 {
177 int __n = _GLIBCXX_NPROCS;
178 if (__n < 0)
179 __n = 0;
180 return __n;
181 }
182
5bbb1f30
JW
183_GLIBCXX_END_NAMESPACE_VERSION
184} // namespace std
185
186#endif // _GLIBCXX_HAS_GTHREADS
187
188namespace std _GLIBCXX_VISIBILITY(default)
189{
190_GLIBCXX_BEGIN_NAMESPACE_VERSION
aa66b299
JW
191namespace this_thread
192{
aa66b299
JW
193 void
194 __sleep_for(chrono::seconds __s, chrono::nanoseconds __ns)
195 {
196#ifdef _GLIBCXX_USE_NANOSLEEP
5bbb1f30 197 struct ::timespec __ts =
aa66b299
JW
198 {
199 static_cast<std::time_t>(__s.count()),
200 static_cast<long>(__ns.count())
201 };
f55e699d
JW
202 while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
203 { }
8ed812cc 204#elif defined(_GLIBCXX_HAVE_SLEEP)
cfef4c32
JW
205 const auto target = chrono::steady_clock::now() + __s + __ns;
206 while (true)
aa66b299 207 {
cfef4c32
JW
208 unsigned secs = __s.count();
209 if (__ns.count() > 0)
210 {
211# ifdef _GLIBCXX_HAVE_USLEEP
212 long us = __ns.count() / 1000;
213 if (us == 0)
214 us = 1;
215 ::usleep(us);
8ed812cc 216# else
cfef4c32
JW
217 if (__ns.count() > 1000000 || secs == 0)
218 ++secs; // No sub-second sleep function, so round up.
aa66b299 219# endif
cfef4c32
JW
220 }
221
222 if (secs > 0)
223 {
224 // Sleep in a loop to handle interruption by signals:
225 while ((secs = ::sleep(secs)))
226 { }
227 }
228 const auto now = chrono::steady_clock::now();
229 if (now >= target)
230 break;
231 __s = chrono::duration_cast<chrono::seconds>(target - now);
232 __ns = chrono::duration_cast<chrono::nanoseconds>(target - (now + __s));
233 }
8ed812cc
JW
234#elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
235 unsigned long ms = __ns.count() / 1000000;
236 if (__ns.count() > 0 && ms == 0)
237 ms = 1;
238 ::Sleep(chrono::milliseconds(__s).count() + ms);
aa66b299
JW
239#endif
240 }
aa66b299 241}
4a15d842 242_GLIBCXX_END_NAMESPACE_VERSION
12ffa228 243} // namespace std