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:
parent
9d57f38680
commit
26f61cdc72
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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>(
|
||||
|
@ -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(),
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user