1 // thread -*- C++ -*- 2 3 // Copyright (C) 2008-2018 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 __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 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 144 void 145 thread::_M_start_thread(__shared_base_type __b) 146 { 147 if (!__gthread_active_p()) 148 #if __cpp_exceptions 149 throw system_error(make_error_code(errc::operation_not_permitted), 150 "Enable multithreading to use std::thread"); 151 #else 152 __throw_system_error(int(errc::operation_not_permitted)); 153 #endif 154 155 _M_start_thread(std::move(__b), nullptr); 156 } 157 158 void 159 thread::_M_start_thread(__shared_base_type __b, void (*)()) 160 { 161 auto ptr = __b.get(); 162 // Create a reference cycle that will be broken in the new thread. 163 ptr->_M_this_ptr = std::move(__b); 164 int __e = __gthread_create(&_M_id._M_thread, 165 &execute_native_thread_routine_compat, ptr); 166 if (__e) 167 { 168 ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr. 169 __throw_system_error(__e); 170 } 171 } 172 #endif 173 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 183 namespace this_thread 184 { 185 void 186 __sleep_for(chrono::seconds __s, chrono::nanoseconds __ns) 187 { 188 #ifdef _GLIBCXX_USE_NANOSLEEP 189 __gthread_time_t __ts = 190 { 191 static_cast<std::time_t>(__s.count()), 192 static_cast<long>(__ns.count()) 193 }; 194 while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) 195 { } 196 #elif defined(_GLIBCXX_HAVE_SLEEP) 197 # ifdef _GLIBCXX_HAVE_USLEEP 198 ::sleep(__s.count()); 199 if (__ns.count() > 0) 200 { 201 long __us = __ns.count() / 1000; 202 if (__us == 0) 203 __us = 1; 204 ::usleep(__us); 205 } 206 # else 207 ::sleep(__s.count() + (__ns.count() >= 1000000)); 208 # endif 209 #elif defined(_GLIBCXX_HAVE_WIN32_SLEEP) 210 unsigned long ms = __ns.count() / 1000000; 211 if (__ns.count() > 0 && ms == 0) 212 ms = 1; 213 ::Sleep(chrono::milliseconds(__s).count() + ms); 214 #endif 215 } 216 } 217 218 _GLIBCXX_END_NAMESPACE_VERSION 219 } // namespace std 220 221 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 222