Chris@16
|
1 #ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
Chris@16
|
2 #define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
Chris@16
|
3 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
4 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6 // (C) Copyright 2007 Anthony Williams
|
Chris@16
|
7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
Chris@16
|
8
|
Chris@16
|
9 #include <boost/thread/detail/config.hpp>
|
Chris@16
|
10 #include <boost/thread/exceptions.hpp>
|
Chris@16
|
11 #include <boost/thread/lock_guard.hpp>
|
Chris@16
|
12 #include <boost/thread/lock_types.hpp>
|
Chris@16
|
13 #include <boost/thread/mutex.hpp>
|
Chris@16
|
14 #include <boost/thread/pthread/condition_variable_fwd.hpp>
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/shared_ptr.hpp>
|
Chris@16
|
17 #include <boost/enable_shared_from_this.hpp>
|
Chris@16
|
18 #include <boost/optional.hpp>
|
Chris@16
|
19 #include <boost/assert.hpp>
|
Chris@16
|
20 #ifdef BOOST_THREAD_USES_CHRONO
|
Chris@16
|
21 #include <boost/chrono/system_clocks.hpp>
|
Chris@16
|
22 #endif
|
Chris@16
|
23
|
Chris@16
|
24 #include <map>
|
Chris@16
|
25 #include <vector>
|
Chris@16
|
26 #include <utility>
|
Chris@16
|
27
|
Chris@16
|
28 #if defined(__ANDROID__)
|
Chris@16
|
29 #include <asm/page.h> // http://code.google.com/p/android/issues/detail?id=39983
|
Chris@16
|
30 #endif
|
Chris@16
|
31
|
Chris@16
|
32 #include <pthread.h>
|
Chris@16
|
33 #include <unistd.h>
|
Chris@16
|
34
|
Chris@16
|
35 #include <boost/config/abi_prefix.hpp>
|
Chris@16
|
36
|
Chris@16
|
37 namespace boost
|
Chris@16
|
38 {
|
Chris@16
|
39 class thread_attributes {
|
Chris@16
|
40 public:
|
Chris@16
|
41 thread_attributes() BOOST_NOEXCEPT {
|
Chris@16
|
42 int res = pthread_attr_init(&val_);
|
Chris@16
|
43 BOOST_VERIFY(!res && "pthread_attr_init failed");
|
Chris@16
|
44 }
|
Chris@16
|
45 ~thread_attributes() {
|
Chris@16
|
46 int res = pthread_attr_destroy(&val_);
|
Chris@16
|
47 BOOST_VERIFY(!res && "pthread_attr_destroy failed");
|
Chris@16
|
48 }
|
Chris@16
|
49 // stack
|
Chris@16
|
50 void set_stack_size(std::size_t size) BOOST_NOEXCEPT {
|
Chris@16
|
51 if (size==0) return;
|
Chris@16
|
52 std::size_t page_size = getpagesize();
|
Chris@16
|
53 #ifdef PTHREAD_STACK_MIN
|
Chris@16
|
54 if (size<PTHREAD_STACK_MIN) size=PTHREAD_STACK_MIN;
|
Chris@16
|
55 #endif
|
Chris@16
|
56 size = ((size+page_size-1)/page_size)*page_size;
|
Chris@16
|
57 int res = pthread_attr_setstacksize(&val_, size);
|
Chris@16
|
58 BOOST_VERIFY(!res && "pthread_attr_setstacksize failed");
|
Chris@16
|
59 }
|
Chris@16
|
60
|
Chris@16
|
61 std::size_t get_stack_size() const BOOST_NOEXCEPT {
|
Chris@16
|
62 std::size_t size;
|
Chris@16
|
63 int res = pthread_attr_getstacksize(&val_, &size);
|
Chris@16
|
64 BOOST_VERIFY(!res && "pthread_attr_getstacksize failed");
|
Chris@16
|
65 return size;
|
Chris@16
|
66 }
|
Chris@16
|
67 #define BOOST_THREAD_DEFINES_THREAD_ATTRIBUTES_NATIVE_HANDLE
|
Chris@16
|
68
|
Chris@16
|
69 typedef pthread_attr_t native_handle_type;
|
Chris@16
|
70 native_handle_type* native_handle() BOOST_NOEXCEPT {
|
Chris@16
|
71 return &val_;
|
Chris@16
|
72 }
|
Chris@16
|
73 const native_handle_type* native_handle() const BOOST_NOEXCEPT {
|
Chris@16
|
74 return &val_;
|
Chris@16
|
75 }
|
Chris@16
|
76
|
Chris@16
|
77 private:
|
Chris@16
|
78 pthread_attr_t val_;
|
Chris@16
|
79 };
|
Chris@16
|
80
|
Chris@16
|
81 class thread;
|
Chris@16
|
82
|
Chris@16
|
83 namespace detail
|
Chris@16
|
84 {
|
Chris@16
|
85 struct shared_state_base;
|
Chris@16
|
86 struct tss_cleanup_function;
|
Chris@16
|
87 struct thread_exit_callback_node;
|
Chris@16
|
88 struct tss_data_node
|
Chris@16
|
89 {
|
Chris@16
|
90 boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
Chris@16
|
91 void* value;
|
Chris@16
|
92
|
Chris@16
|
93 tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_,
|
Chris@16
|
94 void* value_):
|
Chris@16
|
95 func(func_),value(value_)
|
Chris@16
|
96 {}
|
Chris@16
|
97 };
|
Chris@16
|
98
|
Chris@16
|
99 struct thread_data_base;
|
Chris@16
|
100 typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
|
Chris@16
|
101
|
Chris@16
|
102 struct BOOST_THREAD_DECL thread_data_base:
|
Chris@16
|
103 enable_shared_from_this<thread_data_base>
|
Chris@16
|
104 {
|
Chris@16
|
105 thread_data_ptr self;
|
Chris@16
|
106 pthread_t thread_handle;
|
Chris@16
|
107 boost::mutex data_mutex;
|
Chris@16
|
108 boost::condition_variable done_condition;
|
Chris@16
|
109 boost::mutex sleep_mutex;
|
Chris@16
|
110 boost::condition_variable sleep_condition;
|
Chris@16
|
111 bool done;
|
Chris@16
|
112 bool join_started;
|
Chris@16
|
113 bool joined;
|
Chris@16
|
114 boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
Chris@16
|
115 std::map<void const*,boost::detail::tss_data_node> tss_data;
|
Chris@16
|
116
|
Chris@16
|
117 pthread_mutex_t* cond_mutex;
|
Chris@16
|
118 pthread_cond_t* current_cond;
|
Chris@16
|
119 typedef std::vector<std::pair<condition_variable*, mutex*>
|
Chris@16
|
120 //, hidden_allocator<std::pair<condition_variable*, mutex*> >
|
Chris@16
|
121 > notify_list_t;
|
Chris@16
|
122 notify_list_t notify;
|
Chris@16
|
123
|
Chris@16
|
124 typedef std::vector<shared_ptr<shared_state_base> > async_states_t;
|
Chris@16
|
125 async_states_t async_states_;
|
Chris@16
|
126
|
Chris@16
|
127 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
Chris@16
|
128 // These data must be at the end so that the access to the other fields doesn't change
|
Chris@16
|
129 // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined.
|
Chris@16
|
130 // Another option is to have them always
|
Chris@16
|
131 bool interrupt_enabled;
|
Chris@16
|
132 bool interrupt_requested;
|
Chris@16
|
133 //#endif
|
Chris@16
|
134 thread_data_base():
|
Chris@16
|
135 thread_handle(0),
|
Chris@16
|
136 done(false),join_started(false),joined(false),
|
Chris@16
|
137 thread_exit_callbacks(0),
|
Chris@16
|
138 cond_mutex(0),
|
Chris@16
|
139 current_cond(0),
|
Chris@16
|
140 notify(),
|
Chris@16
|
141 async_states_()
|
Chris@16
|
142 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
Chris@16
|
143 , interrupt_enabled(true)
|
Chris@16
|
144 , interrupt_requested(false)
|
Chris@16
|
145 //#endif
|
Chris@16
|
146 {}
|
Chris@16
|
147 virtual ~thread_data_base();
|
Chris@16
|
148
|
Chris@16
|
149 typedef pthread_t native_handle_type;
|
Chris@16
|
150
|
Chris@16
|
151 virtual void run()=0;
|
Chris@16
|
152 virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m)
|
Chris@16
|
153 {
|
Chris@16
|
154 notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
|
Chris@16
|
155 }
|
Chris@16
|
156
|
Chris@16
|
157 void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
|
Chris@16
|
158 {
|
Chris@16
|
159 async_states_.push_back(as);
|
Chris@16
|
160 }
|
Chris@16
|
161
|
Chris@16
|
162 };
|
Chris@16
|
163
|
Chris@16
|
164 BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
|
Chris@16
|
165
|
Chris@16
|
166 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
Chris@16
|
167 class interruption_checker
|
Chris@16
|
168 {
|
Chris@16
|
169 thread_data_base* const thread_info;
|
Chris@16
|
170 pthread_mutex_t* m;
|
Chris@16
|
171 bool set;
|
Chris@16
|
172
|
Chris@16
|
173 void check_for_interruption()
|
Chris@16
|
174 {
|
Chris@16
|
175 #ifndef BOOST_NO_EXCEPTIONS
|
Chris@16
|
176 if(thread_info->interrupt_requested)
|
Chris@16
|
177 {
|
Chris@16
|
178 thread_info->interrupt_requested=false;
|
Chris@16
|
179 throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected
|
Chris@16
|
180 }
|
Chris@16
|
181 #endif
|
Chris@16
|
182 }
|
Chris@16
|
183
|
Chris@16
|
184 void operator=(interruption_checker&);
|
Chris@16
|
185 public:
|
Chris@16
|
186 explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond):
|
Chris@16
|
187 thread_info(detail::get_current_thread_data()),m(cond_mutex),
|
Chris@16
|
188 set(thread_info && thread_info->interrupt_enabled)
|
Chris@16
|
189 {
|
Chris@16
|
190 if(set)
|
Chris@16
|
191 {
|
Chris@16
|
192 lock_guard<mutex> guard(thread_info->data_mutex);
|
Chris@16
|
193 check_for_interruption();
|
Chris@16
|
194 thread_info->cond_mutex=cond_mutex;
|
Chris@16
|
195 thread_info->current_cond=cond;
|
Chris@16
|
196 BOOST_VERIFY(!pthread_mutex_lock(m));
|
Chris@16
|
197 }
|
Chris@16
|
198 else
|
Chris@16
|
199 {
|
Chris@16
|
200 BOOST_VERIFY(!pthread_mutex_lock(m));
|
Chris@16
|
201 }
|
Chris@16
|
202 }
|
Chris@16
|
203 ~interruption_checker()
|
Chris@16
|
204 {
|
Chris@16
|
205 if(set)
|
Chris@16
|
206 {
|
Chris@16
|
207 BOOST_VERIFY(!pthread_mutex_unlock(m));
|
Chris@16
|
208 lock_guard<mutex> guard(thread_info->data_mutex);
|
Chris@16
|
209 thread_info->cond_mutex=NULL;
|
Chris@16
|
210 thread_info->current_cond=NULL;
|
Chris@16
|
211 }
|
Chris@16
|
212 else
|
Chris@16
|
213 {
|
Chris@16
|
214 BOOST_VERIFY(!pthread_mutex_unlock(m));
|
Chris@16
|
215 }
|
Chris@16
|
216 }
|
Chris@16
|
217 };
|
Chris@16
|
218 #endif
|
Chris@16
|
219 }
|
Chris@16
|
220
|
Chris@16
|
221 namespace this_thread
|
Chris@16
|
222 {
|
Chris@16
|
223 namespace hiden
|
Chris@16
|
224 {
|
Chris@16
|
225 void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
Chris@16
|
226 void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
Chris@16
|
227 }
|
Chris@16
|
228
|
Chris@16
|
229 #ifdef BOOST_THREAD_USES_CHRONO
|
Chris@16
|
230 #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
Chris@16
|
231
|
Chris@16
|
232 inline
|
Chris@16
|
233 void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
|
Chris@16
|
234 {
|
Chris@16
|
235 return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns));
|
Chris@16
|
236 }
|
Chris@16
|
237 #endif
|
Chris@16
|
238 #endif // BOOST_THREAD_USES_CHRONO
|
Chris@16
|
239
|
Chris@16
|
240 void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
|
Chris@16
|
241
|
Chris@16
|
242 #if defined BOOST_THREAD_USES_DATETIME
|
Chris@16
|
243 #ifdef __DECXXX
|
Chris@16
|
244 /// Workaround of DECCXX issue of incorrect template substitution
|
Chris@16
|
245 template<>
|
Chris@16
|
246 #endif
|
Chris@16
|
247 inline void sleep(system_time const& abs_time)
|
Chris@16
|
248 {
|
Chris@16
|
249 return boost::this_thread::hiden::sleep_until(boost::detail::to_timespec(abs_time));
|
Chris@16
|
250 }
|
Chris@16
|
251
|
Chris@16
|
252 template<typename TimeDuration>
|
Chris@16
|
253 inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
Chris@16
|
254 {
|
Chris@16
|
255 this_thread::sleep(get_system_time()+rel_time);
|
Chris@16
|
256 }
|
Chris@16
|
257 #endif // BOOST_THREAD_USES_DATETIME
|
Chris@16
|
258 } // this_thread
|
Chris@16
|
259 }
|
Chris@16
|
260
|
Chris@16
|
261 #include <boost/config/abi_suffix.hpp>
|
Chris@16
|
262
|
Chris@16
|
263 #endif
|