Boost logo

Boost-Commit :

From: chris_at_[hidden]
Date: 2008-05-21 05:25:14


Author: chris_kohlhoff
Date: 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
New Revision: 45600
URL: http://svn.boost.org/trac/boost/changeset/45600

Log:
Implement custom allocation support for timer operations.

Text files modified:
   trunk/boost/asio/detail/deadline_timer_service.hpp | 13 +++--
   trunk/boost/asio/detail/dev_poll_reactor.hpp | 10 ++--
   trunk/boost/asio/detail/epoll_reactor.hpp | 10 ++--
   trunk/boost/asio/detail/kqueue_reactor.hpp | 10 ++--
   trunk/boost/asio/detail/select_reactor.hpp | 10 ++--
   trunk/boost/asio/detail/timer_queue.hpp | 89 ++++++++++++++++++++++++++-------------
   trunk/boost/asio/detail/timer_queue_base.hpp | 4
   trunk/boost/asio/detail/win_iocp_io_service.hpp | 2
   8 files changed, 89 insertions(+), 59 deletions(-)

Modified: trunk/boost/asio/detail/deadline_timer_service.hpp
==============================================================================
--- trunk/boost/asio/detail/deadline_timer_service.hpp (original)
+++ trunk/boost/asio/detail/deadline_timer_service.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -26,6 +26,7 @@
 #include <boost/asio/error.hpp>
 #include <boost/asio/io_service.hpp>
 #include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/handler_base_from_member.hpp>
 #include <boost/asio/detail/noncopyable.hpp>
 #include <boost/asio/detail/service_base.hpp>
 #include <boost/asio/detail/socket_ops.hpp>
@@ -154,25 +155,25 @@
   }
 
   template <typename Handler>
- class wait_handler
+ class wait_handler :
+ public handler_base_from_member<Handler>
   {
   public:
     wait_handler(boost::asio::io_service& io_service, Handler handler)
- : io_service_(io_service),
- work_(io_service),
- handler_(handler)
+ : handler_base_from_member<Handler>(handler),
+ io_service_(io_service),
+ work_(io_service)
     {
     }
 
     void operator()(const boost::system::error_code& result)
     {
- io_service_.post(detail::bind_handler(handler_, result));
+ io_service_.post(detail::bind_handler(this->handler_, result));
     }
 
   private:
     boost::asio::io_service& io_service_;
     boost::asio::io_service::work work_;
- Handler handler_;
   };
 
   // Start an asynchronous wait on the timer.

Modified: trunk/boost/asio/detail/dev_poll_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/dev_poll_reactor.hpp (original)
+++ trunk/boost/asio/detail/dev_poll_reactor.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -340,7 +340,7 @@
     // Check if the thread is supposed to stop.
     if (stop_thread_)
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -349,7 +349,7 @@
     if (!block && read_op_queue_.empty() && write_op_queue_.empty()
         && except_op_queue_.empty() && all_timer_queues_are_empty())
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -475,7 +475,7 @@
       cancel_ops_unlocked(pending_cancellations_[i]);
     pending_cancellations_.clear();
 
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
   }
 
   // Run the select loop in the thread.
@@ -575,7 +575,7 @@
   // destructors may make calls back into this reactor. We make a copy of the
   // vector of timer queues since the original may be modified while the lock
   // is not held.
- void complete_operations_and_cleanup_timers(
+ void complete_operations_and_timers(
       boost::asio::detail::mutex::scoped_lock& lock)
   {
     timer_queues_for_cleanup_ = timer_queues_;
@@ -584,7 +584,7 @@
     write_op_queue_.complete_operations();
     except_op_queue_.complete_operations();
     for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->cleanup_timers();
+ timer_queues_for_cleanup_[i]->complete_timers();
   }
 
   // Add a pending event entry for the given descriptor.

Modified: trunk/boost/asio/detail/epoll_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/epoll_reactor.hpp (original)
+++ trunk/boost/asio/detail/epoll_reactor.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -436,7 +436,7 @@
     // Check if the thread is supposed to stop.
     if (stop_thread_)
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -445,7 +445,7 @@
     if (!block && read_op_queue_.empty() && write_op_queue_.empty()
         && except_op_queue_.empty() && all_timer_queues_are_empty())
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -552,7 +552,7 @@
     need_epoll_wait_ = !read_op_queue_.empty()
       || !write_op_queue_.empty() || !except_op_queue_.empty();
 
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
   }
 
   // Run the select loop in the thread.
@@ -655,7 +655,7 @@
   // destructors may make calls back into this reactor. We make a copy of the
   // vector of timer queues since the original may be modified while the lock
   // is not held.
- void complete_operations_and_cleanup_timers(
+ void complete_operations_and_timers(
       boost::asio::detail::mutex::scoped_lock& lock)
   {
     timer_queues_for_cleanup_ = timer_queues_;
@@ -664,7 +664,7 @@
     write_op_queue_.complete_operations();
     except_op_queue_.complete_operations();
     for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->cleanup_timers();
+ timer_queues_for_cleanup_[i]->complete_timers();
   }
 
   // Mutex to protect access to internal data.

Modified: trunk/boost/asio/detail/kqueue_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/kqueue_reactor.hpp (original)
+++ trunk/boost/asio/detail/kqueue_reactor.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -403,7 +403,7 @@
     // Check if the thread is supposed to stop.
     if (stop_thread_)
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -412,7 +412,7 @@
     if (!block && read_op_queue_.empty() && write_op_queue_.empty()
         && except_op_queue_.empty() && all_timer_queues_are_empty())
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -536,7 +536,7 @@
     need_kqueue_wait_ = !read_op_queue_.empty()
       || !write_op_queue_.empty() || !except_op_queue_.empty();
 
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
   }
 
   // Run the select loop in the thread.
@@ -637,7 +637,7 @@
   // destructors may make calls back into this reactor. We make a copy of the
   // vector of timer queues since the original may be modified while the lock
   // is not held.
- void complete_operations_and_cleanup_timers(
+ void complete_operations_and_timers(
       boost::asio::detail::mutex::scoped_lock& lock)
   {
     timer_queues_for_cleanup_ = timer_queues_;
@@ -646,7 +646,7 @@
     write_op_queue_.complete_operations();
     except_op_queue_.complete_operations();
     for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->cleanup_timers();
+ timer_queues_for_cleanup_[i]->complete_timers();
   }
 
   // Mutex to protect access to internal data.

Modified: trunk/boost/asio/detail/select_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/select_reactor.hpp (original)
+++ trunk/boost/asio/detail/select_reactor.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -320,7 +320,7 @@
     // Check if the thread is supposed to stop.
     if (stop_thread_)
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -329,7 +329,7 @@
     if (!block && read_op_queue_.empty() && write_op_queue_.empty()
         && except_op_queue_.empty() && all_timer_queues_are_empty())
     {
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
       return;
     }
 
@@ -392,7 +392,7 @@
       cancel_ops_unlocked(pending_cancellations_[i]);
     pending_cancellations_.clear();
 
- complete_operations_and_cleanup_timers(lock);
+ complete_operations_and_timers(lock);
   }
 
   // Run the select loop in the thread.
@@ -477,7 +477,7 @@
   // destructors may make calls back into this reactor. We make a copy of the
   // vector of timer queues since the original may be modified while the lock
   // is not held.
- void complete_operations_and_cleanup_timers(
+ void complete_operations_and_timers(
       boost::asio::detail::mutex::scoped_lock& lock)
   {
     timer_queues_for_cleanup_ = timer_queues_;
@@ -486,7 +486,7 @@
     write_op_queue_.complete_operations();
     except_op_queue_.complete_operations();
     for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->cleanup_timers();
+ timer_queues_for_cleanup_[i]->complete_timers();
   }
 
   // Mutex to protect access to internal data.

Modified: trunk/boost/asio/detail/timer_queue.hpp
==============================================================================
--- trunk/boost/asio/detail/timer_queue.hpp (original)
+++ trunk/boost/asio/detail/timer_queue.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -27,6 +27,7 @@
 #include <boost/asio/detail/pop_options.hpp>
 
 #include <boost/asio/error.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
 #include <boost/asio/detail/hash_map.hpp>
 #include <boost/asio/detail/noncopyable.hpp>
 #include <boost/asio/detail/timer_queue_base.hpp>
@@ -51,7 +52,7 @@
     : timers_(),
       heap_(),
       cancelled_timers_(0),
- cleanup_timers_(0)
+ complete_timers_(0)
   {
   }
 
@@ -116,10 +117,10 @@
     {
       timer_base* t = heap_[0];
       remove_timer(t);
+ t->result_ = boost::system::error_code();
       t->prev_ = 0;
- t->next_ = cleanup_timers_;
- cleanup_timers_ = t;
- t->invoke(boost::system::error_code());
+ t->next_ = complete_timers_;
+ complete_timers_ = t;
     }
   }
 
@@ -155,17 +156,23 @@
     while (cancelled_timers_)
     {
       timer_base* this_timer = cancelled_timers_;
+ this_timer->result_ = boost::asio::error::operation_aborted;
       cancelled_timers_ = this_timer->next_;
- this_timer->next_ = cleanup_timers_;
- cleanup_timers_ = this_timer;
- this_timer->invoke(boost::asio::error::operation_aborted);
+ this_timer->next_ = complete_timers_;
+ complete_timers_ = this_timer;
     }
   }
 
- // Destroy timers that are waiting to be cleaned up.
- virtual void cleanup_timers()
+ // Complete any timers that are waiting to be completed.
+ virtual void complete_timers()
   {
- destroy_timer_list(cleanup_timers_);
+ while (complete_timers_)
+ {
+ timer_base* this_timer = complete_timers_;
+ complete_timers_ = this_timer->next_;
+ this_timer->next_ = 0;
+ this_timer->complete();
+ }
   }
 
   // Destroy all timers.
@@ -183,7 +190,7 @@
     heap_.clear();
     timers_.clear();
     destroy_timer_list(cancelled_timers_);
- destroy_timer_list(cleanup_timers_);
+ destroy_timer_list(complete_timers_);
   }
 
 private:
@@ -192,27 +199,27 @@
   class timer_base
   {
   public:
- // Perform the timer operation and then destroy.
- void invoke(const boost::system::error_code& result)
+ // Delete the timer and post the handler.
+ void complete()
     {
- invoke_func_(this, result);
+ complete_func_(this, result_);
     }
 
- // Destroy the timer operation.
+ // Delete the timer.
     void destroy()
     {
       destroy_func_(this);
     }
 
   protected:
- typedef void (*invoke_func_type)(timer_base*,
+ typedef void (*complete_func_type)(timer_base*,
         const boost::system::error_code&);
     typedef void (*destroy_func_type)(timer_base*);
 
     // Constructor.
- timer_base(invoke_func_type invoke_func, destroy_func_type destroy_func,
+ timer_base(complete_func_type complete_func, destroy_func_type destroy_func,
         const time_type& time, void* token)
- : invoke_func_(invoke_func),
+ : complete_func_(complete_func),
         destroy_func_(destroy_func),
         time_(time),
         token_(token),
@@ -231,13 +238,16 @@
   private:
     friend class timer_queue<Time_Traits>;
 
- // The function to be called to dispatch the handler.
- invoke_func_type invoke_func_;
+ // The function to be called to delete the timer and post the handler.
+ complete_func_type complete_func_;
 
- // The function to be called to destroy the handler.
+ // The function to be called to delete the timer.
     destroy_func_type destroy_func_;
 
- // The time when the operation should fire.
+ // The result of the timer operation.
+ boost::system::error_code result_;
+
+ // The time when the timer should fire.
     time_type time_;
 
     // The token associated with the timer.
@@ -261,23 +271,42 @@
   public:
     // Constructor.
     timer(const time_type& time, Handler handler, void* token)
- : timer_base(&timer<Handler>::invoke_handler,
+ : timer_base(&timer<Handler>::complete_handler,
           &timer<Handler>::destroy_handler, time, token),
         handler_(handler)
     {
     }
 
- // Invoke the handler and then destroy it.
- static void invoke_handler(timer_base* base,
+ // Delete the timer and post the handler.
+ static void complete_handler(timer_base* base,
         const boost::system::error_code& result)
     {
- static_cast<timer<Handler>*>(base)->handler_(result);
+ // Take ownership of the timer object.
+ typedef timer<Handler> this_type;
+ this_type* this_timer(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
+
+ // Make a copy of the error_code and the handler so that the memory can
+ // be deallocated before the upcall is made.
+ boost::system::error_code ec(result);
+ Handler handler(this_timer->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ handler(ec);
     }
 
- // Destroy the handler.
+ // Delete the timer.
     static void destroy_handler(timer_base* base)
     {
- delete static_cast<timer<Handler>*>(base);
+ // Take ownership of the timer object.
+ typedef timer<Handler> this_type;
+ this_type* this_timer(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
     }
 
   private:
@@ -386,8 +415,8 @@
   // The list of timers to be cancelled.
   timer_base* cancelled_timers_;
 
- // The list of timers to be destroyed.
- timer_base* cleanup_timers_;
+ // The list of timers waiting to be completed.
+ timer_base* complete_timers_;
 };
 
 } // namespace detail

Modified: trunk/boost/asio/detail/timer_queue_base.hpp
==============================================================================
--- trunk/boost/asio/detail/timer_queue_base.hpp (original)
+++ trunk/boost/asio/detail/timer_queue_base.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -48,8 +48,8 @@
   // 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;
+ // Complete all timers that are waiting to be completed.
+ virtual void complete_timers() = 0;
 
   // Destroy all timers.
   virtual void destroy_timers() = 0;

Modified: trunk/boost/asio/detail/win_iocp_io_service.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_io_service.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_io_service.hpp 2008-05-21 05:25:12 EDT (Wed, 21 May 2008)
@@ -436,7 +436,7 @@
           {
             timer_queues_copy_[i]->dispatch_timers();
             timer_queues_copy_[i]->dispatch_cancellations();
- timer_queues_copy_[i]->cleanup_timers();
+ timer_queues_copy_[i]->complete_timers();
           }
         }
         catch (...)


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk