blob: 2775078e26a177b8c16972b879cc892fca9c616f [file] [log] [blame]
//
// indirect_handler_queue.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 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_INDIRECT_HANDLER_QUEUE_HPP
#define BOOST_ASIO_DETAIL_INDIRECT_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>
#if defined(_MSC_VER) && (_MSC_VER >= 1310)
extern "C" void _ReadWriteBarrier();
# pragma intrinsic(_ReadWriteBarrier)
#endif // defined(_MSC_VER) && (_MSC_VER >= 1310)
namespace boost {
namespace asio {
namespace detail {
class indirect_handler_queue
: private noncopyable
{
public:
class handler;
// Element for a node in the queue.
class node
{
public:
node()
: version_(0),
handler_(0),
next_(0)
{
}
private:
friend class indirect_handler_queue;
unsigned long version_;
handler* handler_;
node* next_;
};
// 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)
: node_(new node),
invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
}
~handler()
{
if (node_)
delete node_;
}
private:
friend class indirect_handler_queue;
node* node_;
invoke_func_type invoke_func_;
destroy_func_type destroy_func_;
};
// Smart point to manager handler lifetimes.
class scoped_ptr
: private 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.
indirect_handler_queue()
: front_(new node),
back_(front_),
next_version_(1)
{
}
// Destructor.
~indirect_handler_queue()
{
while (front_)
{
node* tmp = front_;
front_ = front_->next_;
delete tmp;
}
}
// 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();
}
// Determine whether the queue has something ready to pop.
bool poppable()
{
return front_->next_ != 0;
}
// The version number at the front of the queue.
unsigned long front_version()
{
return front_->version_;
}
// The version number at the back of the queue.
unsigned long back_version()
{
return back_->version_;
}
// Pop a handler from the front of the queue.
handler* pop()
{
node* n = front_;
node* new_front = n->next_;
if (new_front)
{
handler* h = new_front->handler_;
h->node_ = n;
new_front->handler_ = 0;
front_ = new_front;
return h;
}
return 0;
}
// Push a handler on to the back of the queue.
void push(handler* h)
{
node* n = h->node_;
h->node_ = 0;
n->version_ = next_version_;
next_version_ += 2;
n->handler_ = h;
n->next_ = 0;
memory_barrier();
back_->next_ = n;
back_ = n;
}
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.
boost_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);
// A sub-object of the handler may be the true owner of the memory
// associated with the handler. Consequently, a local copy of the handler
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Handler handler(h->handler_);
(void)handler;
// Free the memory associated with the handler.
ptr.reset();
}
private:
Handler handler_;
};
// Helper function to create a memory barrier.
static void memory_barrier()
{
#if defined(_GLIBCXX_WRITE_MEM_BARRIER)
_GLIBCXX_WRITE_MEM_BARRIER;
#elif defined(_MSC_VER) && (_MSC_VER >= 1310)
_ReadWriteBarrier();
#else
# error memory barrier required
#endif
}
// The front of the queue.
node* front_;
// The back of the queue.
node* back_;
// The next version counter to be assigned to a node.
unsigned long next_version_;
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP