| 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: |
| 42 | thread_attributes() BOOST_NOEXCEPT { |
| 43 | int res = pthread_attr_init(&val_); |
| 44 | BOOST_VERIFY(!res && "pthread_attr_init failed" ); |
| 45 | } |
| 46 | ~thread_attributes() { |
| 47 | int res = pthread_attr_destroy(&val_); |
| 48 | BOOST_VERIFY(!res && "pthread_attr_destroy failed" ); |
| 49 | } |
| 50 | // stack |
| 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 | |
| 62 | 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; |
| 71 | native_handle_type* native_handle() BOOST_NOEXCEPT { |
| 72 | return &val_; |
| 73 | } |
| 74 | 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 | |
| 94 | 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 |
| 140 | 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; |
| 160 | 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 | |
| 165 | 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 | bool done; |
| 181 | |
| 182 | void check_for_interruption() |
| 183 | { |
| 184 | #ifndef BOOST_NO_EXCEPTIONS |
| 185 | if(thread_info->interrupt_requested) |
| 186 | { |
| 187 | thread_info->interrupt_requested=false; |
| 188 | throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected |
| 189 | } |
| 190 | #endif |
| 191 | } |
| 192 | |
| 193 | void operator=(interruption_checker&); |
| 194 | public: |
| 195 | explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond): |
| 196 | thread_info(detail::get_current_thread_data()),m(cond_mutex), |
| 197 | set(thread_info && thread_info->interrupt_enabled), done(false) |
| 198 | { |
| 199 | if(set) |
| 200 | { |
| 201 | lock_guard<mutex> guard(thread_info->data_mutex); |
| 202 | check_for_interruption(); |
| 203 | thread_info->cond_mutex=cond_mutex; |
| 204 | thread_info->current_cond=cond; |
| 205 | BOOST_VERIFY(!pthread_mutex_lock(m)); |
| 206 | } |
| 207 | else |
| 208 | { |
| 209 | BOOST_VERIFY(!pthread_mutex_lock(m)); |
| 210 | } |
| 211 | } |
| 212 | void check() |
| 213 | { |
| 214 | if ( ! done) { |
| 215 | if (set) |
| 216 | { |
| 217 | BOOST_VERIFY(!pthread_mutex_unlock(m)); |
| 218 | lock_guard<mutex> guard(thread_info->data_mutex); |
| 219 | thread_info->cond_mutex=NULL; |
| 220 | thread_info->current_cond=NULL; |
| 221 | } |
| 222 | else |
| 223 | { |
| 224 | BOOST_VERIFY(!pthread_mutex_unlock(m)); |
| 225 | } |
| 226 | done = true; |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | ~interruption_checker() BOOST_NOEXCEPT_IF(false) |
| 231 | { |
| 232 | check(); |
| 233 | } |
| 234 | }; |
| 235 | #endif |
| 236 | } |
| 237 | |
| 238 | namespace this_thread |
| 239 | { |
| 240 | namespace hidden |
| 241 | { |
| 242 | void BOOST_THREAD_DECL sleep_for(const timespec& ts); |
| 243 | void BOOST_THREAD_DECL sleep_until(const timespec& ts); |
| 244 | } |
| 245 | |
| 246 | #ifdef BOOST_THREAD_USES_CHRONO |
| 247 | #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY |
| 248 | |
| 249 | inline |
| 250 | void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) |
| 251 | { |
| 252 | return boost::this_thread::hidden::sleep_for(boost::detail::to_timespec(ns)); |
| 253 | } |
| 254 | #endif |
| 255 | #endif // BOOST_THREAD_USES_CHRONO |
| 256 | |
| 257 | namespace no_interruption_point |
| 258 | { |
| 259 | namespace hidden |
| 260 | { |
| 261 | void BOOST_THREAD_DECL sleep_for(const timespec& ts); |
| 262 | void BOOST_THREAD_DECL sleep_until(const timespec& ts); |
| 263 | } |
| 264 | |
| 265 | #ifdef BOOST_THREAD_USES_CHRONO |
| 266 | #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY |
| 267 | |
| 268 | inline |
| 269 | void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) |
| 270 | { |
| 271 | return boost::this_thread::no_interruption_point::hidden::sleep_for(boost::detail::to_timespec(ns)); |
| 272 | } |
| 273 | #endif |
| 274 | #endif // BOOST_THREAD_USES_CHRONO |
| 275 | |
| 276 | } // no_interruption_point |
| 277 | |
| 278 | void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; |
| 279 | |
| 280 | #if defined BOOST_THREAD_USES_DATETIME |
| 281 | #ifdef __DECXXX |
| 282 | /// Workaround of DECCXX issue of incorrect template substitution |
| 283 | template<> |
| 284 | #endif |
| 285 | inline void sleep(system_time const& abs_time) |
| 286 | { |
| 287 | return boost::this_thread::hidden::sleep_until(boost::detail::to_timespec(abs_time)); |
| 288 | } |
| 289 | |
| 290 | template<typename TimeDuration> |
| 291 | inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) |
| 292 | { |
| 293 | this_thread::sleep(get_system_time()+rel_time); |
| 294 | } |
| 295 | #endif // BOOST_THREAD_USES_DATETIME |
| 296 | } // this_thread |
| 297 | } |
| 298 | |
| 299 | #include <boost/config/abi_suffix.hpp> |
| 300 | |
| 301 | #endif |
| 302 | |