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 16 #include <boost/shared_ptr.hpp> 17 #include <boost/enable_shared_from_this.hpp> 18 #include <boost/assert.hpp> 19 #ifdef BOOST_THREAD_USES_CHRONO 20 #include <boost/chrono/system_clocks.hpp> 21 #endif 22 23 #include <map> 24 #include <vector> 25 #include <utility> 26 27 #if defined(__ANDROID__) 28 # ifndef PAGE_SIZE 29 # define PAGE_SIZE 4096 30 # endif 31 #endif 32 33 #include <pthread.h> 34 #include <unistd.h> 35 36 #include <boost/config/abi_prefix.hpp> 37 38 namespace boost 39 { 40 class thread_attributes { 41 public: thread_attributes()42 thread_attributes() BOOST_NOEXCEPT { 43 int res = pthread_attr_init(&val_); 44 BOOST_VERIFY(!res && "pthread_attr_init failed"); 45 } ~thread_attributes()46 ~thread_attributes() { 47 int res = pthread_attr_destroy(&val_); 48 BOOST_VERIFY(!res && "pthread_attr_destroy failed"); 49 } 50 // stack set_stack_size(std::size_t size)51 void set_stack_size(std::size_t size) BOOST_NOEXCEPT { 52 if (size==0) return; 53 std::size_t page_size = getpagesize(); 54 #ifdef PTHREAD_STACK_MIN 55 if (size<PTHREAD_STACK_MIN) size=PTHREAD_STACK_MIN; 56 #endif 57 size = ((size+page_size-1)/page_size)*page_size; 58 int res = pthread_attr_setstacksize(&val_, size); 59 BOOST_VERIFY(!res && "pthread_attr_setstacksize failed"); 60 } 61 get_stack_size() const62 std::size_t get_stack_size() const BOOST_NOEXCEPT { 63 std::size_t size; 64 int res = pthread_attr_getstacksize(&val_, &size); 65 BOOST_VERIFY(!res && "pthread_attr_getstacksize failed"); 66 return size; 67 } 68 #define BOOST_THREAD_DEFINES_THREAD_ATTRIBUTES_NATIVE_HANDLE 69 70 typedef pthread_attr_t native_handle_type; native_handle()71 native_handle_type* native_handle() BOOST_NOEXCEPT { 72 return &val_; 73 } native_handle() const74 const native_handle_type* native_handle() const BOOST_NOEXCEPT { 75 return &val_; 76 } 77 78 private: 79 pthread_attr_t val_; 80 }; 81 82 class thread; 83 84 namespace detail 85 { 86 struct shared_state_base; 87 struct tss_cleanup_function; 88 struct thread_exit_callback_node; 89 struct tss_data_node 90 { 91 boost::shared_ptr<boost::detail::tss_cleanup_function> func; 92 void* value; 93 tss_data_nodeboost::detail::tss_data_node94 tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_, 95 void* value_): 96 func(func_),value(value_) 97 {} 98 }; 99 100 struct thread_data_base; 101 typedef boost::shared_ptr<thread_data_base> thread_data_ptr; 102 103 struct BOOST_THREAD_DECL thread_data_base: 104 enable_shared_from_this<thread_data_base> 105 { 106 thread_data_ptr self; 107 pthread_t thread_handle; 108 boost::mutex data_mutex; 109 boost::condition_variable done_condition; 110 boost::mutex sleep_mutex; 111 boost::condition_variable sleep_condition; 112 bool done; 113 bool join_started; 114 bool joined; 115 boost::detail::thread_exit_callback_node* thread_exit_callbacks; 116 std::map<void const*,boost::detail::tss_data_node> tss_data; 117 118 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 119 // These data must be at the end so that the access to the other fields doesn't change 120 // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. 121 // Another option is to have them always 122 pthread_mutex_t* cond_mutex; 123 pthread_cond_t* current_cond; 124 //#endif 125 typedef std::vector<std::pair<condition_variable*, mutex*> 126 //, hidden_allocator<std::pair<condition_variable*, mutex*> > 127 > notify_list_t; 128 notify_list_t notify; 129 130 typedef std::vector<shared_ptr<shared_state_base> > async_states_t; 131 async_states_t async_states_; 132 133 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 134 // These data must be at the end so that the access to the other fields doesn't change 135 // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. 136 // Another option is to have them always 137 bool interrupt_enabled; 138 bool interrupt_requested; 139 //#endif thread_data_baseboost::detail::thread_data_base140 thread_data_base(): 141 thread_handle(0), 142 done(false),join_started(false),joined(false), 143 thread_exit_callbacks(0), 144 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 145 cond_mutex(0), 146 current_cond(0), 147 //#endif 148 notify(), 149 async_states_() 150 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 151 , interrupt_enabled(true) 152 , interrupt_requested(false) 153 //#endif 154 {} 155 virtual ~thread_data_base(); 156 157 typedef pthread_t native_handle_type; 158 159 virtual void run()=0; notify_all_at_thread_exitboost::detail::thread_data_base160 virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m) 161 { 162 notify.push_back(std::pair<condition_variable*, mutex*>(cv, m)); 163 } 164 make_ready_at_thread_exitboost::detail::thread_data_base165 void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) 166 { 167 async_states_.push_back(as); 168 } 169 170 }; 171 172 BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); 173 174 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 175 class interruption_checker 176 { 177 thread_data_base* const thread_info; 178 pthread_mutex_t* m; 179 bool set; 180 check_for_interruption()181 void check_for_interruption() 182 { 183 #ifndef BOOST_NO_EXCEPTIONS 184 if(thread_info->interrupt_requested) 185 { 186 thread_info->interrupt_requested=false; 187 throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected 188 } 189 #endif 190 } 191 192 void operator=(interruption_checker&); 193 public: interruption_checker(pthread_mutex_t * cond_mutex,pthread_cond_t * cond)194 explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond): 195 thread_info(detail::get_current_thread_data()),m(cond_mutex), 196 set(thread_info && thread_info->interrupt_enabled) 197 { 198 if(set) 199 { 200 lock_guard<mutex> guard(thread_info->data_mutex); 201 check_for_interruption(); 202 thread_info->cond_mutex=cond_mutex; 203 thread_info->current_cond=cond; 204 BOOST_VERIFY(!pthread_mutex_lock(m)); 205 } 206 else 207 { 208 BOOST_VERIFY(!pthread_mutex_lock(m)); 209 } 210 } ~interruption_checker()211 ~interruption_checker() 212 { 213 if(set) 214 { 215 BOOST_VERIFY(!pthread_mutex_unlock(m)); 216 lock_guard<mutex> guard(thread_info->data_mutex); 217 thread_info->cond_mutex=NULL; 218 thread_info->current_cond=NULL; 219 } 220 else 221 { 222 BOOST_VERIFY(!pthread_mutex_unlock(m)); 223 } 224 } 225 }; 226 #endif 227 } 228 229 namespace this_thread 230 { 231 namespace hiden 232 { 233 void BOOST_THREAD_DECL sleep_for(const timespec& ts); 234 void BOOST_THREAD_DECL sleep_until(const timespec& ts); 235 } 236 237 #ifdef BOOST_THREAD_USES_CHRONO 238 #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY 239 240 inline sleep_for(const chrono::nanoseconds & ns)241 void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) 242 { 243 return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns)); 244 } 245 #endif 246 #endif // BOOST_THREAD_USES_CHRONO 247 248 namespace no_interruption_point 249 { 250 namespace hiden 251 { 252 void BOOST_THREAD_DECL sleep_for(const timespec& ts); 253 void BOOST_THREAD_DECL sleep_until(const timespec& ts); 254 } 255 256 #ifdef BOOST_THREAD_USES_CHRONO 257 #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY 258 259 inline sleep_for(const chrono::nanoseconds & ns)260 void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) 261 { 262 return boost::this_thread::no_interruption_point::hiden::sleep_for(boost::detail::to_timespec(ns)); 263 } 264 #endif 265 #endif // BOOST_THREAD_USES_CHRONO 266 267 } // no_interruption_point 268 269 void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; 270 271 #if defined BOOST_THREAD_USES_DATETIME 272 #ifdef __DECXXX 273 /// Workaround of DECCXX issue of incorrect template substitution 274 template<> 275 #endif sleep(system_time const & abs_time)276 inline void sleep(system_time const& abs_time) 277 { 278 return boost::this_thread::hiden::sleep_until(boost::detail::to_timespec(abs_time)); 279 } 280 281 template<typename TimeDuration> sleep(TimeDuration const & rel_time)282 inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) 283 { 284 this_thread::sleep(get_system_time()+rel_time); 285 } 286 #endif // BOOST_THREAD_USES_DATETIME 287 } // this_thread 288 } 289 290 #include <boost/config/abi_suffix.hpp> 291 292 #endif 293