diff --git a/include/boost/asio/detail/timer_queue.hpp b/include/boost/asio/detail/timer_queue.hpp index d304f6b0..1d126e9b 100644 --- a/include/boost/asio/detail/timer_queue.hpp +++ b/include/boost/asio/detail/timer_queue.hpp @@ -49,7 +49,9 @@ public: // Constructor. timer_queue() : timers_(), - heap_() + heap_(), + cancelled_timers_(0), + cleanup_timers_(0) { } @@ -112,12 +114,17 @@ public: { timer_base* t = heap_[0]; remove_timer(t); + t->prev_ = 0; + t->next_ = cleanup_timers_; + cleanup_timers_ = t; t->invoke(boost::system::error_code()); } } - // Cancel the timer with the given token. The handler will be invoked - // immediately with the result operation_aborted. + // Cancel the timers with the given token. Any timers pending for the token + // will be notified that they have been cancelled next time + // dispatch_cancellations is called. Returns the number of timers that were + // cancelled. std::size_t cancel_timer(void* timer_token) { std::size_t num_cancelled = 0; @@ -130,7 +137,9 @@ public: { timer_base* next = t->next_; remove_timer(t); - t->invoke(boost::asio::error::operation_aborted); + t->prev_ = 0; + t->next_ = cancelled_timers_; + cancelled_timers_ = t; t = next; ++num_cancelled; } @@ -138,6 +147,31 @@ public: return num_cancelled; } + // Dispatch any pending cancels for timers. + virtual void dispatch_cancellations() + { + while (cancelled_timers_) + { + timer_base* this_timer = cancelled_timers_; + cancelled_timers_ = this_timer->next_; + this_timer->next_ = cleanup_timers_; + cleanup_timers_ = this_timer; + this_timer->invoke(boost::asio::error::operation_aborted); + } + } + + // Destroy timers that are waiting to be cleaned up. + virtual void cleanup_timers() + { + while (cleanup_timers_) + { + timer_base* next_timer = cleanup_timers_->next_; + cleanup_timers_->next_ = 0; + cleanup_timers_->destroy(); + cleanup_timers_ = next_timer; + } + } + // Destroy all timers. virtual void destroy_timers() { @@ -152,6 +186,7 @@ public: } heap_.clear(); timers_.clear(); + cleanup_timers(); } private: @@ -239,8 +274,7 @@ private: static void invoke_handler(timer_base* base, const boost::system::error_code& result) { - std::auto_ptr > t(static_cast*>(base)); - t->handler_(result); + static_cast*>(base)->handler_(result); } // Destroy the handler. @@ -339,6 +373,12 @@ private: // The heap of timers, with the earliest timer at the front. std::vector heap_; + + // The list of timers to be cancelled. + timer_base* cancelled_timers_; + + // The list of timers to be destroyed. + timer_base* cleanup_timers_; }; } // namespace detail diff --git a/include/boost/asio/detail/timer_queue_base.hpp b/include/boost/asio/detail/timer_queue_base.hpp index c788be53..d49e80f6 100644 --- a/include/boost/asio/detail/timer_queue_base.hpp +++ b/include/boost/asio/detail/timer_queue_base.hpp @@ -45,6 +45,12 @@ public: // Dispatch all ready timers. virtual void dispatch_timers() = 0; + // Dispatch any pending cancels for timers. + virtual void dispatch_cancellations() = 0; + + // Destroy timers that are waiting to be cleaned up. + virtual void cleanup_timers() = 0; + // Destroy all timers. virtual void destroy_timers() = 0; };