]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
92f5a8d4 | 15 | #include <boost/thread/pthread/pthread_helpers.hpp> |
7c673cae FG |
16 | |
17 | #include <boost/shared_ptr.hpp> | |
18 | #include <boost/enable_shared_from_this.hpp> | |
19 | #include <boost/assert.hpp> | |
11fdf7f2 | 20 | #include <boost/thread/detail/platform_time.hpp> |
7c673cae FG |
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: | |
44 | thread_attributes() BOOST_NOEXCEPT { | |
45 | int res = pthread_attr_init(&val_); | |
46 | BOOST_VERIFY(!res && "pthread_attr_init failed"); | |
47 | } | |
48 | ~thread_attributes() { | |
49 | int res = pthread_attr_destroy(&val_); | |
50 | BOOST_VERIFY(!res && "pthread_attr_destroy failed"); | |
51 | } | |
52 | // stack | |
53 | void set_stack_size(std::size_t size) BOOST_NOEXCEPT { | |
54 | if (size==0) return; | |
b32b8144 | 55 | #ifdef BOOST_THREAD_USES_GETPAGESIZE |
7c673cae | 56 | std::size_t page_size = getpagesize(); |
b32b8144 FG |
57 | #else |
58 | std::size_t page_size = ::sysconf( _SC_PAGESIZE); | |
59 | #endif | |
f67539c2 | 60 | #ifdef PTHREAD_STACK_MIN |
1e59de90 | 61 | if (size<static_cast<std::size_t>(PTHREAD_STACK_MIN)) size=PTHREAD_STACK_MIN; |
7c673cae FG |
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 | ||
68 | 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; | |
77 | native_handle_type* native_handle() BOOST_NOEXCEPT { | |
78 | return &val_; | |
79 | } | |
80 | 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 | { | |
92f5a8d4 TL |
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; | |
7c673cae FG |
102 | void* value; |
103 | ||
92f5a8d4 TL |
104 | tss_data_node(cleanup_caller_t caller_,cleanup_func_t func_,void* value_): |
105 | caller(caller_),func(func_),value(value_) | |
7c673cae FG |
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; | |
7c673cae FG |
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 | ||
92f5a8d4 | 137 | //#ifndef BOOST_NO_EXCEPTIONS |
7c673cae FG |
138 | typedef std::vector<shared_ptr<shared_state_base> > async_states_t; |
139 | async_states_t async_states_; | |
92f5a8d4 | 140 | //#endif |
7c673cae FG |
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 | |
148 | 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 | |
92f5a8d4 TL |
156 | notify() |
157 | //#ifndef BOOST_NO_EXCEPTIONS | |
158 | , async_states_() | |
159 | //#endif | |
7c673cae FG |
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; | |
170 | 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 | ||
92f5a8d4 | 175 | //#ifndef BOOST_NO_EXCEPTIONS |
7c673cae FG |
176 | void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) |
177 | { | |
178 | async_states_.push_back(as); | |
179 | } | |
92f5a8d4 | 180 | //#endif |
7c673cae FG |
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; | |
b32b8144 | 191 | bool done; |
7c673cae FG |
192 | |
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: | |
206 | explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond): | |
207 | thread_info(detail::get_current_thread_data()),m(cond_mutex), | |
b32b8144 | 208 | set(thread_info && thread_info->interrupt_enabled), done(false) |
7c673cae FG |
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; | |
92f5a8d4 | 216 | BOOST_VERIFY(!posix::pthread_mutex_lock(m)); |
7c673cae FG |
217 | } |
218 | else | |
219 | { | |
92f5a8d4 | 220 | BOOST_VERIFY(!posix::pthread_mutex_lock(m)); |
7c673cae FG |
221 | } |
222 | } | |
b32b8144 | 223 | void unlock_if_locked() |
7c673cae | 224 | { |
b32b8144 FG |
225 | if ( ! done) { |
226 | if (set) | |
7c673cae | 227 | { |
92f5a8d4 | 228 | BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); |
7c673cae FG |
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 | { | |
92f5a8d4 | 235 | BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); |
7c673cae | 236 | } |
b32b8144 FG |
237 | done = true; |
238 | } | |
239 | } | |
240 | ||
241 | ~interruption_checker() BOOST_NOEXCEPT_IF(false) | |
242 | { | |
243 | unlock_if_locked(); | |
7c673cae FG |
244 | } |
245 | }; | |
246 | #endif | |
247 | } | |
248 | ||
249 | namespace this_thread | |
250 | { | |
11fdf7f2 TL |
251 | void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; |
252 | ||
7c673cae FG |
253 | namespace hidden |
254 | { | |
11fdf7f2 TL |
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 | |
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); | |
7c673cae FG |
272 | } |
273 | ||
11fdf7f2 TL |
274 | template<typename TimeDuration> |
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 | ||
7c673cae | 284 | #ifdef BOOST_THREAD_USES_CHRONO |
11fdf7f2 TL |
285 | template <class Clock, class Duration> |
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 | } | |
7c673cae | 293 | |
11fdf7f2 TL |
294 | template <class Rep, class Period> |
295 | void sleep_for(const chrono::duration<Rep, Period>& d) | |
7c673cae | 296 | { |
11fdf7f2 TL |
297 | mutex mut; |
298 | unique_lock<mutex> lk(mut); | |
299 | condition_variable cv; | |
300 | cv.wait_for(lk, d, hidden::always_false); | |
7c673cae FG |
301 | } |
302 | #endif | |
7c673cae FG |
303 | |
304 | namespace no_interruption_point | |
305 | { | |
11fdf7f2 TL |
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 | ||
7c673cae FG |
310 | namespace hidden |
311 | { | |
11fdf7f2 | 312 | void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts); |
7c673cae FG |
313 | } |
314 | ||
11fdf7f2 TL |
315 | #if defined BOOST_THREAD_USES_DATETIME |
316 | #ifdef __DECXXX | |
317 | /// Workaround of DECCXX issue of incorrect template substitution | |
318 | template<> | |
319 | #endif | |
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> | |
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 | |
b32b8144 | 340 | template <class Rep, class Period> |
11fdf7f2 TL |
341 | void sleep_for(const chrono::duration<Rep, Period>& d) |
342 | { | |
343 | hidden::sleep_for_internal(detail::platform_duration(d)); | |
344 | } | |
7c673cae | 345 | |
11fdf7f2 TL |
346 | template <class Duration> |
347 | void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t) | |
7c673cae | 348 | { |
11fdf7f2 | 349 | sleep_for(t - chrono::steady_clock::now()); |
7c673cae | 350 | } |
7c673cae | 351 | |
11fdf7f2 TL |
352 | template <class Clock, class Duration> |
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 | |
7c673cae | 365 | |
11fdf7f2 TL |
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. | |
7c673cae FG |
369 | |
370 | #if defined BOOST_THREAD_USES_DATETIME | |
371 | #ifdef __DECXXX | |
11fdf7f2 TL |
372 | /// Workaround of DECCXX issue of incorrect template substitution |
373 | template<> | |
7c673cae | 374 | #endif |
11fdf7f2 TL |
375 | inline void sleep(system_time const& abs_time) |
376 | { | |
377 | this_thread::sleep(abs_time); | |
378 | } | |
7c673cae | 379 | |
11fdf7f2 TL |
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 | |
7c673cae FG |
403 | } // this_thread |
404 | } | |
405 | ||
406 | #include <boost/config/abi_suffix.hpp> | |
407 | ||
408 | #endif |