Line data Source code
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:
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;
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 : #if PTHREAD_STACK_MIN > 0
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 :
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 : {
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 :
104 : 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
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
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;
170 0 : virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m)
171 : {
172 0 : notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
173 0 : }
174 :
175 : //#ifndef BOOST_NO_EXCEPTIONS
176 : 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 :
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 0 : explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond):
207 0 : thread_info(detail::get_current_thread_data()),m(cond_mutex),
208 0 : set(thread_info && thread_info->interrupt_enabled), done(false)
209 : {
210 0 : if(set)
211 : {
212 0 : lock_guard<mutex> guard(thread_info->data_mutex);
213 0 : check_for_interruption();
214 0 : thread_info->cond_mutex=cond_mutex;
215 0 : thread_info->current_cond=cond;
216 0 : BOOST_VERIFY(!posix::pthread_mutex_lock(m));
217 : }
218 : else
219 : {
220 0 : BOOST_VERIFY(!posix::pthread_mutex_lock(m));
221 : }
222 0 : }
223 0 : void unlock_if_locked()
224 : {
225 0 : if ( ! done) {
226 0 : if (set)
227 : {
228 0 : BOOST_VERIFY(!posix::pthread_mutex_unlock(m));
229 0 : lock_guard<mutex> guard(thread_info->data_mutex);
230 0 : thread_info->cond_mutex=NULL;
231 0 : thread_info->current_cond=NULL;
232 : }
233 : else
234 : {
235 0 : BOOST_VERIFY(!posix::pthread_mutex_unlock(m));
236 : }
237 0 : done = true;
238 : }
239 0 : }
240 :
241 0 : ~interruption_checker() BOOST_NOEXCEPT_IF(false)
242 0 : {
243 0 : 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 : {
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);
272 : }
273 :
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 :
284 : #ifdef BOOST_THREAD_USES_CHRONO
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 : }
293 :
294 : template <class Rep, class Period>
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
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
340 : template <class Rep, class Period>
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>
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>
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
|