1 // thread -*- C++ -*- 2 3 // Copyright (C) 2008-2016 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 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) 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 81 __try 82 { 83 __t->_M_run(); 84 } 85 __catch(const __cxxabiv1::__forced_unwind&) 86 { 87 __throw_exception_again; 88 } 89 __catch(...) 90 { 91 std::terminate(); 92 } 93 94 return nullptr; 95 } 96 97 #if _GLIBCXX_THREAD_ABI_COMPAT 98 static void* 99 execute_native_thread_routine_compat(void* __p) 100 { 101 thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p); 102 thread::__shared_base_type __local; 103 // Now that a new thread has been created we can transfer ownership of 104 // the thread state to a local object, breaking the reference cycle 105 // created in thread::_M_start_thread. 106 __local.swap(__t->_M_this_ptr); 107 108 __try 109 { 110 __t->_M_run(); 111 } 112 __catch(const __cxxabiv1::__forced_unwind&) 113 { 114 __throw_exception_again; 115 } 116 __catch(...) 117 { 118 std::terminate(); 119 } 120 121 return nullptr; 122 } 123 #endif 124 } // extern "C" 125 126 _GLIBCXX_BEGIN_NAMESPACE_VERSION 127 128 thread::_State::~_State() = default; 129 130 void 131 thread::join() 132 { 133 int __e = EINVAL; 134 135 if (_M_id != id()) 136 __e = __gthread_join(_M_id._M_thread, 0); 137 138 if (__e) 139 __throw_system_error(__e); 140 141 _M_id = id(); 142 } 143 144 void 145 thread::detach() 146 { 147 int __e = EINVAL; 148 149 if (_M_id != id()) 150 __e = __gthread_detach(_M_id._M_thread); 151 152 if (__e) 153 __throw_system_error(__e); 154 155 _M_id = id(); 156 } 157 158 void 159 thread::_M_start_thread(_State_ptr state, void (*)()) 160 { 161 const int err = __gthread_create(&_M_id._M_thread, 162 &execute_native_thread_routine, 163 state.get()); 164 if (err) 165 __throw_system_error(err); 166 state.release(); 167 } 168 169 #if _GLIBCXX_THREAD_ABI_COMPAT 170 void 171 thread::_M_start_thread(__shared_base_type __b) 172 { 173 if (!__gthread_active_p()) 174 #if __cpp_exceptions 175 throw system_error(make_error_code(errc::operation_not_permitted), 176 "Enable multithreading to use std::thread"); 177 #else 178 __throw_system_error(int(errc::operation_not_permitted)); 179 #endif 180 181 _M_start_thread(std::move(__b), nullptr); 182 } 183 184 void 185 thread::_M_start_thread(__shared_base_type __b, void (*)()) 186 { 187 auto ptr = __b.get(); 188 // Create a reference cycle that will be broken in the new thread. 189 ptr->_M_this_ptr = std::move(__b); 190 int __e = __gthread_create(&_M_id._M_thread, 191 &execute_native_thread_routine_compat, ptr); 192 if (__e) 193 { 194 ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr. 195 __throw_system_error(__e); 196 } 197 } 198 #endif 199 200 unsigned int 201 thread::hardware_concurrency() noexcept 202 { 203 int __n = _GLIBCXX_NPROCS; 204 if (__n < 0) 205 __n = 0; 206 return __n; 207 } 208 209 _GLIBCXX_END_NAMESPACE_VERSION 210 211 namespace this_thread 212 { 213 _GLIBCXX_BEGIN_NAMESPACE_VERSION 214 215 void 216 __sleep_for(chrono::seconds __s, chrono::nanoseconds __ns) 217 { 218 #ifdef _GLIBCXX_USE_NANOSLEEP 219 __gthread_time_t __ts = 220 { 221 static_cast<std::time_t>(__s.count()), 222 static_cast<long>(__ns.count()) 223 }; 224 while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) 225 { } 226 #elif defined(_GLIBCXX_HAVE_SLEEP) 227 # ifdef _GLIBCXX_HAVE_USLEEP 228 ::sleep(__s.count()); 229 if (__ns.count() > 0) 230 { 231 long __us = __ns.count() / 1000; 232 if (__us == 0) 233 __us = 1; 234 ::usleep(__us); 235 } 236 # else 237 ::sleep(__s.count() + (__ns.count() >= 1000000)); 238 # endif 239 #elif defined(_GLIBCXX_HAVE_WIN32_SLEEP) 240 unsigned long ms = __ns.count() / 1000000; 241 if (__ns.count() > 0 && ms == 0) 242 ms = 1; 243 ::Sleep(chrono::milliseconds(__s).count() + ms); 244 #endif 245 } 246 247 _GLIBCXX_END_NAMESPACE_VERSION 248 } 249 250 } // namespace std 251 252 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 253