Change contexts so that they can be passed by value, with all copies being

equivalent to the original (i.e. they represent the same completion
context).
This commit is contained in:
chris 2003-12-30 00:45:27 +00:00
parent 9d57f38680
commit 26f61cdc72
20 changed files with 301 additions and 266 deletions

View File

@ -127,8 +127,7 @@ public:
template <typename Handler>
void operation_completed(Handler handler)
{
service_.operation_completed(handler, null_completion_context::instance(),
false);
service_.operation_completed(handler, null_completion_context(), false);
}
/// Notify the demuxer that an operation has completed.
@ -146,12 +145,11 @@ public:
* signature of the handler must be: @code void handler(); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* completion_context object is retained by the caller, which must guarantee
* that it is valid until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Handler, typename Completion_Context>
void operation_completed(Handler handler, Completion_Context& context)
void operation_completed(Handler handler, Completion_Context context)
{
service_.operation_completed(handler, context, false);
}
@ -171,9 +169,8 @@ public:
* signature of the handler must be: @code void handler(); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* completion_context object is retained by the caller, which must guarantee
* that it is valid until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*
* @param allow_nested_delivery If true, this allows the demuxer to run the
* completion handler before operation_completed returns, as an optimisation.
@ -183,7 +180,7 @@ public:
* immediately.
*/
template <typename Handler, typename Completion_Context>
void operation_completed(Handler handler, Completion_Context& context,
void operation_completed(Handler handler, Completion_Context context,
bool allow_nested_delivery)
{
service_.operation_completed(handler, context, allow_nested_delivery);
@ -206,8 +203,7 @@ public:
template <typename Handler>
void operation_immediate(Handler handler)
{
service_.operation_immediate(handler, null_completion_context::instance(),
false);
service_.operation_immediate(handler, null_completion_context(), false);
}
/// Notify the demuxer of an operation that started and finished immediately.
@ -225,12 +221,11 @@ public:
* signature of the handler must be: @code void handler(); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* completion_context object is retained by the caller, which must guarantee
* that it is valid until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Handler, typename Completion_Context>
void operation_immediate(Handler handler, Completion_Context& context)
void operation_immediate(Handler handler, Completion_Context context)
{
service_.operation_immediate(handler, context, false);
}
@ -250,9 +245,8 @@ public:
* signature of the handler must be: @code void handler(); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*
* @param allow_nested_delivery If true, this allows the demuxer to run the
* completion handler before operation_immediate returns, as an optimisation.
@ -262,7 +256,7 @@ public:
* immediately.
*/
template <typename Handler, typename Completion_Context>
void operation_immediate(Handler handler, Completion_Context& context,
void operation_immediate(Handler handler, Completion_Context context,
bool allow_nested_delivery)
{
service_.operation_immediate(handler, context, allow_nested_delivery);

View File

@ -331,7 +331,7 @@ public:
const Address& destination, Handler handler)
{
service_.async_sendto(impl_, data, length, destination, handler,
null_completion_context::instance());
null_completion_context());
}
/// Start an asynchronous send.
@ -362,14 +362,13 @@ public:
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Address, typename Handler, typename Completion_Context>
void async_sendto(const void* data, size_t length,
const Address& destination, Handler handler,
Completion_Context& context)
Completion_Context context)
{
service_.async_sendto(impl_, data, length, destination, handler, context);
}
@ -460,7 +459,7 @@ public:
Handler handler)
{
service_.async_recvfrom(impl_, data, max_length, sender_address, handler,
null_completion_context::instance());
null_completion_context());
}
/// Start an asynchronous receive.
@ -489,13 +488,12 @@ public:
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Address, typename Handler, typename Completion_Context>
void async_recvfrom(void* data, size_t max_length, Address& sender_address,
Handler handler, Completion_Context& context)
Handler handler, Completion_Context context)
{
service_.async_recvfrom(impl_, data, max_length, sender_address, handler,
context);

View File

@ -328,7 +328,7 @@ public:
void async_accept(Stream& peer_socket, Handler handler)
{
service_.async_accept(impl_, peer_socket.lowest_layer(), handler,
null_completion_context::instance());
null_completion_context());
}
/// Start an asynchronous accept.
@ -348,13 +348,12 @@ public:
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Stream, typename Handler, typename Completion_Context>
void async_accept(Stream& peer_socket, Handler handler,
Completion_Context& context)
Completion_Context context)
{
service_.async_accept(impl_, peer_socket.lowest_layer(), handler, context);
}
@ -436,7 +435,7 @@ public:
Handler handler)
{
service_.async_accept_address(impl_, peer_socket.lowest_layer(),
peer_address, handler, null_completion_context::instance());
peer_address, handler, null_completion_context());
}
/// Start an asynchronous accept.
@ -462,14 +461,13 @@ public:
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Stream, typename Address, typename Handler,
typename Completion_Context>
void async_accept_address(Stream& peer_socket, Address& peer_address,
Handler handler, Completion_Context& context)
Handler handler, Completion_Context context)
{
service_.async_accept_address(impl_, peer_socket.lowest_layer(),
peer_address, handler, context);

View File

@ -186,7 +186,7 @@ public:
Handler handler)
{
service_.async_connect(impl_, peer_socket.lowest_layer(), peer_address,
handler, null_completion_context::instance());
handler, null_completion_context());
}
/// Start an asynchronous connect.
@ -209,14 +209,13 @@ public:
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Stream, typename Address, typename Handler,
typename Completion_Context>
void async_connect(Stream& peer_socket, const Address& peer_address,
Handler handler, Completion_Context& context)
Handler handler, Completion_Context context)
{
service_.async_connect(impl_, peer_socket.lowest_layer(), peer_address,
handler, context);

View File

@ -276,7 +276,7 @@ public:
void async_send(const void* data, size_t length, Handler handler)
{
service_.async_send(impl_, data, length, handler,
null_completion_context::instance());
null_completion_context());
}
/// Start an asynchronous send.
@ -299,9 +299,8 @@ public:
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the asio::async_send_n() function if you need to ensure
@ -309,7 +308,7 @@ public:
*/
template <typename Handler, typename Completion_Context>
void async_send(const void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
service_.async_send(impl_, data, length, handler, context);
}
@ -398,7 +397,7 @@ public:
void async_recv(void* data, size_t max_length, Handler handler)
{
service_.async_recv(impl_, data, max_length, handler,
null_completion_context::instance());
null_completion_context());
}
/// Start an asynchronous receive.
@ -421,9 +420,8 @@ public:
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*
* @note The recv operation may not receive all of the requested number of
* bytes. Consider using the asio::async_recv_n() function if you need to
@ -432,7 +430,7 @@ public:
*/
template <typename Handler, typename Completion_Context>
void async_recv(void* data, size_t max_length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
service_.async_recv(impl_, data, max_length, handler, context);
}

View File

@ -169,7 +169,7 @@ public:
template <typename Handler>
void async_wait(Handler handler)
{
service_.async_wait(impl_, handler, null_completion_context::instance());
service_.async_wait(impl_, handler, null_completion_context());
}
/// Start an asynchronous wait on the timer.
@ -183,12 +183,11 @@ public:
* signature of the handler must be: @code void handler(); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made
* of the context object as required, however all copies are equivalent.
*/
template <typename Handler, typename Completion_Context>
void async_wait(Handler handler, Completion_Context& context)
void async_wait(Handler handler, Completion_Context context)
{
service_.async_wait(impl_, handler, context);
}

View File

@ -114,7 +114,7 @@ public:
/// lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_send(const void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
next_layer_.async_send(data, length, handler, context);
}
@ -186,7 +186,7 @@ public:
/// Start an asynchronous fill.
template <typename Handler, typename Completion_Context>
void async_fill(Handler handler, Completion_Context& context)
void async_fill(Handler handler, Completion_Context context)
{
size_t previous_size = buffer_.size();
buffer_.resize(buffer_.capacity());
@ -275,7 +275,7 @@ public:
/// must be valid for the lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_recv(void* data, size_t max_length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
if (buffer_.empty())
{

View File

@ -100,7 +100,7 @@ public:
/// lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_send(const void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
next_layer_.async_send(data, length, handler, context);
}
@ -132,7 +132,7 @@ public:
/// must be valid for the lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_recv(void* data, size_t max_length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
next_layer_.async_recv(data, max_length, handler, context);
}

View File

@ -110,7 +110,7 @@ public:
/// lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_send(const void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
stream_impl_.async_send(data, length, handler, context);
}
@ -141,7 +141,7 @@ public:
/// Start an asynchronous fill.
template <typename Handler, typename Completion_Context>
void async_fill(Handler handler, Completion_Context& context)
void async_fill(Handler handler, Completion_Context context)
{
stream_impl_.async_fill(handler, context);
}
@ -173,7 +173,7 @@ public:
/// must be valid for the lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_recv(void* data, size_t max_length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
stream_impl_.async_recv(data, max_length, handler, context);
}

View File

@ -24,150 +24,240 @@ namespace asio {
/// The counting_completion_context class is a concrete implementation of the
/// Completion_Context concept. It allows a limitation on the number of
/// concurrent upcalls to completion handlers that may be associated with the
/// context.
/// context. Copies of an instance of this class represent the same context as
/// the original.
class counting_completion_context
{
public:
/// Constructor.
explicit counting_completion_context(int max_concurrent_upcalls)
: mutex_(),
max_concurrent_upcalls_(max_concurrent_upcalls),
concurrent_upcalls_(0),
first_waiter_(0),
last_waiter_(0)
/// Default constructor.
counting_completion_context()
: impl_(new impl(1))
{
}
/// Construct with a specified limit on the number of upcalls.
explicit counting_completion_context(int max_concurrent_upcalls)
: impl_(new impl(max_concurrent_upcalls))
{
}
/// Copy constructor.
counting_completion_context(const counting_completion_context& other)
: impl_(other.impl_)
{
impl_->add_ref();
}
/// Destructor.
~counting_completion_context()
{
while (first_waiter_)
{
waiter_base* delete_waiter = first_waiter_;
first_waiter_ = first_waiter_->next_;
delete delete_waiter;
}
impl_->remove_ref();
}
/// Assignment operator.
counting_completion_context& operator=(
const counting_completion_context& other)
{
counting_completion_context tmp(other);
impl* tmp_impl = tmp.impl_;
tmp.impl_ = impl_;
impl_ = tmp_impl;
return *this;
}
/// Attempt to acquire the right to make an upcall.
bool try_acquire()
{
detail::mutex::scoped_lock lock(mutex_);
if (concurrent_upcalls_ < max_concurrent_upcalls_)
{
++concurrent_upcalls_;
return true;
}
return false;
return impl_->try_acquire();
}
/// Acquire the right to make an upcall.
template <typename Handler>
void acquire(Handler handler)
{
detail::mutex::scoped_lock lock(mutex_);
if (concurrent_upcalls_ < max_concurrent_upcalls_)
{
// The context can been acquired for the locker.
++concurrent_upcalls_;
lock.unlock();
handler();
}
else
{
// Can't acquire the context for the locker right now, so put it on the
// list of waiters.
waiter_base* new_waiter = new waiter<Handler>(handler);
if (first_waiter_ == 0)
{
first_waiter_ = new_waiter;
last_waiter_ = new_waiter;
}
else
{
last_waiter_->next_ = new_waiter;
last_waiter_ = new_waiter;
}
}
impl_->acquire(handler);
}
/// Relinquish a previously granted right to make an upcall.
void release()
{
detail::mutex::scoped_lock lock(mutex_);
// Check if we can start one of the waiting tasks now.
if (concurrent_upcalls_ <= max_concurrent_upcalls_ && first_waiter_)
{
waiter_base* next_waiter = first_waiter_;
first_waiter_ = first_waiter_->next_;
if (first_waiter_ == 0)
last_waiter_ = 0;
lock.unlock();
next_waiter->notify();
delete next_waiter;
}
else
{
--concurrent_upcalls_;
}
impl_->release();
}
private:
// Mutex to protect access to internal data.
detail::mutex mutex_;
// The maximum number of concurrent upcalls.
int max_concurrent_upcalls_;
// The current number of upcalls.
int concurrent_upcalls_;
// Base class for all waiter types.
class waiter_base
// Inner implementation class to allow all copies made of a
// counting_completion_context to remain equivalent.
class impl
{
public:
waiter_base()
: next_(0)
// Constructor.
explicit impl(int max_concurrent_upcalls)
: mutex_(),
ref_count_(1),
max_concurrent_upcalls_(max_concurrent_upcalls),
concurrent_upcalls_(0),
first_waiter_(0),
last_waiter_(0)
{
}
virtual ~waiter_base()
// Destructor.
~impl()
{
while (first_waiter_)
{
waiter_base* delete_waiter = first_waiter_;
first_waiter_ = first_waiter_->next_;
delete delete_waiter;
}
}
virtual void notify() = 0;
waiter_base* next_;
};
// Class template for a waiter.
template <typename Handler>
class waiter
: public waiter_base
{
public:
waiter(Handler handler)
: handler_(handler)
// Attempt to acquire the right to make an upcall.
bool try_acquire()
{
detail::mutex::scoped_lock lock(mutex_);
if (concurrent_upcalls_ < max_concurrent_upcalls_)
{
++concurrent_upcalls_;
return true;
}
return false;
}
virtual void notify()
// Acquire the right to make an upcall.
template <typename Handler>
void acquire(Handler handler)
{
handler_();
detail::mutex::scoped_lock lock(mutex_);
if (concurrent_upcalls_ < max_concurrent_upcalls_)
{
// The context can been acquired for the locker.
++concurrent_upcalls_;
lock.unlock();
handler();
}
else
{
// Can't acquire the context for the locker right now, so put it on the
// list of waiters.
waiter_base* new_waiter = new waiter<Handler>(handler);
if (first_waiter_ == 0)
{
first_waiter_ = new_waiter;
last_waiter_ = new_waiter;
}
else
{
last_waiter_->next_ = new_waiter;
last_waiter_ = new_waiter;
}
}
}
// Relinquish a previously granted right to make an upcall.
void release()
{
detail::mutex::scoped_lock lock(mutex_);
// Check if we can start one of the waiting tasks now.
if (concurrent_upcalls_ <= max_concurrent_upcalls_ && first_waiter_)
{
waiter_base* next_waiter = first_waiter_;
first_waiter_ = first_waiter_->next_;
if (first_waiter_ == 0)
last_waiter_ = 0;
lock.unlock();
next_waiter->notify();
delete next_waiter;
}
else
{
--concurrent_upcalls_;
}
}
// Increment the reference count.
void add_ref()
{
detail::mutex::scoped_lock lock(mutex_);
++ref_count_;
}
// Decrement the reference count and delete the object if necessary.
void remove_ref()
{
detail::mutex::scoped_lock lock(mutex_);
if (--ref_count_ == 0)
{
lock.unlock();
delete this;
}
}
private:
Handler handler_;
// Mutex to protect access to internal data.
detail::mutex mutex_;
// The reference count on the implementation.
int ref_count_;
// The maximum number of concurrent upcalls.
int max_concurrent_upcalls_;
// The current number of upcalls.
int concurrent_upcalls_;
// Base class for all waiter types.
class waiter_base
{
public:
waiter_base()
: next_(0)
{
}
virtual ~waiter_base()
{
}
virtual void notify() = 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 notify()
{
handler_();
}
private:
Handler handler_;
};
// The start of the list of waiters for the context.
waiter_base* first_waiter_;
// The end of the list of waiters for the context.
waiter_base* last_waiter_;
};
// The start of the list of waiters for the context.
waiter_base* first_waiter_;
// The end of the list of waiters for the context.
waiter_base* last_waiter_;
// The inner implementation.
impl* impl_;
};
} // namespace asio

View File

@ -136,7 +136,7 @@ public:
public:
sendto_handler(impl_type impl, Demuxer& demuxer, const void* data,
size_t length, const Address& address, Handler handler,
Completion_Context& context)
Completion_Context context)
: impl_(impl),
demuxer_(demuxer),
data_(data),
@ -170,15 +170,14 @@ public:
size_t length_;
Address destination_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename Address, typename Handler, typename Completion_Context>
void async_sendto(impl_type& impl, const void* data, size_t length,
const Address& destination, Handler handler,
Completion_Context& context)
const Address& destination, Handler handler, Completion_Context context)
{
demuxer_.operation_started();
reactor_.start_write_op(impl,
@ -212,7 +211,7 @@ public:
public:
recvfrom_handler(impl_type impl, Demuxer& demuxer, void* data,
size_t max_length, Address& address, Handler handler,
Completion_Context& context)
Completion_Context context)
: impl_(impl),
demuxer_(demuxer),
data_(data),
@ -248,7 +247,7 @@ public:
size_t max_length_;
Address& sender_address_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous receive. The buffer for the data being received and
@ -256,7 +255,7 @@ public:
// asynchronous operation.
template <typename Address, typename Handler, typename Completion_Context>
void async_recvfrom(impl_type& impl, void* data, size_t max_length,
Address& sender_address, Handler handler, Completion_Context& context)
Address& sender_address, Handler handler, Completion_Context context)
{
demuxer_.operation_started();
reactor_.start_read_op(impl,

View File

@ -182,7 +182,7 @@ public:
public:
accept_handler(impl_type impl, Demuxer& demuxer,
basic_stream_socket<Stream_Socket_Service>& peer, Handler handler,
Completion_Context& context)
Completion_Context context)
: impl_(impl),
demuxer_(demuxer),
peer_(peer),
@ -211,7 +211,7 @@ public:
Demuxer& demuxer_;
basic_stream_socket<Stream_Socket_Service>& peer_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous accept. The peer_socket object must be valid until
@ -219,8 +219,8 @@ public:
template <typename Stream_Socket_Service, typename Handler,
typename Completion_Context>
void async_accept(impl_type& impl,
basic_stream_socket<Stream_Socket_Service>& peer,
Handler handler, Completion_Context& context)
basic_stream_socket<Stream_Socket_Service>& peer, Handler handler,
Completion_Context context)
{
if (peer.impl() != invalid_socket)
{
@ -243,7 +243,7 @@ public:
public:
accept_addr_handler(impl_type impl, Demuxer& demuxer,
basic_stream_socket<Stream_Socket_Service>& peer,
Address& peer_address, Handler handler, Completion_Context& context)
Address& peer_address, Handler handler, Completion_Context context)
: impl_(impl),
demuxer_(demuxer),
peer_(peer),
@ -277,7 +277,7 @@ public:
basic_stream_socket<Stream_Socket_Service>& peer_;
Address& peer_address_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous accept. The peer_socket and peer_address objects
@ -286,7 +286,7 @@ public:
typename Completion_Context>
void async_accept_address(impl_type& impl,
basic_stream_socket<Stream_Socket_Service>& peer,
Address& peer_address, Handler handler, Completion_Context& context)
Address& peer_address, Handler handler, Completion_Context context)
{
if (peer.impl() != invalid_socket)
{

View File

@ -167,7 +167,7 @@ public:
connect_handler(impl_type impl, socket_type new_socket, Demuxer& demuxer,
basic_stream_socket<Stream_Socket_Service>& peer,
const Address& peer_address, Handler handler,
Completion_Context& context)
Completion_Context context)
: impl_(impl),
new_socket_(new_socket),
demuxer_(demuxer),
@ -234,7 +234,7 @@ public:
basic_stream_socket<Stream_Socket_Service>& peer_;
Address peer_address_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous connect. The peer socket object must be valid until
@ -244,7 +244,7 @@ public:
void async_connect(impl_type& impl,
basic_stream_socket<Stream_Socket_Service>& peer,
const Address& peer_address, Handler handler,
Completion_Context& context)
Completion_Context context)
{
if (peer.impl() != invalid_socket)
{

View File

@ -112,7 +112,7 @@ public:
{
public:
send_handler(impl_type impl, Demuxer& demuxer, const void* data,
size_t length, Handler handler, Completion_Context& context)
size_t length, Handler handler, Completion_Context context)
: impl_(impl),
demuxer_(demuxer),
data_(data),
@ -144,14 +144,14 @@ public:
const void* data_;
size_t length_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_send(impl_type& impl, const void* data, size_t length,
Handler handler, Completion_Context& context)
Handler handler, Completion_Context context)
{
demuxer_.operation_started();
reactor_.start_write_op(impl, send_handler<Handler, Completion_Context>(
@ -178,7 +178,7 @@ public:
{
public:
recv_handler(impl_type impl, Demuxer& demuxer, void* data,
size_t max_length, Handler handler, Completion_Context& context)
size_t max_length, Handler handler, Completion_Context context)
: impl_(impl),
demuxer_(demuxer),
data_(data),
@ -209,14 +209,14 @@ public:
void* data_;
size_t max_length_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename Handler, typename Completion_Context>
void async_recv(impl_type& impl, void* data, size_t max_length,
Handler handler, Completion_Context& context)
Handler handler, Completion_Context context)
{
demuxer_.operation_started();
reactor_.start_read_op(impl, recv_handler<Handler, Completion_Context>(

View File

@ -134,7 +134,7 @@ public:
{
public:
wait_handler(impl_type& impl, Demuxer& demuxer, Handler handler,
Completion_Context& context)
Completion_Context context)
: impl_(impl),
demuxer_(demuxer),
handler_(handler),
@ -158,13 +158,12 @@ public:
impl_type& impl_;
Demuxer& demuxer_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// Start an asynchronous wait on the timer.
template <typename Handler, typename Completion_Context>
void async_wait(impl_type& impl, Handler handler,
Completion_Context& context)
void async_wait(impl_type& impl, Handler handler, Completion_Context context)
{
demuxer_.operation_started();
reactor_.schedule_timer(impl->expiry.sec(), impl->expiry.usec(),

View File

@ -157,7 +157,7 @@ public:
// Notify the demuxer that an operation has completed.
template <typename Handler, typename Completion_Context>
void operation_completed(Handler handler, Completion_Context& context,
void operation_completed(Handler handler, Completion_Context context,
bool allow_nested_delivery)
{
asio::detail::mutex::scoped_lock lock(mutex_);
@ -202,7 +202,7 @@ public:
// Notify the demuxer of an operation that started and finished immediately.
template <typename Handler, typename Completion_Context>
void operation_immediate(Handler handler, Completion_Context& context,
void operation_immediate(Handler handler, Completion_Context context,
bool allow_nested_delivery)
{
operation_started();
@ -310,7 +310,7 @@ private:
: public completion_base
{
public:
completion(Handler handler, Completion_Context& context)
completion(Handler handler, Completion_Context context)
: handler_(handler),
context_(context)
{
@ -335,7 +335,7 @@ private:
private:
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
// The demuxer that owns this service.

View File

@ -17,48 +17,15 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/noncopyable.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail
{
// Helper template used to create a global instance of the
// null_completion_context without needing a .cpp file for it.
template <typename Type>
struct global
{
static Type instance;
};
template <typename Type> Type global<Type>::instance;
}
/// The null_completion_context class is a concrete implementation of the
/// Completion_Context concept. It does not place any limits on the number of
/// concurrent upcalls to completion handlers that may be associated with the
/// context.
/// context. All instances of this class are equivalent.
class null_completion_context
: private boost::noncopyable
{
public:
/// Obtain the null completion context.
/**
* This function can be used to obtain a null completion context
* implementation. This null implementation provides no control over when
* completion handler upcalls are made.
*
* @return A reference to a null completion context object. The ownership of
* the object is not transferred to the caller, and the object is guaranteed
* to be valid for the lifetime of the program.
*/
static null_completion_context& instance()
{
return detail::global<null_completion_context>::instance;
}
/// Attempt to acquire the right to make an upcall.
/**
* This function is called to attempt to obtain the right to make an upcall

View File

@ -147,9 +147,8 @@ void async_recv(Stream& s, void* data, size_t max_length, Handler handler)
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made of
* the context object as required, however all copies are equivalent.
*
* @note The recv operation may not receive all of the requested number of
* bytes. Consider using the asio::async_recv_n() function if you need to
@ -158,7 +157,7 @@ void async_recv(Stream& s, void* data, size_t max_length, Handler handler)
*/
template <typename Stream, typename Handler, typename Completion_Context>
void async_recv(Stream& s, void* data, size_t max_length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
s.async_recv(data, max_length, handler, context);
}
@ -264,7 +263,7 @@ namespace detail
{
public:
recv_n_handler(Stream& stream, void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
: stream_(stream),
data_(data),
length_(length),
@ -296,7 +295,7 @@ namespace detail
size_t length_;
size_t total_recvd_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
} // namespace detail
@ -332,7 +331,7 @@ void async_recv_n(Stream& s, void* data, size_t length, Handler handler)
{
async_recv(s, data, length,
detail::recv_n_handler<Stream, Handler, null_completion_context>(s, data,
length, handler, null_completion_context::instance()));
length, handler, null_completion_context()));
}
/// Start an asynchronous receive that will not complete until the specified
@ -363,13 +362,12 @@ void async_recv_n(Stream& s, void* data, size_t length, Handler handler)
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made of
* the context object as required, however all copies are equivalent.
*/
template <typename Stream, typename Handler, typename Completion_Context>
void async_recv_n(Stream& s, void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
async_recv(s, data, length,
detail::recv_n_handler<Stream, Handler, Completion_Context>(s, data,
@ -516,7 +514,7 @@ namespace detail
{
public:
recv_decode_handler(Buffered_Stream& stream, Decoder decoder,
Handler handler, Completion_Context& context)
Handler handler, Completion_Context context)
: stream_(stream),
decoder_(decoder),
total_recvd_(0),
@ -562,7 +560,7 @@ namespace detail
Decoder decoder_;
size_t total_recvd_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
} // namespace detail
@ -626,7 +624,7 @@ void async_recv_decode(Buffered_Stream& s, Decoder decoder, Handler handler)
s.async_fill(detail::recv_decode_handler<Buffered_Stream, Decoder, Handler,
null_completion_context>(s, decoder, handler,
null_completion_context::instance()));
null_completion_context()));
}
/// Start an asynchronous receive that will not complete until some data has
@ -669,14 +667,13 @@ void async_recv_decode(Buffered_Stream& s, Decoder decoder, Handler handler)
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made of
* the context object as required, however all copies are equivalent.
*/
template <typename Buffered_Stream, typename Decoder, typename Handler,
typename Completion_Context>
void async_recv_decode(Buffered_Stream& s, Decoder decoder, Handler handler,
Completion_Context& context)
Completion_Context context)
{
while (!s.recv_buffer().empty())
{
@ -874,14 +871,13 @@ void async_recv_until(Buffered_Stream& s, std::string& data,
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made of
* the context object as required, however all copies are equivalent.
*/
template <typename Buffered_Stream, typename Handler,
typename Completion_Context>
void async_recv_until(Buffered_Stream& s, std::string& data,
const std::string& delimiter, Handler handler, Completion_Context& context)
const std::string& delimiter, Handler handler, Completion_Context context)
{
async_recv_decode(s, detail::recv_until_decoder(data, delimiter), handler,
context);

View File

@ -139,9 +139,8 @@ void async_send(Stream& s, const void* data, size_t length, Handler handler)
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made of
* the context object as required, however all copies are equivalent.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the asio::async_send_n() function if you need to ensure that
@ -149,7 +148,7 @@ void async_send(Stream& s, const void* data, size_t length, Handler handler)
*/
template <typename Stream, typename Handler, typename Completion_Context>
void async_send(Stream& s, const void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
s.async_send(data, length, handler, context);
}
@ -255,7 +254,7 @@ namespace detail
{
public:
send_n_handler(Stream& stream, const void* data, size_t length,
Handler handler, Completion_Context& context)
Handler handler, Completion_Context context)
: stream_(stream),
data_(data),
length_(length),
@ -287,7 +286,7 @@ namespace detail
size_t length_;
size_t total_sent_;
Handler handler_;
Completion_Context& context_;
Completion_Context context_;
};
} // namespace detail
@ -322,7 +321,7 @@ void async_send_n(Stream& s, const void* data, size_t length, Handler handler)
{
async_send(s, data, length,
detail::send_n_handler<Stream, Handler, null_completion_context>(s,
data, length, handler, null_completion_context::instance()));
data, length, handler, null_completion_context()));
}
/// Start an asynchronous send that will not complete until the specified
@ -352,13 +351,12 @@ void async_send_n(Stream& s, const void* data, size_t length, Handler handler)
* ); @endcode
*
* @param context The completion context which controls the number of
* concurrent invocations of handlers that may be made. Ownership of the
* object is retained by the caller, which must guarantee that it is valid
* until after the handler has been called.
* concurrent invocations of handlers that may be made. Copies will be made of
* the context object as required, however all copies are equivalent.
*/
template <typename Stream, typename Handler, typename Completion_Context>
void async_send_n(Stream& s, const void* data, size_t length, Handler handler,
Completion_Context& context)
Completion_Context context)
{
async_send(s, data, length,
detail::send_n_handler<Stream, Handler, Completion_Context>(s, data,

View File

@ -33,7 +33,7 @@ void outer_print(demuxer& d, int id, detail::mutex& io_mutex)
lock.unlock();
d.operation_immediate(boost::bind(inner_print, id, boost::ref(io_mutex)),
null_completion_context::instance(), true);
null_completion_context(), true);
lock.lock();
std::cout << "Finished " << id << "\n";