1616#include < boost/chrono/system_clocks.hpp>
1717#include < boost/chrono/chrono_io.hpp>
1818
19+ #include < algorithm> // std::min
20+
1921#include < boost/config/abi_prefix.hpp>
2022
2123namespace boost
@@ -59,6 +61,45 @@ namespace detail
5961 }
6062 }; // end struct
6163
64+ template <class Duration >
65+ chrono::time_point<chrono::steady_clock,Duration>
66+ limit_timepoint (chrono::time_point<chrono::steady_clock,Duration> const & tp)
67+ {
68+ // Clock == chrono::steady_clock
69+ return tp;
70+ }
71+
72+ template <class Clock , class Duration >
73+ chrono::time_point<Clock,Duration>
74+ limit_timepoint (chrono::time_point<Clock,Duration> const & tp)
75+ {
76+ // Clock != chrono::steady_clock
77+ // The system time may jump while wait_until() is waiting. To compensate for this and time out near
78+ // the correct time, we limit how long wait_until() can wait before going around the loop again.
79+ const chrono::time_point<Clock,Duration> tpmax (chrono::time_point_cast<Duration>(Clock::now () + chrono::milliseconds (BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
80+ return (std::min)(tp, tpmax);
81+ }
82+
83+ template <class Duration >
84+ chrono::steady_clock::time_point
85+ convert_to_steady_clock_timepoint (chrono::time_point<chrono::steady_clock,Duration> const & tp)
86+ {
87+ // Clock == chrono::steady_clock
88+ return chrono::time_point_cast<chrono::steady_clock::duration>(tp);
89+ }
90+
91+ template <class Clock , class Duration >
92+ chrono::steady_clock::time_point
93+ convert_to_steady_clock_timepoint (chrono::time_point<Clock,Duration> const & tp)
94+ {
95+ // Clock != chrono::steady_clock
96+ // The system time may jump while wait_until() is waiting. To compensate for this and time out near
97+ // the correct time, we limit how long wait_until() can wait before going around the loop again.
98+ const chrono::steady_clock::duration dura (chrono::duration_cast<chrono::steady_clock::duration>(tp - Clock::now ()));
99+ const chrono::steady_clock::duration duramax (chrono::milliseconds (BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
100+ return chrono::steady_clock::now () + (std::min)(dura, duramax);
101+ }
102+
62103} // end detail namespace
63104
64105 template <class T , class Clock = chrono::steady_clock, class TimePoint =typename Clock::time_point>
@@ -88,8 +129,8 @@ namespace detail
88129 T pull ();
89130 void pull (T& elem);
90131
91- template <class WClock , class Duration >
92- queue_op_status pull_until (chrono::time_point<WClock ,Duration> const & tp, T& elem);
132+ template <class Duration >
133+ queue_op_status pull_until (chrono::time_point<clock ,Duration> const & tp, T& elem);
93134 template <class Rep , class Period >
94135 queue_op_status pull_for (chrono::duration<Rep,Period> const & dura, T& elem);
95136
@@ -122,8 +163,9 @@ namespace detail
122163 inline bool not_empty_and_time_reached (lock_guard<mutex>& lk) const ;
123164
124165 bool wait_to_pull (unique_lock<mutex>&);
125- template <class WClock , class Duration >
126- queue_op_status wait_to_pull_until (unique_lock<mutex>&, chrono::time_point<WClock, Duration> const & tp);
166+ queue_op_status wait_to_pull_until (unique_lock<mutex>&, TimePoint const & tp);
167+ template <class Rep , class Period >
168+ queue_op_status wait_to_pull_for (unique_lock<mutex>& lk, chrono::duration<Rep,Period> const & dura);
127169
128170 T pull (unique_lock<mutex>&);
129171 T pull (lock_guard<mutex>&);
@@ -228,14 +270,13 @@ namespace detail
228270 if (not_empty_and_time_reached (lk)) return false ; // success
229271 if (super::closed (lk)) return true ; // closed
230272
231- const time_point tp ( super::data_.top ().time );
232- super::cond_.wait_until (lk, tp );
273+ const time_point tpmin ( detail::limit_timepoint ( super::data_.top ().time ) );
274+ super::cond_.wait_until (lk, tpmin );
233275 }
234276 }
235277
236278 template <class T , class Clock , class TimePoint >
237- template <class WClock , class Duration >
238- queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_until(unique_lock<mutex>& lk, chrono::time_point<WClock, Duration> const & tp)
279+ queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_until(unique_lock<mutex>& lk, TimePoint const & tp)
239280 {
240281 for (;;)
241282 {
@@ -249,7 +290,29 @@ namespace detail
249290 if (super::closed (lk)) return queue_op_status::closed;
250291 if (clock::now () >= tp) return super::empty (lk) ? queue_op_status::timeout : queue_op_status::not_ready;
251292
252- const time_point tpmin (tp < super::data_.top ().time ? tp : super::data_.top ().time );
293+ const time_point tpmin ((std::min)(tp, detail::limit_timepoint (super::data_.top ().time )));
294+ super::cond_.wait_until (lk, tpmin);
295+ }
296+ }
297+
298+ template <class T , class Clock , class TimePoint >
299+ template <class Rep , class Period >
300+ queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_for(unique_lock<mutex>& lk, chrono::duration<Rep,Period> const & dura)
301+ {
302+ const chrono::steady_clock::time_point tp (chrono::steady_clock::now () + chrono::duration_cast<chrono::steady_clock::duration>(dura));
303+ for (;;)
304+ {
305+ if (not_empty_and_time_reached (lk)) return queue_op_status::success;
306+ if (super::closed (lk)) return queue_op_status::closed;
307+ if (chrono::steady_clock::now () >= tp) return super::empty (lk) ? queue_op_status::timeout : queue_op_status::not_ready;
308+
309+ super::wait_until_not_empty_or_closed_until (lk, tp);
310+
311+ if (not_empty_and_time_reached (lk)) return queue_op_status::success;
312+ if (super::closed (lk)) return queue_op_status::closed;
313+ if (chrono::steady_clock::now () >= tp) return super::empty (lk) ? queue_op_status::timeout : queue_op_status::not_ready;
314+
315+ const chrono::steady_clock::time_point tpmin ((std::min)(tp, detail::convert_to_steady_clock_timepoint (super::data_.top ().time )));
253316 super::cond_.wait_until (lk, tpmin);
254317 }
255318 }
@@ -315,12 +378,12 @@ namespace detail
315378
316379 // ////////////////////
317380 template <class T , class Clock , class TimePoint >
318- template <class WClock , class Duration >
381+ template <class Duration >
319382 queue_op_status
320- sync_timed_queue<T, Clock, TimePoint>::pull_until(chrono::time_point<WClock, Duration> const & tp, T& elem)
383+ sync_timed_queue<T, Clock, TimePoint>::pull_until(chrono::time_point<clock, Duration> const & tp, T& elem)
321384 {
322385 unique_lock<mutex> lk (super::mtx_);
323- const queue_op_status rc = wait_to_pull_until (lk, tp );
386+ const queue_op_status rc = wait_to_pull_until (lk, chrono::time_point_cast< typename time_point::duration>(tp) );
324387 if (rc == queue_op_status::success) pull (lk, elem);
325388 return rc;
326389 }
@@ -331,7 +394,10 @@ namespace detail
331394 queue_op_status
332395 sync_timed_queue<T, Clock, TimePoint>::pull_for(chrono::duration<Rep,Period> const & dura, T& elem)
333396 {
334- return pull_until (chrono::steady_clock::now () + dura, elem);
397+ unique_lock<mutex> lk (super::mtx_);
398+ const queue_op_status rc = wait_to_pull_for (lk, dura);
399+ if (rc == queue_op_status::success) pull (lk, elem);
400+ return rc;
335401 }
336402
337403 // /////////////////////////
0 commit comments