]>
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> | |
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 hidden | |
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::hidden::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 hidden | |
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::hidden::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::hidden::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 |