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 | |
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: |
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 | } |
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 |
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 |
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 |
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> |
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 | |