230 lines
4.8 KiB
C++
230 lines
4.8 KiB
C++
|
//
|
||
|
// 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 ASIO_DETAIL_HANDLER_QUEUE_HPP
|
||
|
#define ASIO_DETAIL_HANDLER_QUEUE_HPP
|
||
|
|
||
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||
|
# pragma once
|
||
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||
|
|
||
|
#include "asio/detail/push_options.hpp"
|
||
|
|
||
|
#include "asio/detail/handler_alloc_helpers.hpp"
|
||
|
#include "asio/detail/handler_invoke_helpers.hpp"
|
||
|
#include "asio/detail/noncopyable.hpp"
|
||
|
|
||
|
namespace asio {
|
||
|
namespace detail {
|
||
|
|
||
|
class handler_queue
|
||
|
: private 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
|
||
|
: 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.
|
||
|
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);
|
||
|
|
||
|
// 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_;
|
||
|
};
|
||
|
|
||
|
// The front of the queue.
|
||
|
handler* front_;
|
||
|
|
||
|
// The back of the queue.
|
||
|
handler* back_;
|
||
|
};
|
||
|
|
||
|
} // namespace detail
|
||
|
} // namespace asio
|
||
|
|
||
|
#include "asio/detail/pop_options.hpp"
|
||
|
|
||
|
#endif // ASIO_DETAIL_HANDLER_QUEUE_HPP
|