]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP |
2 | #define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_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-8 Anthony Williams | |
7 | // (C) Copyright 2011-2012 Vicente J. Botet Escriba | |
8 | ||
9 | #include <boost/assert.hpp> | |
10 | #include <boost/throw_exception.hpp> | |
11 | #include <pthread.h> | |
12 | #include <boost/thread/cv_status.hpp> | |
13 | #include <boost/thread/mutex.hpp> | |
14 | #include <boost/thread/lock_types.hpp> | |
15 | #include <boost/thread/thread_time.hpp> | |
16 | #include <boost/thread/pthread/timespec.hpp> | |
17 | #if defined BOOST_THREAD_USES_DATETIME | |
18 | #include <boost/thread/xtime.hpp> | |
19 | #endif | |
20 | #ifdef BOOST_THREAD_USES_CHRONO | |
21 | #include <boost/chrono/system_clocks.hpp> | |
22 | #include <boost/chrono/ceil.hpp> | |
23 | #endif | |
24 | #include <boost/thread/detail/delete.hpp> | |
25 | #include <boost/date_time/posix_time/posix_time_duration.hpp> | |
26 | ||
27 | #include <boost/config/abi_prefix.hpp> | |
28 | ||
29 | namespace boost | |
30 | { | |
31 | namespace detail { | |
32 | inline int monotonic_pthread_cond_init(pthread_cond_t& cond) { | |
33 | ||
34 | #ifdef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
35 | pthread_condattr_t attr; | |
36 | int res = pthread_condattr_init(&attr); | |
37 | if (res) | |
38 | { | |
39 | return res; | |
40 | } | |
41 | pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); | |
42 | res=pthread_cond_init(&cond,&attr); | |
43 | pthread_condattr_destroy(&attr); | |
44 | return res; | |
45 | #else | |
46 | return pthread_cond_init(&cond,NULL); | |
47 | #endif | |
48 | ||
49 | } | |
50 | } | |
51 | ||
52 | class condition_variable | |
53 | { | |
54 | private: | |
55 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
56 | pthread_mutex_t internal_mutex; | |
57 | #endif | |
58 | pthread_cond_t cond; | |
59 | ||
60 | public: | |
61 | //private: // used by boost::thread::try_join_until | |
62 | ||
63 | inline bool do_wait_until( | |
64 | unique_lock<mutex>& lock, | |
65 | struct timespec const &timeout); | |
66 | ||
67 | bool do_wait_for( | |
68 | unique_lock<mutex>& lock, | |
69 | struct timespec const &timeout) | |
70 | { | |
71 | return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); | |
72 | } | |
73 | ||
74 | public: | |
75 | BOOST_THREAD_NO_COPYABLE(condition_variable) | |
76 | condition_variable() | |
77 | { | |
78 | int res; | |
79 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
80 | res=pthread_mutex_init(&internal_mutex,NULL); | |
81 | if(res) | |
82 | { | |
83 | boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init")); | |
84 | } | |
85 | #endif | |
86 | res = detail::monotonic_pthread_cond_init(cond); | |
87 | if (res) | |
88 | { | |
89 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
90 | BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); | |
91 | #endif | |
92 | boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in detail::monotonic_pthread_cond_init")); | |
93 | } | |
94 | } | |
95 | ~condition_variable() | |
96 | { | |
97 | int ret; | |
98 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS | |
99 | do { | |
100 | ret = pthread_mutex_destroy(&internal_mutex); | |
101 | } while (ret == EINTR); | |
102 | BOOST_ASSERT(!ret); | |
103 | #endif | |
104 | do { | |
105 | ret = pthread_cond_destroy(&cond); | |
106 | } while (ret == EINTR); | |
107 | BOOST_ASSERT(!ret); | |
108 | } | |
109 | ||
110 | void wait(unique_lock<mutex>& m); | |
111 | ||
112 | template<typename predicate_type> | |
113 | void wait(unique_lock<mutex>& m,predicate_type pred) | |
114 | { | |
115 | while(!pred()) wait(m); | |
116 | } | |
117 | ||
118 | #if defined BOOST_THREAD_USES_DATETIME | |
119 | inline bool timed_wait( | |
120 | unique_lock<mutex>& m, | |
121 | boost::system_time const& abs_time) | |
122 | { | |
123 | #if defined BOOST_THREAD_WAIT_BUG | |
124 | struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG); | |
125 | return do_wait_until(m, timeout); | |
126 | #else | |
127 | struct timespec const timeout=detail::to_timespec(abs_time); | |
128 | return do_wait_until(m, timeout); | |
129 | #endif | |
130 | } | |
131 | bool timed_wait( | |
132 | unique_lock<mutex>& m, | |
133 | xtime const& abs_time) | |
134 | { | |
135 | return timed_wait(m,system_time(abs_time)); | |
136 | } | |
137 | ||
138 | template<typename duration_type> | |
139 | bool timed_wait( | |
140 | unique_lock<mutex>& m, | |
141 | duration_type const& wait_duration) | |
142 | { | |
143 | if (wait_duration.is_pos_infinity()) | |
144 | { | |
145 | wait(m); // or do_wait(m,detail::timeout::sentinel()); | |
146 | return true; | |
147 | } | |
148 | if (wait_duration.is_special()) | |
149 | { | |
150 | return true; | |
151 | } | |
152 | return timed_wait(m,get_system_time()+wait_duration); | |
153 | } | |
154 | ||
155 | template<typename predicate_type> | |
156 | bool timed_wait( | |
157 | unique_lock<mutex>& m, | |
158 | boost::system_time const& abs_time,predicate_type pred) | |
159 | { | |
160 | while (!pred()) | |
161 | { | |
162 | if(!timed_wait(m, abs_time)) | |
163 | return pred(); | |
164 | } | |
165 | return true; | |
166 | } | |
167 | ||
168 | template<typename predicate_type> | |
169 | bool timed_wait( | |
170 | unique_lock<mutex>& m, | |
171 | xtime const& abs_time,predicate_type pred) | |
172 | { | |
173 | return timed_wait(m,system_time(abs_time),pred); | |
174 | } | |
175 | ||
176 | template<typename duration_type,typename predicate_type> | |
177 | bool timed_wait( | |
178 | unique_lock<mutex>& m, | |
179 | duration_type const& wait_duration,predicate_type pred) | |
180 | { | |
181 | if (wait_duration.is_pos_infinity()) | |
182 | { | |
183 | while (!pred()) | |
184 | { | |
185 | wait(m); // or do_wait(m,detail::timeout::sentinel()); | |
186 | } | |
187 | return true; | |
188 | } | |
189 | if (wait_duration.is_special()) | |
190 | { | |
191 | return pred(); | |
192 | } | |
193 | return timed_wait(m,get_system_time()+wait_duration,pred); | |
194 | } | |
195 | #endif | |
196 | ||
197 | #ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
198 | ||
199 | #ifdef BOOST_THREAD_USES_CHRONO | |
200 | ||
201 | template <class Duration> | |
202 | cv_status | |
203 | wait_until( | |
204 | unique_lock<mutex>& lock, | |
205 | const chrono::time_point<chrono::system_clock, Duration>& t) | |
206 | { | |
207 | using namespace chrono; | |
208 | typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; | |
209 | wait_until(lock, | |
210 | nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); | |
211 | return system_clock::now() < t ? cv_status::no_timeout : | |
212 | cv_status::timeout; | |
213 | } | |
214 | ||
215 | template <class Clock, class Duration> | |
216 | cv_status | |
217 | wait_until( | |
218 | unique_lock<mutex>& lock, | |
219 | const chrono::time_point<Clock, Duration>& t) | |
220 | { | |
221 | using namespace chrono; | |
222 | system_clock::time_point s_now = system_clock::now(); | |
223 | typename Clock::time_point c_now = Clock::now(); | |
224 | wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); | |
225 | return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; | |
226 | } | |
227 | ||
228 | ||
229 | ||
230 | template <class Rep, class Period> | |
231 | cv_status | |
232 | wait_for( | |
233 | unique_lock<mutex>& lock, | |
234 | const chrono::duration<Rep, Period>& d) | |
235 | { | |
236 | using namespace chrono; | |
237 | system_clock::time_point s_now = system_clock::now(); | |
238 | steady_clock::time_point c_now = steady_clock::now(); | |
239 | wait_until(lock, s_now + ceil<nanoseconds>(d)); | |
240 | return steady_clock::now() - c_now < d ? cv_status::no_timeout : | |
241 | cv_status::timeout; | |
242 | ||
243 | } | |
244 | ||
245 | inline cv_status wait_until( | |
246 | unique_lock<mutex>& lk, | |
247 | chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) | |
248 | { | |
249 | using namespace chrono; | |
250 | nanoseconds d = tp.time_since_epoch(); | |
251 | timespec ts = boost::detail::to_timespec(d); | |
252 | if (do_wait_until(lk, ts)) return cv_status::no_timeout; | |
253 | else return cv_status::timeout; | |
254 | } | |
255 | #endif | |
256 | ||
257 | #else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
258 | #ifdef BOOST_THREAD_USES_CHRONO | |
259 | ||
260 | template <class Duration> | |
261 | cv_status | |
262 | wait_until( | |
263 | unique_lock<mutex>& lock, | |
264 | const chrono::time_point<chrono::steady_clock, Duration>& t) | |
265 | { | |
266 | using namespace chrono; | |
267 | typedef time_point<steady_clock, nanoseconds> nano_sys_tmpt; | |
268 | wait_until(lock, | |
269 | nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); | |
270 | return steady_clock::now() < t ? cv_status::no_timeout : | |
271 | cv_status::timeout; | |
272 | } | |
273 | ||
274 | template <class Clock, class Duration> | |
275 | cv_status | |
276 | wait_until( | |
277 | unique_lock<mutex>& lock, | |
278 | const chrono::time_point<Clock, Duration>& t) | |
279 | { | |
280 | using namespace chrono; | |
281 | steady_clock::time_point s_now = steady_clock::now(); | |
282 | typename Clock::time_point c_now = Clock::now(); | |
283 | wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); | |
284 | return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; | |
285 | } | |
286 | ||
287 | template <class Rep, class Period> | |
288 | cv_status | |
289 | wait_for( | |
290 | unique_lock<mutex>& lock, | |
291 | const chrono::duration<Rep, Period>& d) | |
292 | { | |
293 | using namespace chrono; | |
294 | steady_clock::time_point c_now = steady_clock::now(); | |
295 | wait_until(lock, c_now + ceil<nanoseconds>(d)); | |
296 | return steady_clock::now() - c_now < d ? cv_status::no_timeout : | |
297 | cv_status::timeout; | |
298 | } | |
299 | ||
300 | inline cv_status wait_until( | |
301 | unique_lock<mutex>& lk, | |
302 | chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp) | |
303 | { | |
304 | using namespace chrono; | |
305 | nanoseconds d = tp.time_since_epoch(); | |
306 | timespec ts = boost::detail::to_timespec(d); | |
307 | if (do_wait_until(lk, ts)) return cv_status::no_timeout; | |
308 | else return cv_status::timeout; | |
309 | } | |
310 | #endif | |
311 | ||
312 | #endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
313 | ||
314 | #ifdef BOOST_THREAD_USES_CHRONO | |
315 | template <class Clock, class Duration, class Predicate> | |
316 | bool | |
317 | wait_until( | |
318 | unique_lock<mutex>& lock, | |
319 | const chrono::time_point<Clock, Duration>& t, | |
320 | Predicate pred) | |
321 | { | |
322 | while (!pred()) | |
323 | { | |
324 | if (wait_until(lock, t) == cv_status::timeout) | |
325 | return pred(); | |
326 | } | |
327 | return true; | |
328 | } | |
329 | ||
330 | template <class Rep, class Period, class Predicate> | |
331 | bool | |
332 | wait_for( | |
333 | unique_lock<mutex>& lock, | |
334 | const chrono::duration<Rep, Period>& d, | |
335 | Predicate pred) | |
336 | { | |
337 | return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); | |
338 | } | |
339 | #endif | |
340 | ||
341 | #define BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE | |
342 | typedef pthread_cond_t* native_handle_type; | |
343 | native_handle_type native_handle() | |
344 | { | |
345 | return &cond; | |
346 | } | |
347 | ||
348 | void notify_one() BOOST_NOEXCEPT; | |
349 | void notify_all() BOOST_NOEXCEPT; | |
350 | ||
351 | ||
352 | }; | |
353 | ||
354 | BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); | |
355 | ||
356 | } | |
357 | ||
358 | ||
359 | #include <boost/config/abi_suffix.hpp> | |
360 | ||
361 | #endif |