thread_data.hpp 13 KB

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