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