Added initial locking_dispatcher implementation.

This commit is contained in:
chris 2004-03-22 07:56:59 +00:00
parent 271db66458
commit 24e0725efa
12 changed files with 658 additions and 28 deletions

View File

@ -2,6 +2,7 @@ nobase_include_HEADERS = \
asio.hpp \
asio/basic_demuxer.hpp \
asio/basic_dgram_socket.hpp \
asio/basic_locking_dispatcher.hpp \
asio/basic_socket_acceptor.hpp \
asio/basic_socket_connector.hpp \
asio/basic_stream_socket.hpp \
@ -13,6 +14,7 @@ nobase_include_HEADERS = \
asio/detail/bind_handler.hpp \
asio/detail/buffer_resize_guard.hpp \
asio/detail/event.hpp \
asio/detail/locking_dispatcher_service.hpp \
asio/detail/mutex.hpp \
asio/detail/pipe_select_interrupter.hpp \
asio/detail/pop_options.hpp \
@ -57,6 +59,7 @@ nobase_include_HEADERS = \
asio/ipv4/address.hpp \
asio/ipv4/tcp.hpp \
asio/ipv4/udp.hpp \
asio/locking_dispatcher.hpp \
asio/recv.hpp \
asio/send.hpp \
asio/service_factory.hpp \
@ -66,7 +69,8 @@ nobase_include_HEADERS = \
asio/socket_option.hpp \
asio/stream_socket.hpp \
asio/timer.hpp \
asio/timer_base.hpp
asio/timer_base.hpp \
asio/wrapped_handler.hpp
MAINTAINERCLEANFILES = \
Makefile.in

View File

@ -17,6 +17,7 @@
#include "asio/basic_demuxer.hpp"
#include "asio/basic_dgram_socket.hpp"
#include "asio/basic_locking_dispatcher.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_connector.hpp"
#include "asio/basic_stream_socket.hpp"
@ -31,6 +32,7 @@
#include "asio/ipv4/address.hpp"
#include "asio/ipv4/tcp.hpp"
#include "asio/ipv4/udp.hpp"
#include "asio/locking_dispatcher.hpp"
#include "asio/recv.hpp"
#include "asio/send.hpp"
#include "asio/service_factory.hpp"

View File

@ -22,6 +22,8 @@
#include "asio/detail/pop_options.hpp"
#include "asio/service_factory.hpp"
#include "asio/wrapped_handler.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/service_registry.hpp"
#include "asio/detail/signal_init.hpp"
#include "asio/detail/winsock_init.hpp"
@ -162,31 +164,6 @@ public:
service_.post(handler);
}
template <typename Handler>
class wrapped_handler
{
public:
wrapped_handler(basic_demuxer<Demuxer_Service>& demuxer, Handler handler)
: demuxer_(demuxer),
handler_(handler)
{
}
void operator()()
{
demuxer_.dispatch(handler_);
}
void operator()() const
{
demuxer_.dispatch(handler_);
}
private:
basic_demuxer<Demuxer_Service>& demuxer_;
Handler handler_;
};
/// Create a new handler that automatically dispatches the wrapped handler
/// on the demuxer.
/**
@ -199,9 +176,11 @@ public:
* the handler must be: @code void handler(); @endcode
*/
template <typename Handler>
wrapped_handler<Handler> wrap(Handler handler)
wrapped_handler<basic_demuxer<Demuxer_Service>, Handler> wrap(
Handler handler)
{
return wrapped_handler<Handler>(*this, handler);
return wrapped_handler<basic_demuxer<Demuxer_Service>, Handler>(*this,
handler);
}
/// Obtain the service interface corresponding to the given type.

View File

@ -0,0 +1,139 @@
//
// basic_locking_dispatcher.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003, 2004 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#ifndef ASIO_BASIC_LOCKING_DISPATCHER_HPP
#define ASIO_BASIC_LOCKING_DISPATCHER_HPP
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/wrapped_handler.hpp"
namespace asio {
/// The basic_locking_dispatcher class template provides the ability to post
/// and dispatch handlers with the guarantee that none of those handlers will
/// execute concurrently. Most applications will use the locking_dispatcher
/// typedef.
template <typename Service>
class basic_locking_dispatcher
{
public:
/// The type of the service that will be used to provide locking dispatcher
/// operations.
typedef Service service_type;
/// The native implementation type of the locking dispatcher.
typedef typename service_type::impl_type impl_type;
/// The demuxer type for this dispatcher.
typedef typename service_type::demuxer_type demuxer_type;
/// Constructor.
/**
* Constructs the locking dispatcher.
*
* @param d The demuxer object that the locking dispatcher will use to
* dispatch handlers that are ready to be run.
*/
explicit basic_locking_dispatcher(demuxer_type& d)
: service_(d.get_service(service_factory<Service>())),
impl_(service_.null())
{
service_.create(impl_);
}
/// Destructor.
~basic_locking_dispatcher()
{
service_.destroy(impl_);
}
/// Request the dispatcher to invoke the given handler.
/**
* This function is used to ask the dispatcher to execute the given handler.
*
* The dispatcher guarantees that the handler will only be called in a thread
* in which the underlying demuxer's run member function is currently being
* invoked. It also guarantees that only one handler executed through this
* dispatcher will be invoked at a time. The handler may be executed inside
* this function if the guarantee can be met.
*
* @param handler The handler to be called. The dispatcher will make
* a copy of the handler object as required. The equivalent function
* signature of the handler must be: @code void handler(); @endcode
*/
template <typename Handler>
void dispatch(Handler handler)
{
service_.dispatch(impl_, handler);
}
/// Request the dispatcher to invoke the given handler and return
/// immediately.
/**
* This function is used to ask the dispatcher to execute the given handler,
* but without allowing the dispatcher to call the handler from inside this
* function.
*
* The dispatcher guarantees that the handler will only be called in a thread
* in which the underlying demuxer's run member function is currently being
* invoked. It also guarantees that only one handler executed through this
* dispatcher will be invoked at a time.
*
* @param handler The handler to be called. The dispatcher will make
* a copy of the handler object as required. The equivalent function
* signature of the handler must be: @code void handler(); @endcode
*/
template <typename Handler>
void post(Handler handler)
{
service_.post(impl_, handler);
}
/// Create a new handler that automatically dispatches the wrapped handler
/// on the dispatcher.
/**
* This function is used to create a new handler function object that, when
* invoked, will automatically pass the wrapped handler to the dispatcher's
* dispatch function.
*
* @param handler The handler to be wrapped. The dispatcher will make a copy
* of the handler object as required. The equivalent function signature of
* the handler must be: @code void handler(); @endcode
*/
template <typename Handler>
wrapped_handler<basic_locking_dispatcher<Service>, Handler> wrap(
Handler handler)
{
return wrapped_handler<basic_locking_dispatcher<Service>, Handler>(*this,
handler);
}
private:
/// The backend service implementation.
service_type& service_;
/// The underlying native implementation.
impl_type impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_LOCKING_DISPATCHER_HPP

View File

@ -128,6 +128,91 @@ binder3<Handler, Arg1, Arg2, Arg3> bind_handler(Handler handler, Arg1 arg1,
return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
class binder4
{
public:
binder4(Handler handler, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_);
}
private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler(Handler handler,
Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
{
return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3,
arg4);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
class binder5
{
public:
binder5(Handler handler, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4,
Arg5 arg5)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4),
arg5_(arg5)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}
private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
Arg5 arg5_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(Handler handler,
Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
{
return binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2,
arg3, arg4, arg5);
}
} // namespace detail
} // namespace asio

View File

@ -0,0 +1,252 @@
//
// locking_dispatcher_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003, 2004 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#ifndef ASIO_DETAIL_LOCKING_DISPATCHER_SERVICE_HPP
#define ASIO_DETAIL_LOCKING_DISPATCHER_SERVICE_HPP
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/mutex.hpp"
namespace asio {
namespace detail {
template <typename Demuxer>
class locking_dispatcher_service
{
public:
class dispatcher_impl
: private boost::noncopyable
{
public:
// Constructor.
dispatcher_impl()
: first_waiter_(),
last_waiter_(),
mutex_()
{
}
// Request a dispatcher to invoke the given handler.
template <typename Handler>
void dispatch(Demuxer& demuxer, Handler handler)
{
detail::mutex::scoped_lock lock(mutex_);
if (first_waiter_ == 0)
{
// This handler now has the lock, so can be dispatched immediately.
first_waiter_ = last_waiter_ = new waiter<Handler>(handler);
lock.unlock();
demuxer.dispatch(waiter_handler(demuxer, *this));
}
else
{
// Another waiter already holds the lock, so this handler must join
// the list of waiters. The handler will be posted automatically when
// its turn comes.
last_waiter_->next_ = new waiter<Handler>(handler);
last_waiter_ = last_waiter_->next_;
}
}
// Request a dispatcher to invoke the given handler and return immediately.
template <typename Handler>
void post(Demuxer& demuxer, Handler handler)
{
detail::mutex::scoped_lock lock(mutex_);
if (first_waiter_ == 0)
{
// This handler now has the lock, so can be posted immediately.
first_waiter_ = last_waiter_ = new waiter<Handler>(handler);
lock.unlock();
demuxer.post(waiter_handler(demuxer, *this));
}
else
{
// Another waiter already holds the lock, so this handler must join
// the list of waiters. The handler will be posted automatically when
// its turn comes.
last_waiter_->next_ = new waiter<Handler>(handler);
last_waiter_ = last_waiter_->next_;
}
}
private:
// Base class for all waiter types.
class waiter_base
{
public:
waiter_base()
: next_(0)
{
}
virtual ~waiter_base()
{
}
virtual void call() = 0;
waiter_base* next_;
};
// Class template for a waiter.
template <typename Handler>
class waiter
: public waiter_base
{
public:
waiter(Handler handler)
: handler_(handler)
{
}
virtual void call()
{
handler_();
}
private:
Handler handler_;
};
// Helper class to allow waiting handlers to be dispatched.
class waiter_handler
{
public:
waiter_handler(Demuxer& demuxer, dispatcher_impl& impl)
: demuxer_(demuxer),
impl_(impl)
{
}
void operator()()
{
do_upcall();
detail::mutex::scoped_lock lock(impl_.mutex_);
waiter_base* tmp = impl_.first_waiter_;
impl_.first_waiter_ = impl_.first_waiter_->next_;
delete tmp;
if (impl_.first_waiter_)
{
lock.unlock();
demuxer_.post(*this);
}
else
{
impl_.last_waiter_ = 0;
}
}
void do_upcall()
{
try
{
impl_.first_waiter_->call();
}
catch (...)
{
}
}
private:
Demuxer& demuxer_;
dispatcher_impl& impl_;
};
friend class waiter_handler;
// The start of the list of waiters for the dispatcher. If this pointer
// is non-null then it indicates that a handler holds the lock.
waiter_base* first_waiter_;
// The end of the list of waiters for the dispatcher.
waiter_base* last_waiter_;
// Mutex to protect access to internal data.
detail::mutex mutex_;
};
// The native type of the locking dispatcher.
typedef dispatcher_impl* impl_type;
// Return a null locking dispatcher implementation.
static impl_type null()
{
return 0;
}
// Constructor.
locking_dispatcher_service(Demuxer& d)
: demuxer_(d)
{
}
// The demuxer type for this service.
typedef Demuxer demuxer_type;
// Get the demuxer associated with the service.
demuxer_type& demuxer()
{
return demuxer_;
}
// Create a new locking dispatcher implementation.
void create(impl_type& impl)
{
impl = new dispatcher_impl;
}
// Destroy a locking dispatcher implementation.
void destroy(impl_type& impl)
{
if (impl != null())
{
delete impl;
impl = null();
}
}
// Request a dispatcher to invoke the given handler.
template <typename Handler>
void dispatch(impl_type& impl, Handler handler)
{
impl->dispatch(demuxer_, handler);
}
// Request a dispatcher to invoke the given handler and return immediately.
template <typename Handler>
void post(impl_type& impl, Handler handler)
{
impl->post(demuxer_, handler);
}
private:
// The demuxer used for dispatching handlers.
Demuxer& demuxer_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_LOCKING_DISPATCHER_SERVICE_HPP

View File

@ -0,0 +1,43 @@
//
// locking_dispatcher.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003, 2004 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#ifndef ASIO_LOCKING_DISPATCHER_HPP
#define ASIO_LOCKING_DISPATCHER_HPP
#include "asio/detail/push_options.hpp"
#include "asio/basic_locking_dispatcher.hpp"
#include "asio/demuxer.hpp"
#include "asio/detail/locking_dispatcher_service.hpp"
namespace asio {
/// Typedef for the typical usage of locking_dispatcher.
#if defined(GENERATING_DOCUMENTATION)
typedef basic_locking_dispatcher
<
implementation_defined
> locking_dispatcher;
#else
typedef basic_locking_dispatcher
<
detail::locking_dispatcher_service<demuxer>
> locking_dispatcher;
#endif
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_LOCKING_DISPATCHER_HPP

View File

@ -0,0 +1,119 @@
//
// wrapped_handler.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003, 2004 Christopher M. Kohlhoff (chris@kohlhoff.com)
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both the copyright
// notice and this permission notice appear in supporting documentation. This
// software is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
#ifndef ASIO_WRAPPED_HANDLER_HPP
#define ASIO_WRAPPED_HANDLER_HPP
#include "asio/detail/push_options.hpp"
#include "asio/detail/bind_handler.hpp"
namespace asio {
template <typename Dispatcher, typename Handler>
class wrapped_handler
{
public:
wrapped_handler(Dispatcher& dispatcher, Handler handler)
: dispatcher_(dispatcher),
handler_(handler)
{
}
void operator()()
{
dispatcher_.dispatch(handler_);
}
void operator()() const
{
dispatcher_.dispatch(handler_);
}
template <typename Arg1>
void operator()(Arg1 arg1)
{
dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
}
template <typename Arg1>
void operator()(Arg1 arg1) const
{
dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
}
template <typename Arg1, typename Arg2>
void operator()(Arg1 arg1, Arg2 arg2)
{
dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
}
template <typename Arg1, typename Arg2>
void operator()(Arg1 arg1, Arg2 arg2) const
{
dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
}
template <typename Arg1, typename Arg2, typename Arg3>
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3)
{
dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
}
template <typename Arg1, typename Arg2, typename Arg3>
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) const
{
dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
}
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
{
dispatcher_.dispatch(
detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
}
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) const
{
dispatcher_.dispatch(
detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
}
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5>
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
{
dispatcher_.dispatch(
detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
}
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5>
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) const
{
dispatcher_.dispatch(
detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
}
private:
Dispatcher& dispatcher_;
Handler handler_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_WRAPPED_HANDLER_HPP

View File

@ -9,6 +9,7 @@ noinst_PROGRAMS = \
tests/unit/dgram_socket_test \
tests/unit/error_handler_test \
tests/unit/fixed_buffer_test \
tests/unit/locking_dispatcher_test \
tests/unit/socket_acceptor_test \
tests/unit/timer_test \
examples/chat/chat_client \
@ -47,6 +48,7 @@ tests_unit_demuxer_test_SOURCES = tests/unit/demuxer_test.cpp
tests_unit_dgram_socket_test_SOURCES = tests/unit/dgram_socket_test.cpp
tests_unit_error_handler_test_SOURCES = tests/unit/error_handler_test.cpp
tests_unit_fixed_buffer_test_SOURCES = tests/unit/fixed_buffer_test.cpp
tests_unit_locking_dispatcher_test_SOURCES = tests/unit/locking_dispatcher_test.cpp
tests_unit_socket_acceptor_test_SOURCES = tests/unit/socket_acceptor_test.cpp
tests_unit_timer_test_SOURCES = tests/unit/timer_test.cpp
examples_chat_chat_client_SOURCES = examples/chat/chat_client.cpp

View File

@ -13,6 +13,7 @@ all: \
tests\unit\dgram_socket_test.exe \
tests\unit\error_handler_test.exe \
tests\unit\fixed_buffer_test.exe \
tests\unit\locking_dispatcher_test.exe \
tests\unit\socket_acceptor_test.exe \
tests\unit\timer_test.exe \
examples\chat\chat_client.exe \
@ -36,6 +37,7 @@ check: all
@tests\unit\dgram_socket_test.exe
@tests\unit\error_handler_test.exe
@tests\unit\fixed_buffer_test.exe
@tests\unit\locking_dispatcher_test.exe
@tests\unit\socket_acceptor_test.exe
@tests\unit\timer_test.exe

View File

@ -13,6 +13,7 @@ TEST_EXES = \
tests/unit/dgram_socket_test.exe \
tests/unit/error_handler_test.exe \
tests/unit/fixed_buffer_test.exe \
tests/unit/locking_dispatcher_test.exe \
tests/unit/socket_acceptor_test.exe \
tests/unit/timer_test.exe

View File

@ -13,6 +13,7 @@ all: \
tests\unit\dgram_socket_test.exe \
tests\unit\error_handler_test.exe \
tests\unit\fixed_buffer_test.exe \
tests\unit\locking_dispatcher_test.exe \
tests\unit\socket_acceptor_test.exe \
tests\unit\timer_test.exe \
examples\chat\chat_client.exe \
@ -37,6 +38,7 @@ tests\unit\demuxer_test.exe: tests\unit\demuxer_test.obj
tests\unit\dgram_socket_test.exe: tests\unit\dgram_socket_test.obj
tests\unit\error_handler_test.exe: tests\unit\error_handler_test.obj
tests\unit\fixed_buffer_test.exe: tests\unit\fixed_buffer_test.obj
tests\unit\locking_dispatcher_test.exe: tests\unit\locking_dispatcher_test.obj
tests\unit\socket_acceptor_test.exe: tests\unit\socket_acceptor_test.obj
tests\unit\timer_test.exe: tests\unit\timer_test.obj
examples\chat\chat_client.exe: examples\chat\chat_client.obj