|
Boost-Commit : |
From: chris_at_[hidden]
Date: 2007-09-20 18:26:55
Author: chris_kohlhoff
Date: 2007-09-20 18:26:55 EDT (Thu, 20 Sep 2007)
New Revision: 39430
URL: http://svn.boost.org/trac/boost/changeset/39430
Log:
Move handler queue management to a separate class.
Added:
trunk/boost/asio/detail/handler_queue.hpp (contents, props changed)
Text files modified:
trunk/boost/asio/detail/task_io_service.hpp | 154 ++++-----------------------------------
1 files changed, 18 insertions(+), 136 deletions(-)
Added: trunk/boost/asio/detail/handler_queue.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/detail/handler_queue.hpp 2007-09-20 18:26:55 EDT (Thu, 20 Sep 2007)
@@ -0,0 +1,221 @@
+//
+// handler_queue.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class handler_queue
+ : noncopyable
+{
+public:
+ // Base class for handlers in the queue.
+ class handler
+ : private noncopyable
+ {
+ public:
+ void invoke()
+ {
+ invoke_func_(this);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*invoke_func_type)(handler*);
+ typedef void (*destroy_func_type)(handler*);
+
+ handler(invoke_func_type invoke_func,
+ destroy_func_type destroy_func)
+ : next_(0),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ }
+
+ ~handler()
+ {
+ }
+
+ private:
+ friend class handler_queue;
+ handler* next_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ // Smart point to manager handler lifetimes.
+ class scoped_ptr
+ : noncopyable
+ {
+ public:
+ explicit scoped_ptr(handler* h)
+ : handler_(h)
+ {
+ }
+
+ ~scoped_ptr()
+ {
+ if (handler_)
+ handler_->destroy();
+ }
+
+ handler* get() const
+ {
+ return handler_;
+ }
+
+ handler* release()
+ {
+ handler* tmp = handler_;
+ handler_ = 0;
+ return tmp;
+ }
+
+ private:
+ handler* handler_;
+ };
+
+ // Constructor.
+ handler_queue()
+ : front_(0),
+ back_(0)
+ {
+ }
+
+ // Wrap a handler to be pushed into the queue.
+ template <typename Handler>
+ static handler* wrap(Handler h)
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(h);
+ handler_ptr<alloc_traits> ptr(raw_ptr, h);
+ return ptr.release();
+ }
+
+ // Get the handler at the front of the queue.
+ handler* front()
+ {
+ return front_;
+ }
+
+ // Pop a handler from the front of the queue.
+ void pop()
+ {
+ if (front_)
+ {
+ handler* tmp = front_;
+ front_ = front_->next_;
+ if (front_ == 0)
+ back_ = 0;
+ tmp->next_= 0;
+ }
+ }
+
+ // Push a handler on to the back of the queue.
+ void push(handler* h)
+ {
+ h->next_ = 0;
+ if (back_)
+ {
+ back_->next_ = h;
+ back_ = h;
+ }
+ else
+ {
+ front_ = back_ = h;
+ }
+ }
+
+ // Whether the queue is empty.
+ bool empty() const
+ {
+ return front_ == 0;
+ }
+
+private:
+ // Template wrapper for handlers.
+ template <typename Handler>
+ class handler_wrapper
+ : public handler
+ {
+ public:
+ handler_wrapper(Handler h)
+ : handler(
+ &handler_wrapper<Handler>::do_call,
+ &handler_wrapper<Handler>::do_destroy),
+ handler_(h)
+ {
+ }
+
+ static void do_call(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(h->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void do_destroy(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // The front of the queue.
+ handler* front_;
+
+ // The back of the queue.
+ handler* back_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
Modified: trunk/boost/asio/detail/task_io_service.hpp
==============================================================================
--- trunk/boost/asio/detail/task_io_service.hpp (original)
+++ trunk/boost/asio/detail/task_io_service.hpp 2007-09-20 18:26:55 EDT (Thu, 20 Sep 2007)
@@ -22,6 +22,7 @@
#include <boost/asio/detail/event.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_queue.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/service_base.hpp>
#include <boost/asio/detail/task_io_service_fwd.hpp>
@@ -42,12 +43,11 @@
task_(use_service<Task>(io_service)),
task_interrupted_(true),
outstanding_work_(0),
- handler_queue_(&task_handler_),
- handler_queue_end_(&task_handler_),
stopped_(false),
shutdown_(false),
first_idle_thread_(0)
{
+ handler_queue_.push(&task_handler_);
}
void init(size_t /*concurrency_hint*/)
@@ -62,17 +62,16 @@
lock.unlock();
// Destroy handler objects.
- while (handler_queue_)
+ while (!handler_queue_.empty())
{
- handler_base* h = handler_queue_;
- handler_queue_ = h->next_;
+ handler_queue::handler* h = handler_queue_.front();
+ handler_queue_.pop();
if (h != &task_handler_)
h->destroy();
}
// Reset handler queue to initial state.
- handler_queue_ = &task_handler_;
- handler_queue_end_ = &task_handler_;
+ handler_queue_.push(&task_handler_);
}
// Run the event loop until interrupted or no more work.
@@ -173,10 +172,7 @@
void post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- typedef handler_wrapper<Handler> value_type;
- typedef handler_alloc_traits<Handler, value_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
boost::asio::detail::mutex::scoped_lock lock(mutex_);
@@ -185,15 +181,7 @@
return;
// Add the handler to the end of the queue.
- if (handler_queue_end_)
- {
- handler_queue_end_->next_ = ptr.get();
- handler_queue_end_ = ptr.get();
- }
- else
- {
- handler_queue_ = handler_queue_end_ = ptr.get();
- }
+ handler_queue_.push(ptr.get());
ptr.release();
// An undelivered handler is treated as unfinished work.
@@ -227,18 +215,15 @@
bool task_has_run = false;
while (!stopped_)
{
- if (handler_queue_)
+ if (!handler_queue_.empty())
{
// Prepare to execute first handler from queue.
- handler_base* h = handler_queue_;
- handler_queue_ = h->next_;
- if (handler_queue_ == 0)
- handler_queue_end_ = 0;
- h->next_ = 0;
+ handler_queue::handler* h = handler_queue_.front();
+ handler_queue_.pop();
if (h == &task_handler_)
{
- bool more_handlers = (handler_queue_ != 0);
+ bool more_handlers = (!handler_queue_.empty());
task_interrupted_ = more_handlers || polling;
lock.unlock();
@@ -263,7 +248,7 @@
handler_cleanup c(lock, *this);
// Invoke the handler. May throw an exception.
- h->call(); // call() deletes the handler object
+ h->invoke(); // invoke() deletes the handler object
ec = boost::system::error_code();
return 1;
@@ -330,93 +315,6 @@
}
}
- class task_cleanup;
- friend class task_cleanup;
-
- // The base class for all handler wrappers. A function pointer is used
- // instead of virtual functions to avoid the associated overhead.
- class handler_base
- {
- public:
- typedef void (*call_func_type)(handler_base*);
- typedef void (*destroy_func_type)(handler_base*);
-
- handler_base(call_func_type call_func, destroy_func_type destroy_func)
- : next_(0),
- call_func_(call_func),
- destroy_func_(destroy_func)
- {
- }
-
- void call()
- {
- call_func_(this);
- }
-
- void destroy()
- {
- destroy_func_(this);
- }
-
- protected:
- // Prevent deletion through this type.
- ~handler_base()
- {
- }
-
- private:
- friend class task_io_service<Task>;
- friend class task_cleanup;
- handler_base* next_;
- call_func_type call_func_;
- destroy_func_type destroy_func_;
- };
-
- // Template wrapper for handlers.
- template <typename Handler>
- class handler_wrapper
- : public handler_base
- {
- public:
- handler_wrapper(Handler handler)
- : handler_base(&handler_wrapper<Handler>::do_call,
- &handler_wrapper<Handler>::do_destroy),
- handler_(handler)
- {
- }
-
- static void do_call(handler_base* base)
- {
- // Take ownership of the handler object.
- typedef handler_wrapper<Handler> this_type;
- this_type* h(static_cast<this_type*>(base));
- typedef handler_alloc_traits<Handler, this_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(h->handler_, h);
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(h->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Make the upcall.
- asio_handler_invoke_helpers::invoke(handler, &handler);
- }
-
- static void do_destroy(handler_base* base)
- {
- // Take ownership of the handler object.
- typedef handler_wrapper<Handler> this_type;
- this_type* h(static_cast<this_type*>(base));
- typedef handler_alloc_traits<Handler, this_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(h->handler_, h);
- }
-
- private:
- Handler handler_;
- };
-
// Helper class to perform task-related operations on block exit.
class task_cleanup
{
@@ -433,20 +331,7 @@
// Reinsert the task at the end of the handler queue.
lock_.lock();
task_io_service_.task_interrupted_ = true;
- task_io_service_.task_handler_.next_ = 0;
- if (task_io_service_.handler_queue_end_)
- {
- task_io_service_.handler_queue_end_->next_
- = &task_io_service_.task_handler_;
- task_io_service_.handler_queue_end_
- = &task_io_service_.task_handler_;
- }
- else
- {
- task_io_service_.handler_queue_
- = task_io_service_.handler_queue_end_
- = &task_io_service_.task_handler_;
- }
+ task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
}
private:
@@ -487,11 +372,11 @@
// Handler object to represent the position of the task in the queue.
class task_handler
- : public handler_base
+ : public handler_queue::handler
{
public:
task_handler()
- : handler_base(0, 0)
+ : handler_queue::handler(0, 0)
{
}
} task_handler_;
@@ -502,11 +387,8 @@
// The count of unfinished work.
int outstanding_work_;
- // The start of a linked list of handlers that are ready to be delivered.
- handler_base* handler_queue_;
-
- // The end of a linked list of handlers that are ready to be delivered.
- handler_base* handler_queue_end_;
+ // The queue of handlers that are ready to be delivered.
+ handler_queue handler_queue_;
// Flag to indicate that the dispatcher has been stopped.
bool stopped_;
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