1 #ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP 2 #define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 // (C) Copyright 2007 Anthony Williams 7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba 8 9 #include <boost/thread/detail/config.hpp> 10 #include <boost/thread/exceptions.hpp> 11 #include <boost/thread/lock_guard.hpp> 12 #include <boost/thread/lock_types.hpp> 13 #include <boost/thread/mutex.hpp> 14 #include <boost/thread/pthread/condition_variable_fwd.hpp> 15 #include <boost/thread/pthread/pthread_helpers.hpp> 16 17 #include <boost/shared_ptr.hpp> 18 #include <boost/enable_shared_from_this.hpp> 19 #include <boost/assert.hpp> 20 #include <boost/thread/detail/platform_time.hpp> 21 #ifdef BOOST_THREAD_USES_CHRONO 22 #include <boost/chrono/system_clocks.hpp> 23 #endif 24 25 #include <map> 26 #include <vector> 27 #include <utility> 28 29 #if defined(__ANDROID__) 30 # ifndef PAGE_SIZE 31 # define PAGE_SIZE 4096 32 # endif 33 #endif 34 35 #include <pthread.h> 36 #include <unistd.h> 37 38 #include <boost/config/abi_prefix.hpp> 39 40 namespace boost 41 { 42 class thread_attributes { 43 public: thread_attributes()44 thread_attributes() BOOST_NOEXCEPT { 45 int res = pthread_attr_init(&val_); 46 BOOST_VERIFY(!res && "pthread_attr_init failed"); 47 } ~thread_attributes()48 ~thread_attributes() { 49 int res = pthread_attr_destroy(&val_); 50 BOOST_VERIFY(!res && "pthread_attr_destroy failed"); 51 } 52 // stack set_stack_size(std::size_t size)53 void set_stack_size(std::size_t size) BOOST_NOEXCEPT { 54 if (size==0) return; 55 #ifdef BOOST_THREAD_USES_GETPAGESIZE 56 std::size_t page_size = getpagesize(); 57 #else 58 std::size_t page_size = ::sysconf( _SC_PAGESIZE); 59 #endif 60 #ifdef PTHREAD_STACK_MIN 61 if (size<PTHREAD_STACK_MIN) size=PTHREAD_STACK_MIN; 62 #endif 63 size = ((size+page_size-1)/page_size)*page_size; 64 int res = pthread_attr_setstacksize(&val_, size); 65 BOOST_VERIFY(!res && "pthread_attr_setstacksize failed"); 66 } 67 get_stack_size() const68 std::size_t get_stack_size() const BOOST_NOEXCEPT { 69 std::size_t size; 70 int res = pthread_attr_getstacksize(&val_, &size); 71 BOOST_VERIFY(!res && "pthread_attr_getstacksize failed"); 72 return size; 73 } 74 #define BOOST_THREAD_DEFINES_THREAD_ATTRIBUTES_NATIVE_HANDLE 75 76 typedef pthread_attr_t native_handle_type; native_handle()77 native_handle_type* native_handle() BOOST_NOEXCEPT { 78 return &val_; 79 } native_handle() const80 const native_handle_type* native_handle() const BOOST_NOEXCEPT { 81 return &val_; 82 } 83 84 private: 85 pthread_attr_t val_; 86 }; 87 88 class thread; 89 90 namespace detail 91 { 92 struct shared_state_base; 93 struct tss_cleanup_function; 94 struct thread_exit_callback_node; 95 struct tss_data_node 96 { 97 typedef void(*cleanup_func_t)(void*); 98 typedef void(*cleanup_caller_t)(cleanup_func_t, void*); 99 100 cleanup_caller_t caller; 101 cleanup_func_t func; 102 void* value; 103 tss_data_nodeboost::detail::tss_data_node104 tss_data_node(cleanup_caller_t caller_,cleanup_func_t func_,void* value_): 105 caller(caller_),func(func_),value(value_) 106 {} 107 }; 108 109 struct thread_data_base; 110 typedef boost::shared_ptr<thread_data_base> thread_data_ptr; 111 112 struct BOOST_THREAD_DECL thread_data_base: 113 enable_shared_from_this<thread_data_base> 114 { 115 thread_data_ptr self; 116 pthread_t thread_handle; 117 boost::mutex data_mutex; 118 boost::condition_variable done_condition; 119 bool done; 120 bool join_started; 121 bool joined; 122 boost::detail::thread_exit_callback_node* thread_exit_callbacks; 123 std::map<void const*,boost::detail::tss_data_node> tss_data; 124 125 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 126 // These data must be at the end so that the access to the other fields doesn't change 127 // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. 128 // Another option is to have them always 129 pthread_mutex_t* cond_mutex; 130 pthread_cond_t* current_cond; 131 //#endif 132 typedef std::vector<std::pair<condition_variable*, mutex*> 133 //, hidden_allocator<std::pair<condition_variable*, mutex*> > 134 > notify_list_t; 135 notify_list_t notify; 136 137 //#ifndef BOOST_NO_EXCEPTIONS 138 typedef std::vector<shared_ptr<shared_state_base> > async_states_t; 139 async_states_t async_states_; 140 //#endif 141 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 142 // These data must be at the end so that the access to the other fields doesn't change 143 // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. 144 // Another option is to have them always 145 bool interrupt_enabled; 146 bool interrupt_requested; 147 //#endif thread_data_baseboost::detail::thread_data_base148 thread_data_base(): 149 thread_handle(0), 150 done(false),join_started(false),joined(false), 151 thread_exit_callbacks(0), 152 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 153 cond_mutex(0), 154 current_cond(0), 155 //#endif 156 notify() 157 //#ifndef BOOST_NO_EXCEPTIONS 158 , async_states_() 159 //#endif 160 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 161 , interrupt_enabled(true) 162 , interrupt_requested(false) 163 //#endif 164 {} 165 virtual ~thread_data_base(); 166 167 typedef pthread_t native_handle_type; 168 169 virtual void run()=0; notify_all_at_thread_exitboost::detail::thread_data_base170 virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m) 171 { 172 notify.push_back(std::pair<condition_variable*, mutex*>(cv, m)); 173 } 174 175 //#ifndef BOOST_NO_EXCEPTIONS make_ready_at_thread_exitboost::detail::thread_data_base176 void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) 177 { 178 async_states_.push_back(as); 179 } 180 //#endif 181 }; 182 183 BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); 184 185 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 186 class interruption_checker 187 { 188 thread_data_base* const thread_info; 189 pthread_mutex_t* m; 190 bool set; 191 bool done; 192 check_for_interruption()193 void check_for_interruption() 194 { 195 #ifndef BOOST_NO_EXCEPTIONS 196 if(thread_info->interrupt_requested) 197 { 198 thread_info->interrupt_requested=false; 199 throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected 200 } 201 #endif 202 } 203 204 void operator=(interruption_checker&); 205 public: interruption_checker(pthread_mutex_t * cond_mutex,pthread_cond_t * cond)206 explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond): 207 thread_info(detail::get_current_thread_data()),m(cond_mutex), 208 set(thread_info && thread_info->interrupt_enabled), done(false) 209 { 210 if(set) 211 { 212 lock_guard<mutex> guard(thread_info->data_mutex); 213 check_for_interruption(); 214 thread_info->cond_mutex=cond_mutex; 215 thread_info->current_cond=cond; 216 BOOST_VERIFY(!posix::pthread_mutex_lock(m)); 217 } 218 else 219 { 220 BOOST_VERIFY(!posix::pthread_mutex_lock(m)); 221 } 222 } unlock_if_locked()223 void unlock_if_locked() 224 { 225 if ( ! done) { 226 if (set) 227 { 228 BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); 229 lock_guard<mutex> guard(thread_info->data_mutex); 230 thread_info->cond_mutex=NULL; 231 thread_info->current_cond=NULL; 232 } 233 else 234 { 235 BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); 236 } 237 done = true; 238 } 239 } 240 BOOST_NOEXCEPT_IF(false)241 ~interruption_checker() BOOST_NOEXCEPT_IF(false) 242 { 243 unlock_if_locked(); 244 } 245 }; 246 #endif 247 } 248 249 namespace this_thread 250 { 251 void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; 252 253 namespace hidden 254 { always_false()255 inline bool always_false() 256 { 257 return false; 258 } 259 } 260 261 #if defined BOOST_THREAD_USES_DATETIME 262 #ifdef __DECXXX 263 /// Workaround of DECCXX issue of incorrect template substitution 264 template<> 265 #endif sleep(system_time const & abs_time)266 inline void sleep(system_time const& abs_time) 267 { 268 mutex mx; 269 unique_lock<mutex> lock(mx); 270 condition_variable cond; 271 cond.timed_wait(lock, abs_time, hidden::always_false); 272 } 273 274 template<typename TimeDuration> sleep(TimeDuration const & rel_time)275 void sleep(TimeDuration const& rel_time) 276 { 277 mutex mx; 278 unique_lock<mutex> lock(mx); 279 condition_variable cond; 280 cond.timed_wait(lock, rel_time, hidden::always_false); 281 } 282 #endif 283 284 #ifdef BOOST_THREAD_USES_CHRONO 285 template <class Clock, class Duration> sleep_until(const chrono::time_point<Clock,Duration> & t)286 void sleep_until(const chrono::time_point<Clock, Duration>& t) 287 { 288 mutex mut; 289 unique_lock<mutex> lk(mut); 290 condition_variable cv; 291 cv.wait_until(lk, t, hidden::always_false); 292 } 293 294 template <class Rep, class Period> sleep_for(const chrono::duration<Rep,Period> & d)295 void sleep_for(const chrono::duration<Rep, Period>& d) 296 { 297 mutex mut; 298 unique_lock<mutex> lk(mut); 299 condition_variable cv; 300 cv.wait_for(lk, d, hidden::always_false); 301 } 302 #endif 303 304 namespace no_interruption_point 305 { 306 #if defined BOOST_THREAD_SLEEP_FOR_IS_STEADY 307 // Use pthread_delay_np or nanosleep when available 308 // because they do not provide an interruption point. 309 310 namespace hidden 311 { 312 void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts); 313 } 314 315 #if defined BOOST_THREAD_USES_DATETIME 316 #ifdef __DECXXX 317 /// Workaround of DECCXX issue of incorrect template substitution 318 template<> 319 #endif sleep(system_time const & abs_time)320 inline void sleep(system_time const& abs_time) 321 { 322 const detail::real_platform_timepoint ts(abs_time); 323 detail::platform_duration d(ts - detail::real_platform_clock::now()); 324 while (d > detail::platform_duration::zero()) 325 { 326 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 327 hidden::sleep_for_internal(d); 328 d = ts - detail::real_platform_clock::now(); 329 } 330 } 331 332 template<typename TimeDuration> sleep(TimeDuration const & rel_time)333 void sleep(TimeDuration const& rel_time) 334 { 335 hidden::sleep_for_internal(detail::platform_duration(rel_time)); 336 } 337 #endif 338 339 #ifdef BOOST_THREAD_USES_CHRONO 340 template <class Rep, class Period> sleep_for(const chrono::duration<Rep,Period> & d)341 void sleep_for(const chrono::duration<Rep, Period>& d) 342 { 343 hidden::sleep_for_internal(detail::platform_duration(d)); 344 } 345 346 template <class Duration> sleep_until(const chrono::time_point<chrono::steady_clock,Duration> & t)347 void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t) 348 { 349 sleep_for(t - chrono::steady_clock::now()); 350 } 351 352 template <class Clock, class Duration> sleep_until(const chrono::time_point<Clock,Duration> & t)353 void sleep_until(const chrono::time_point<Clock, Duration>& t) 354 { 355 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 356 common_duration d(t - Clock::now()); 357 while (d > common_duration::zero()) 358 { 359 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 360 hidden::sleep_for_internal(detail::platform_duration(d)); 361 d = t - Clock::now(); 362 } 363 } 364 #endif 365 366 #else // BOOST_THREAD_SLEEP_FOR_IS_STEADY 367 // When pthread_delay_np and nanosleep are not available, 368 // fall back to using the interruptible sleep functions. 369 370 #if defined BOOST_THREAD_USES_DATETIME 371 #ifdef __DECXXX 372 /// Workaround of DECCXX issue of incorrect template substitution 373 template<> 374 #endif 375 inline void sleep(system_time const& abs_time) 376 { 377 this_thread::sleep(abs_time); 378 } 379 380 template<typename TimeDuration> 381 void sleep(TimeDuration const& rel_time) 382 { 383 this_thread::sleep(rel_time); 384 } 385 #endif 386 387 #ifdef BOOST_THREAD_USES_CHRONO 388 template <class Clock, class Duration> 389 void sleep_until(const chrono::time_point<Clock, Duration>& t) 390 { 391 this_thread::sleep_until(t); 392 } 393 394 template <class Rep, class Period> 395 void sleep_for(const chrono::duration<Rep, Period>& d) 396 { 397 this_thread::sleep_for(d); 398 } 399 #endif 400 401 #endif // BOOST_THREAD_SLEEP_FOR_IS_STEADY 402 } // no_interruption_point 403 } // this_thread 404 } 405 406 #include <boost/config/abi_suffix.hpp> 407 408 #endif 409