1 //===------------------------- thread.cpp----------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "thread" 11 #include "exception" 12 #include "vector" 13 #include "future" 14 #include "limits" 15 #include <sys/types.h> 16 #if !_WIN32 17 #if !__sun__ && !__linux__ 18 #include <sys/sysctl.h> 19 #else 20 #include <unistd.h> 21 #endif // !__sun__ && !__linux__ 22 #endif // !_WIN32 23 24 _LIBCPP_BEGIN_NAMESPACE_STD 25 26 thread::~thread() 27 { 28 if (__t_ != 0) 29 terminate(); 30 } 31 32 void 33 thread::join() 34 { 35 int ec = pthread_join(__t_, 0); 36 #ifndef _LIBCPP_NO_EXCEPTIONS 37 if (ec) 38 throw system_error(error_code(ec, system_category()), "thread::join failed"); 39 #endif // _LIBCPP_NO_EXCEPTIONS 40 __t_ = 0; 41 } 42 43 void 44 thread::detach() 45 { 46 int ec = EINVAL; 47 if (__t_ != 0) 48 { 49 ec = pthread_detach(__t_); 50 if (ec == 0) 51 __t_ = 0; 52 } 53 #ifndef _LIBCPP_NO_EXCEPTIONS 54 if (ec) 55 throw system_error(error_code(ec, system_category()), "thread::detach failed"); 56 #endif // _LIBCPP_NO_EXCEPTIONS 57 } 58 59 unsigned 60 thread::hardware_concurrency() _NOEXCEPT 61 { 62 #if defined(CTL_HW) && defined(HW_NCPU) 63 unsigned n; 64 int mib[2] = {CTL_HW, HW_NCPU}; 65 std::size_t s = sizeof(n); 66 sysctl(mib, 2, &n, &s, 0, 0); 67 return n; 68 #elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) && defined(_SC_NPROCESSORS_ONLN) 69 long result = sysconf(_SC_NPROCESSORS_ONLN); 70 if (result < 0 || result > UINT_MAX) 71 result = 0; 72 return result; 73 #else // defined(CTL_HW) && defined(HW_NCPU) 74 // TODO: grovel through /proc or check cpuid on x86 and similar 75 // instructions on other architectures. 76 return 0; // Means not computable [thread.thread.static] 77 #endif // defined(CTL_HW) && defined(HW_NCPU) 78 } 79 80 namespace this_thread 81 { 82 83 void 84 sleep_for(const chrono::nanoseconds& ns) 85 { 86 using namespace chrono; 87 if (ns > nanoseconds::zero()) 88 { 89 seconds s = duration_cast<seconds>(ns); 90 timespec ts; 91 typedef decltype(ts.tv_sec) ts_sec; 92 _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max(); 93 if (s.count() < ts_sec_max) 94 { 95 ts.tv_sec = static_cast<ts_sec>(s.count()); 96 ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count()); 97 } 98 else 99 { 100 ts.tv_sec = ts_sec_max; 101 ts.tv_nsec = giga::num - 1; 102 } 103 nanosleep(&ts, 0); 104 } 105 } 106 107 } // this_thread 108 109 __thread_specific_ptr<__thread_struct>& 110 __thread_local_data() 111 { 112 static __thread_specific_ptr<__thread_struct> __p; 113 return __p; 114 } 115 116 // __thread_struct_imp 117 118 template <class T> 119 class _LIBCPP_HIDDEN __hidden_allocator 120 { 121 public: 122 typedef T value_type; 123 124 T* allocate(size_t __n) 125 {return static_cast<T*>(::operator new(__n * sizeof(T)));} 126 void deallocate(T* __p, size_t) {::operator delete((void*)__p);} 127 128 size_t max_size() const {return size_t(~0) / sizeof(T);} 129 }; 130 131 class _LIBCPP_HIDDEN __thread_struct_imp 132 { 133 typedef vector<__assoc_sub_state*, 134 __hidden_allocator<__assoc_sub_state*> > _AsyncStates; 135 typedef vector<pair<condition_variable*, mutex*>, 136 __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify; 137 138 _AsyncStates async_states_; 139 _Notify notify_; 140 141 __thread_struct_imp(const __thread_struct_imp&); 142 __thread_struct_imp& operator=(const __thread_struct_imp&); 143 public: 144 __thread_struct_imp() {} 145 ~__thread_struct_imp(); 146 147 void notify_all_at_thread_exit(condition_variable* cv, mutex* m); 148 void __make_ready_at_thread_exit(__assoc_sub_state* __s); 149 }; 150 151 __thread_struct_imp::~__thread_struct_imp() 152 { 153 for (_Notify::iterator i = notify_.begin(), e = notify_.end(); 154 i != e; ++i) 155 { 156 i->second->unlock(); 157 i->first->notify_all(); 158 } 159 for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end(); 160 i != e; ++i) 161 { 162 (*i)->__make_ready(); 163 (*i)->__release_shared(); 164 } 165 } 166 167 void 168 __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m) 169 { 170 notify_.push_back(pair<condition_variable*, mutex*>(cv, m)); 171 } 172 173 void 174 __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s) 175 { 176 async_states_.push_back(__s); 177 __s->__add_shared(); 178 } 179 180 // __thread_struct 181 182 __thread_struct::__thread_struct() 183 : __p_(new __thread_struct_imp) 184 { 185 } 186 187 __thread_struct::~__thread_struct() 188 { 189 delete __p_; 190 } 191 192 void 193 __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m) 194 { 195 __p_->notify_all_at_thread_exit(cv, m); 196 } 197 198 void 199 __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) 200 { 201 __p_->__make_ready_at_thread_exit(__s); 202 } 203 204 _LIBCPP_END_NAMESPACE_STD 205