Update basic_waitable_timer to proposed interface.
diff --git a/asio/include/asio/basic_deadline_timer.hpp b/asio/include/asio/basic_deadline_timer.hpp index 6aef75c..8115bb7 100644 --- a/asio/include/asio/basic_deadline_timer.hpp +++ b/asio/include/asio/basic_deadline_timer.hpp
@@ -164,7 +164,7 @@ : basic_io_object<TimerService>(io_service) { asio::error_code ec; - this->service.expires_at(this->implementation, expiry_time, ec); + this->get_service().expires_at(this->get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_at"); } @@ -183,7 +183,8 @@ : basic_io_object<TimerService>(io_service) { asio::error_code ec; - this->service.expires_from_now(this->implementation, expiry_time, ec); + this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_from_now"); } @@ -212,7 +213,7 @@ std::size_t cancel() { asio::error_code ec; - std::size_t s = this->service.cancel(this->implementation, ec); + std::size_t s = this->get_service().cancel(this->get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); return s; } @@ -241,7 +242,7 @@ */ std::size_t cancel(asio::error_code& ec) { - return this->service.cancel(this->implementation, ec); + return this->get_service().cancel(this->get_implementation(), ec); } /// Cancels one asynchronous operation that is waiting on the timer. @@ -271,7 +272,8 @@ std::size_t cancel_one() { asio::error_code ec; - std::size_t s = this->service.cancel_one(this->implementation, ec); + std::size_t s = this->get_service().cancel_one( + this->get_implementation(), ec); asio::detail::throw_error(ec, "cancel_one"); return s; } @@ -302,7 +304,7 @@ */ std::size_t cancel_one(asio::error_code& ec) { - return this->service.cancel_one(this->implementation, ec); + return this->get_service().cancel_one(this->get_implementation(), ec); } /// Get the timer's expiry time as an absolute time. @@ -312,7 +314,7 @@ */ time_type expires_at() const { - return this->service.expires_at(this->implementation); + return this->get_service().expires_at(this->get_implementation()); } /// Set the timer's expiry time as an absolute time. @@ -340,8 +342,8 @@ std::size_t expires_at(const time_type& expiry_time) { asio::error_code ec; - std::size_t s = this->service.expires_at( - this->implementation, expiry_time, ec); + std::size_t s = this->get_service().expires_at( + this->get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_at"); return s; } @@ -371,7 +373,8 @@ std::size_t expires_at(const time_type& expiry_time, asio::error_code& ec) { - return this->service.expires_at(this->implementation, expiry_time, ec); + return this->get_service().expires_at( + this->get_implementation(), expiry_time, ec); } /// Get the timer's expiry time relative to now. @@ -381,7 +384,7 @@ */ duration_type expires_from_now() const { - return this->service.expires_from_now(this->implementation); + return this->get_service().expires_from_now(this->get_implementation()); } /// Set the timer's expiry time relative to now. @@ -409,8 +412,8 @@ std::size_t expires_from_now(const duration_type& expiry_time) { asio::error_code ec; - std::size_t s = this->service.expires_from_now( - this->implementation, expiry_time, ec); + std::size_t s = this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); asio::detail::throw_error(ec, "expires_from_now"); return s; } @@ -440,8 +443,8 @@ std::size_t expires_from_now(const duration_type& expiry_time, asio::error_code& ec) { - return this->service.expires_from_now( - this->implementation, expiry_time, ec); + return this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); } /// Perform a blocking wait on the timer. @@ -454,7 +457,7 @@ void wait() { asio::error_code ec; - this->service.wait(this->implementation, ec); + this->get_service().wait(this->get_implementation(), ec); asio::detail::throw_error(ec, "wait"); } @@ -467,7 +470,7 @@ */ void wait(asio::error_code& ec) { - this->service.wait(this->implementation, ec); + this->get_service().wait(this->get_implementation(), ec); } /// Start an asynchronous wait on the timer. @@ -503,7 +506,7 @@ // not meet the documented type requirements for a WaitHandler. ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - return this->service.async_wait(this->implementation, + return this->get_service().async_wait(this->get_implementation(), ASIO_MOVE_CAST(WaitHandler)(handler)); } };
diff --git a/asio/include/asio/basic_waitable_timer.hpp b/asio/include/asio/basic_waitable_timer.hpp index 9b3f860..0fbe49b 100644 --- a/asio/include/asio/basic_waitable_timer.hpp +++ b/asio/include/asio/basic_waitable_timer.hpp
@@ -54,7 +54,7 @@ * asio::steady_timer timer(io_service); * * // Set an expiry time relative to now. - * timer.expires_from_now(std::chrono::seconds(5)); + * timer.expires_after(std::chrono::seconds(5)); * * // Wait for the timer to expire. * timer.wait(); @@ -91,7 +91,7 @@ * @code * void on_some_event() * { - * if (my_timer.expires_from_now(seconds(5)) > 0) + * if (my_timer.expires_after(seconds(5)) > 0) * { * // We managed to cancel the timer. Start new asynchronous wait. * my_timer.async_wait(on_timeout); @@ -111,7 +111,7 @@ * } * @endcode * - * @li The asio::basic_waitable_timer::expires_from_now() function + * @li The asio::basic_waitable_timer::expires_after() function * cancels any pending asynchronous waits, and returns the number of * asynchronous waits that were cancelled. If it returns 0 then you were too * late and the wait handler has already been executed, or will soon be @@ -127,6 +127,9 @@ : public basic_io_object<WaitableTimerService> { public: + /// The executor type. + typedef asio::io_service::executor_type executor_type; + /// The clock type. typedef Clock clock_type; @@ -142,8 +145,8 @@ /// Constructor. /** * This constructor creates a timer without setting an expiry time. The - * expires_at() or expires_from_now() functions must be called to set an - * expiry time before the timer can be waited on. + * expires_at() or expires_after() functions must be called to set an expiry + * time before the timer can be waited on. * * @param io_service The io_service object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. @@ -187,11 +190,46 @@ : basic_io_object<WaitableTimerService>(io_service) { asio::error_code ec; - this->get_service().expires_from_now( + this->get_service().expires_after( this->get_implementation(), expiry_time, ec); - asio::detail::throw_error(ec, "expires_from_now"); + asio::detail::throw_error(ec, "expires_after"); } +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_waitable_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(io_service&) constructor. + */ + basic_waitable_timer(basic_waitable_timer&& other) + : basic_io_object<WaitableTimerService>( + ASIO_MOVE_CAST(basic_waitable_timer)(other)) + { + } + + /// Move-assign a basic_waitable_timer from another. + /** + * This assignment operator moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(io_service&) constructor. + */ + basic_waitable_timer& operator=(basic_waitable_timer&& other) + { + basic_io_object<WaitableTimerService>::operator=( + ASIO_MOVE_CAST(basic_waitable_timer)(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Cancel any asynchronous operations that are waiting on the timer. /** * This function forces the completion of any pending asynchronous wait @@ -311,7 +349,9 @@ return this->get_service().cancel_one(this->get_implementation(), ec); } - /// Get the timer's expiry time as an absolute time. +#if defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute + /// time. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. @@ -320,6 +360,17 @@ { return this->get_service().expires_at(this->get_implementation()); } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Get the timer's expiry time as an absolute time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_point expiry() const + { + return this->get_service().expiry(this->get_implementation()); + } /// Set the timer's expiry time as an absolute time. /** @@ -381,7 +432,68 @@ this->get_implementation(), expiry_time, ec); } - /// Get the timer's expiry time relative to now. + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_after() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_after(const duration& expiry_time) + { + asio::error_code ec; + std::size_t s = this->get_service().expires_after( + this->get_implementation(), expiry_time, ec); + asio::detail::throw_error(ec, "expires_after"); + return s; + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_after() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_after(const duration& expiry_time, + asio::error_code& ec) + { + return this->get_service().expires_after( + this->get_implementation(), expiry_time, ec); + } + +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the timer's expiry time relative to now. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. @@ -391,7 +503,8 @@ return this->get_service().expires_from_now(this->get_implementation()); } - /// Set the timer's expiry time relative to now. + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will @@ -422,7 +535,8 @@ return s; } - /// Set the timer's expiry time relative to now. + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will @@ -450,6 +564,7 @@ return this->get_service().expires_from_now( this->get_implementation(), expiry_time, ec); } +#endif // !defined(ASIO_NO_DEPRECATED) /// Perform a blocking wait on the timer. /**
diff --git a/asio/include/asio/deadline_timer_service.hpp b/asio/include/asio/deadline_timer_service.hpp index b4d5aea..2efe935 100644 --- a/asio/include/asio/deadline_timer_service.hpp +++ b/asio/include/asio/deadline_timer_service.hpp
@@ -105,7 +105,7 @@ /// Get the expiry time for the timer as an absolute time. time_type expires_at(const implementation_type& impl) const { - return service_impl_.expires_at(impl); + return service_impl_.expiry(impl); } /// Set the expiry time for the timer as an absolute time. @@ -118,14 +118,14 @@ /// Get the expiry time for the timer relative to now. duration_type expires_from_now(const implementation_type& impl) const { - return service_impl_.expires_from_now(impl); + return TimeTraits::subtract(service_impl_.expiry(impl), TimeTraits::now()); } /// Set the expiry time for the timer relative to now. std::size_t expires_from_now(implementation_type& impl, const duration_type& expiry_time, asio::error_code& ec) { - return service_impl_.expires_from_now(impl, expiry_time, ec); + return service_impl_.expires_after(impl, expiry_time, ec); } // Perform a blocking wait on the timer.
diff --git a/asio/include/asio/detail/deadline_timer_service.hpp b/asio/include/asio/detail/deadline_timer_service.hpp index 50dee9e..3d4aebb 100644 --- a/asio/include/asio/detail/deadline_timer_service.hpp +++ b/asio/include/asio/detail/deadline_timer_service.hpp
@@ -93,6 +93,38 @@ cancel(impl, ec); } + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + if (this != &other_service) + if (impl.might_have_pending_waits) + scheduler_.cancel_timer(timer_queue_, impl.timer_data); + + other_service.scheduler_.move_timer(other_service.timer_queue_, + impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + // Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, asio::error_code& ec) { @@ -131,7 +163,7 @@ } // Get the expiry time for the timer as an absolute time. - time_type expires_at(const implementation_type& impl) const + time_type expiry(const implementation_type& impl) const { return impl.expiry; } @@ -146,14 +178,8 @@ return count; } - // Get the expiry time for the timer relative to now. - duration_type expires_from_now(const implementation_type& impl) const - { - return Time_Traits::subtract(expires_at(impl), Time_Traits::now()); - } - // Set the expiry time for the timer relative to now. - std::size_t expires_from_now(implementation_type& impl, + std::size_t expires_after(implementation_type& impl, const duration_type& expiry_time, asio::error_code& ec) { return expires_at(impl,
diff --git a/asio/include/asio/detail/dev_poll_reactor.hpp b/asio/include/asio/detail/dev_poll_reactor.hpp index a04463b..6ee4183 100644 --- a/asio/include/asio/detail/dev_poll_reactor.hpp +++ b/asio/include/asio/detail/dev_poll_reactor.hpp
@@ -132,6 +132,12 @@ typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + // Run /dev/poll once until interrupted or events are ready to be dispatched. ASIO_DECL void run(bool block, op_queue<operation>& ops);
diff --git a/asio/include/asio/detail/epoll_reactor.hpp b/asio/include/asio/detail/epoll_reactor.hpp index 65da611..5993638 100644 --- a/asio/include/asio/detail/epoll_reactor.hpp +++ b/asio/include/asio/detail/epoll_reactor.hpp
@@ -152,6 +152,12 @@ typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + // Run epoll once until interrupted or events are ready to be dispatched. ASIO_DECL void run(bool block, op_queue<operation>& ops);
diff --git a/asio/include/asio/detail/impl/dev_poll_reactor.hpp b/asio/include/asio/detail/impl/dev_poll_reactor.hpp index d929350..0fcf510 100644 --- a/asio/include/asio/detail/impl/dev_poll_reactor.hpp +++ b/asio/include/asio/detail/impl/dev_poll_reactor.hpp
@@ -68,6 +68,19 @@ return n; } +template <typename Time_Traits> +void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/impl/epoll_reactor.hpp b/asio/include/asio/detail/impl/epoll_reactor.hpp index 91d85d4..b854b53 100644 --- a/asio/include/asio/detail/impl/epoll_reactor.hpp +++ b/asio/include/asio/detail/impl/epoll_reactor.hpp
@@ -66,6 +66,19 @@ return n; } +template <typename Time_Traits> +void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/impl/kqueue_reactor.hpp b/asio/include/asio/detail/impl/kqueue_reactor.hpp index 0f70b0b..f87e862 100644 --- a/asio/include/asio/detail/impl/kqueue_reactor.hpp +++ b/asio/include/asio/detail/impl/kqueue_reactor.hpp
@@ -70,6 +70,19 @@ return n; } +template <typename Time_Traits> +void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/impl/select_reactor.hpp b/asio/include/asio/detail/impl/select_reactor.hpp index 3ca2608..3591906 100644 --- a/asio/include/asio/detail/impl/select_reactor.hpp +++ b/asio/include/asio/detail/impl/select_reactor.hpp
@@ -73,6 +73,19 @@ return n; } +template <typename Time_Traits> +void select_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/impl/win_iocp_io_service.hpp b/asio/include/asio/detail/impl/win_iocp_io_service.hpp index df7ba80..37d6a7f 100644 --- a/asio/include/asio/detail/impl/win_iocp_io_service.hpp +++ b/asio/include/asio/detail/impl/win_iocp_io_service.hpp
@@ -80,6 +80,19 @@ return n; } +template <typename Time_Traits> +void win_iocp_io_service::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(dispatch_mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + post_deferred_completions(ops); +} + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp b/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp index 544758d..f76005a 100644 --- a/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp +++ b/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp
@@ -69,6 +69,19 @@ return n; } +template <typename Time_Traits> +void winrt_timer_scheduler::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/kqueue_reactor.hpp b/asio/include/asio/detail/kqueue_reactor.hpp index 194354d..8df24c1 100644 --- a/asio/include/asio/detail/kqueue_reactor.hpp +++ b/asio/include/asio/detail/kqueue_reactor.hpp
@@ -155,6 +155,12 @@ typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + // Run the kqueue loop. ASIO_DECL void run(bool block, op_queue<operation>& ops);
diff --git a/asio/include/asio/detail/select_reactor.hpp b/asio/include/asio/detail/select_reactor.hpp index 2d67d81..c0a473f 100644 --- a/asio/include/asio/detail/select_reactor.hpp +++ b/asio/include/asio/detail/select_reactor.hpp
@@ -141,6 +141,12 @@ typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + // Run select once until interrupted or events are ready to be dispatched. ASIO_DECL void run(bool block, op_queue<operation>& ops);
diff --git a/asio/include/asio/detail/timer_queue.hpp b/asio/include/asio/detail/timer_queue.hpp index 171619c..df85c07 100644 --- a/asio/include/asio/detail/timer_queue.hpp +++ b/asio/include/asio/detail/timer_queue.hpp
@@ -46,7 +46,11 @@ class per_timer_data { public: - per_timer_data() : next_(0), prev_(0) {} + per_timer_data() : + heap_index_((std::numeric_limits<std::size_t>::max)()), + next_(0), prev_(0) + { + } private: friend class timer_queue; @@ -188,6 +192,29 @@ return num_cancelled; } + // Move operations from one timer to another, empty timer. + void move_timer(per_timer_data& to, per_timer_data& from) + { + to.op_queue_.push(from.op_queue_); + + to.heap_index_ = from.heap_index_; + from.heap_index_ = (std::numeric_limits<std::size_t>::max)(); + + if (to.heap_index_ < heap_.size()) + heap_[to.heap_index_].timer_ = &to; + + if (timers_ == &from) + timers_ = &to; + if (from.prev_) + from.prev_->next_ = &to; + if (from.next_) + from.next_->prev_= &to; + to.next_ = from.next_; + to.prev_ = from.prev_; + from.next_ = 0; + from.prev_ = 0; + } + private: // Move the item at the given index up the heap to its correct position. void up_heap(std::size_t index)
diff --git a/asio/include/asio/detail/win_iocp_io_service.hpp b/asio/include/asio/detail/win_iocp_io_service.hpp index ad6f92f..fbfbd32 100644 --- a/asio/include/asio/detail/win_iocp_io_service.hpp +++ b/asio/include/asio/detail/win_iocp_io_service.hpp
@@ -191,6 +191,12 @@ typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + private: #if defined(WINVER) && (WINVER < 0x0500) typedef DWORD dword_ptr_t;
diff --git a/asio/include/asio/detail/winrt_timer_scheduler.hpp b/asio/include/asio/detail/winrt_timer_scheduler.hpp index b4cbb63..459746f 100644 --- a/asio/include/asio/detail/winrt_timer_scheduler.hpp +++ b/asio/include/asio/detail/winrt_timer_scheduler.hpp
@@ -81,6 +81,12 @@ typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + private: // Run the select loop in the thread. ASIO_DECL void run_thread();
diff --git a/asio/include/asio/ssl/detail/io.hpp b/asio/include/asio/ssl/detail/io.hpp index c31b744..0916bea 100644 --- a/asio/include/asio/ssl/detail/io.hpp +++ b/asio/include/asio/ssl/detail/io.hpp
@@ -148,7 +148,7 @@ // cannot allow more than one read operation at a time on the // underlying transport. The pending_read_ timer's expiry is set to // pos_infin if a read is in progress, and neg_infin otherwise. - if (core_.pending_read_.expires_at() == core_.neg_infin()) + if (core_.expiry(core_.pending_read_) == core_.neg_infin()) { // Prevent other read operations from being started. core_.pending_read_.expires_at(core_.pos_infin()); @@ -175,7 +175,7 @@ // cannot allow more than one write operation at a time on the // underlying transport. The pending_write_ timer's expiry is set to // pos_infin if a write is in progress, and neg_infin otherwise. - if (core_.pending_write_.expires_at() == core_.neg_infin()) + if (core_.expiry(core_.pending_write_) == core_.neg_infin()) { // Prevent other write operations from being started. core_.pending_write_.expires_at(core_.pos_infin());
diff --git a/asio/include/asio/ssl/detail/stream_core.hpp b/asio/include/asio/ssl/detail/stream_core.hpp index cfce0ff..c45c78f 100644 --- a/asio/include/asio/ssl/detail/stream_core.hpp +++ b/asio/include/asio/ssl/detail/stream_core.hpp
@@ -75,6 +75,13 @@ { return boost::posix_time::pos_infin; } + + // Helper function to get a timer's expiry time. + static asio::deadline_timer::time_type expiry( + const asio::deadline_timer& timer) + { + return timer.expires_at(); + } #else // defined(ASIO_HAS_BOOST_DATE_TIME) // Timer used for storing queued read operations. asio::steady_timer pending_read_; @@ -93,6 +100,13 @@ { return (asio::steady_timer::time_point::max)(); } + + // Helper function to get a timer's expiry time. + static asio::steady_timer::time_point expiry( + const asio::steady_timer& timer) + { + return timer.expiry(); + } #endif // defined(ASIO_HAS_BOOST_DATE_TIME) // Buffer space used to prepare output intended for the transport.
diff --git a/asio/include/asio/wait_traits.hpp b/asio/include/asio/wait_traits.hpp index 3b2218f..dec13d5 100644 --- a/asio/include/asio/wait_traits.hpp +++ b/asio/include/asio/wait_traits.hpp
@@ -24,7 +24,7 @@ struct wait_traits { /// Convert a clock duration into a duration used for waiting. - /** + /** * @returns @c d. */ static typename Clock::duration to_wait_duration( @@ -32,6 +32,21 @@ { return d; } + + /// Convert a clock duration into a duration used for waiting. + /** + * @returns @c d. + */ + static typename Clock::duration to_wait_duration( + const typename Clock::time_point& t) + { + typename Clock::time_point now = Clock::now(); + if (now + Clock::duration::max() < t) + return Clock::duration::max(); + if (now + Clock::duration::min() > t) + return Clock::duration::min(); + return t - now; + } }; } // namespace asio
diff --git a/asio/include/asio/waitable_timer_service.hpp b/asio/include/asio/waitable_timer_service.hpp index 3aac26c..8760af4 100644 --- a/asio/include/asio/waitable_timer_service.hpp +++ b/asio/include/asio/waitable_timer_service.hpp
@@ -89,6 +89,23 @@ service_impl_.destroy(impl); } +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a new timer implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + service_impl_.move_construct(impl, other_impl); + } + + /// Move-assign from another timer implementation. + void move_assign(implementation_type& impl, + waitable_timer_service& other_service, + implementation_type& other_impl) + { + service_impl_.move_assign(impl, other_service.service_impl_, other_impl); + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, asio::error_code& ec) { @@ -102,10 +119,19 @@ return service_impl_.cancel_one(impl, ec); } - /// Get the expiry time for the timer as an absolute time. +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the expiry time for the timer as an + /// absolute time. time_point expires_at(const implementation_type& impl) const { - return service_impl_.expires_at(impl); + return service_impl_.expiry(impl); + } +#endif // !defined(ASIO_NO_DEPRECATED) + + /// Get the expiry time for the timer as an absolute time. + time_point expiry(const implementation_type& impl) const + { + return service_impl_.expiry(impl); } /// Set the expiry time for the timer as an absolute time. @@ -115,18 +141,30 @@ return service_impl_.expires_at(impl, expiry_time, ec); } - /// Get the expiry time for the timer relative to now. - duration expires_from_now(const implementation_type& impl) const + /// Set the expiry time for the timer relative to now. + std::size_t expires_after(implementation_type& impl, + const duration& expiry_time, asio::error_code& ec) { - return service_impl_.expires_from_now(impl); + return service_impl_.expires_after(impl, expiry_time, ec); } - /// Set the expiry time for the timer relative to now. +#if !defined(ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the expiry time for the timer relative to + /// now. + duration expires_from_now(const implementation_type& impl) const + { + typedef detail::chrono_time_traits<Clock, WaitTraits> traits; + return traits::subtract(service_impl_.expiry(impl), traits::now()); + } + + /// (Deprecated: Use expires_after().) Set the expiry time for the timer + /// relative to now. std::size_t expires_from_now(implementation_type& impl, const duration& expiry_time, asio::error_code& ec) { - return service_impl_.expires_from_now(impl, expiry_time, ec); + return service_impl_.expires_after(impl, expiry_time, ec); } +#endif // !defined(ASIO_NO_DEPRECATED) // Perform a blocking wait on the timer. void wait(implementation_type& impl, asio::error_code& ec)
diff --git a/asio/src/doc/requirements/WaitTraits.qbk b/asio/src/doc/requirements/WaitTraits.qbk index 19aaed1..a77190e 100644 --- a/asio/src/doc/requirements/WaitTraits.qbk +++ b/asio/src/doc/requirements/WaitTraits.qbk
@@ -8,8 +8,9 @@ [section:WaitTraits Wait traits requirements] In the table below, `X` denotes a wait traits class for clock type `Clock`, -where `Clock` meets the C++11 type requirements for a clock, and `d` denotes -a value of type `Clock::duration`. +where `Clock` meets the C++11 type requirements for a clock, `t` denotes a +value of type `Clock::time_point`, and `d` denotes a value of type +`Clock::duration`. [table WaitTraits requirements [[expression] [return type] [assertion/note\npre/post-condition]] @@ -18,7 +19,15 @@ [`Clock::duration`] [ Returns the maximum duration to be used for an individual, - implementation-defined wait operation. + implementation-defined wait operation for the duration `d`. + ] + ] + [ + [`X::to_wait_duration(t);`] + [`Clock::duration`] + [ + Returns the maximum duration to be used for an individual, + implementation-defined wait operation until the time point `t`. ] ] ]
diff --git a/asio/src/doc/requirements/WaitableTimerService.qbk b/asio/src/doc/requirements/WaitableTimerService.qbk index a8faf6c..51d0981 100644 --- a/asio/src/doc/requirements/WaitableTimerService.qbk +++ b/asio/src/doc/requirements/WaitableTimerService.qbk
@@ -42,7 +42,7 @@ ] ] [ - [`a.expires_at(b);`] + [`a.expiry(b);`] [`Clock::time_point`] [] ] @@ -58,15 +58,8 @@ ] ] [ - [`a.expires_from_now(b);`] - [`Clock::duration`] - [ - Returns a value equivalent to `a.expires_at(b) - Clock::now()`. - ] - ] - [ [`` - a.expires_from_now(b, d, e); + a.expires_after(b, d, e); ``] [`size_t`] [
diff --git a/asio/src/tests/unit/strand.cpp b/asio/src/tests/unit/strand.cpp index 93fd02e..da2ed00 100644 --- a/asio/src/tests/unit/strand.cpp +++ b/asio/src/tests/unit/strand.cpp
@@ -151,10 +151,18 @@ timer timer1(ios, chronons::seconds(3)); timer1.wait(); ASIO_CHECK(count == 0); +#if defined(ASIO_HAS_BOOST_DATE_TIME) timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif defined(ASIO_HAS_BOOST_DATE_TIME) timer1.wait(); ASIO_CHECK(count == 1); +#if defined(ASIO_HAS_BOOST_DATE_TIME) timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif defined(ASIO_HAS_BOOST_DATE_TIME) timer1.wait(); ASIO_CHECK(count == 2);
diff --git a/asio/src/tests/unit/system_timer.cpp b/asio/src/tests/unit/system_timer.cpp index 1d392c5..021ee33 100644 --- a/asio/src/tests/unit/system_timer.cpp +++ b/asio/src/tests/unit/system_timer.cpp
@@ -55,7 +55,7 @@ int before_value = *count; - t->expires_at(t->expires_at() + chronons::seconds(1)); + t->expires_at(t->expiry() + chronons::seconds(1)); t->async_wait(bindns::bind(decrement_to_zero, t, count)); // Completion cannot nest, so count value should remain unchanged. @@ -119,7 +119,7 @@ expected_end = start + seconds(1) + microseconds(500000); ASIO_CHECK(expected_end < end || expected_end == end); - t2.expires_at(t2.expires_at() + seconds(1)); + t2.expires_at(t2.expiry() + seconds(1)); t2.wait(); // The timer must block until after its expiry time. @@ -129,7 +129,7 @@ start = now(); - t2.expires_from_now(seconds(1) + microseconds(200000)); + t2.expires_after(seconds(1) + microseconds(200000)); t2.wait(); // The timer must block until after its expiry time. @@ -327,13 +327,13 @@ asio::thread th(bindns::bind(io_service_run, &ios)); - t2.expires_from_now(chronons::seconds(2)); + t2.expires_after(chronons::seconds(2)); t2.wait(); - t1.expires_from_now(chronons::seconds(2)); + t1.expires_after(chronons::seconds(2)); t1.async_wait(bindns::bind(increment, &count)); - t2.expires_from_now(chronons::seconds(4)); + t2.expires_after(chronons::seconds(4)); t2.wait(); ios.stop(); @@ -342,6 +342,39 @@ ASIO_CHECK(count == 1); } +#if defined(ASIO_HAS_MOVE) +asio::system_timer make_timer(asio::io_service& ios, int* count) +{ + asio::system_timer t(ios); + t.expires_after(std::chrono::seconds(1)); + t.async_wait(bindns::bind(increment, count)); + return t; +} +#endif + +void system_timer_move_test() +{ +#if defined(ASIO_HAS_MOVE) + asio::io_service io_service1; + asio::io_service io_service2; + int count = 0; + + asio::system_timer t1 = make_timer(io_service1, &count); + asio::system_timer t2 = make_timer(io_service2, &count); + asio::system_timer t3 = std::move(t1); + + t2 = std::move(t1); + + io_service2.run(); + + ASIO_CHECK(count == 1); + + io_service1.run(); + + ASIO_CHECK(count == 2); +#endif // defined(ASIO_HAS_MOVE) +} + ASIO_TEST_SUITE ( "system_timer", @@ -349,6 +382,7 @@ ASIO_TEST_CASE(system_timer_cancel_test) ASIO_TEST_CASE(system_timer_custom_allocation_test) ASIO_TEST_CASE(system_timer_thread_test) + ASIO_TEST_CASE(system_timer_move_test) ) #else // defined(ASIO_HAS_STD_CHRONO) ASIO_TEST_SUITE