From 26f61cdc7260c593791b32c75ae524d37878e942 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 30 Dec 2003 00:45:27 +0000 Subject: [PATCH] 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). --- asio/include/asio/basic_demuxer.hpp | 34 +-- asio/include/asio/basic_dgram_socket.hpp | 18 +- asio/include/asio/basic_socket_acceptor.hpp | 18 +- asio/include/asio/basic_socket_connector.hpp | 9 +- asio/include/asio/basic_stream_socket.hpp | 18 +- asio/include/asio/basic_timer.hpp | 9 +- asio/include/asio/buffered_recv_stream.hpp | 6 +- asio/include/asio/buffered_send_stream.hpp | 4 +- asio/include/asio/buffered_stream.hpp | 6 +- .../asio/counting_completion_context.hpp | 288 ++++++++++++------ .../detail/reactive_dgram_socket_service.hpp | 13 +- .../reactive_socket_acceptor_service.hpp | 14 +- .../reactive_socket_connector_service.hpp | 6 +- .../detail/reactive_stream_socket_service.hpp | 12 +- .../asio/detail/reactive_timer_service.hpp | 7 +- .../asio/detail/task_demuxer_service.hpp | 8 +- asio/include/asio/null_completion_context.hpp | 35 +-- asio/include/asio/recv.hpp | 40 ++- asio/include/asio/send.hpp | 20 +- asio/src/tests/dispatcher_test.cpp | 2 +- 20 files changed, 301 insertions(+), 266 deletions(-) diff --git a/asio/include/asio/basic_demuxer.hpp b/asio/include/asio/basic_demuxer.hpp index a3727957..97d38d99 100644 --- a/asio/include/asio/basic_demuxer.hpp +++ b/asio/include/asio/basic_demuxer.hpp @@ -127,8 +127,7 @@ public: template 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 - 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 - 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 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 - 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 - 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); diff --git a/asio/include/asio/basic_dgram_socket.hpp b/asio/include/asio/basic_dgram_socket.hpp index 6db44516..00bf2716 100644 --- a/asio/include/asio/basic_dgram_socket.hpp +++ b/asio/include/asio/basic_dgram_socket.hpp @@ -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 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 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); diff --git a/asio/include/asio/basic_socket_acceptor.hpp b/asio/include/asio/basic_socket_acceptor.hpp index f9353d82..78994a18 100644 --- a/asio/include/asio/basic_socket_acceptor.hpp +++ b/asio/include/asio/basic_socket_acceptor.hpp @@ -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 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 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); diff --git a/asio/include/asio/basic_socket_connector.hpp b/asio/include/asio/basic_socket_connector.hpp index d3c0d596..0e4f3e67 100644 --- a/asio/include/asio/basic_socket_connector.hpp +++ b/asio/include/asio/basic_socket_connector.hpp @@ -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 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); diff --git a/asio/include/asio/basic_stream_socket.hpp b/asio/include/asio/basic_stream_socket.hpp index 3443e52d..ca76f25e 100644 --- a/asio/include/asio/basic_stream_socket.hpp +++ b/asio/include/asio/basic_stream_socket.hpp @@ -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 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 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); } diff --git a/asio/include/asio/basic_timer.hpp b/asio/include/asio/basic_timer.hpp index 2c7154af..309eeec9 100644 --- a/asio/include/asio/basic_timer.hpp +++ b/asio/include/asio/basic_timer.hpp @@ -169,7 +169,7 @@ public: template 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 - void async_wait(Handler handler, Completion_Context& context) + void async_wait(Handler handler, Completion_Context context) { service_.async_wait(impl_, handler, context); } diff --git a/asio/include/asio/buffered_recv_stream.hpp b/asio/include/asio/buffered_recv_stream.hpp index d039263e..ed55f267 100644 --- a/asio/include/asio/buffered_recv_stream.hpp +++ b/asio/include/asio/buffered_recv_stream.hpp @@ -114,7 +114,7 @@ public: /// lifetime of the asynchronous operation. template 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 - 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 void async_recv(void* data, size_t max_length, Handler handler, - Completion_Context& context) + Completion_Context context) { if (buffer_.empty()) { diff --git a/asio/include/asio/buffered_send_stream.hpp b/asio/include/asio/buffered_send_stream.hpp index 25ff6aa6..3f051695 100644 --- a/asio/include/asio/buffered_send_stream.hpp +++ b/asio/include/asio/buffered_send_stream.hpp @@ -100,7 +100,7 @@ public: /// lifetime of the asynchronous operation. template 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 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); } diff --git a/asio/include/asio/buffered_stream.hpp b/asio/include/asio/buffered_stream.hpp index c19a57c8..795499ec 100644 --- a/asio/include/asio/buffered_stream.hpp +++ b/asio/include/asio/buffered_stream.hpp @@ -110,7 +110,7 @@ public: /// lifetime of the asynchronous operation. template 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 - 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 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); } diff --git a/asio/include/asio/counting_completion_context.hpp b/asio/include/asio/counting_completion_context.hpp index 4b4e52b3..f959d7e1 100644 --- a/asio/include/asio/counting_completion_context.hpp +++ b/asio/include/asio/counting_completion_context.hpp @@ -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 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); - 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 - 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 + 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); + 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 + 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 diff --git a/asio/include/asio/detail/reactive_dgram_socket_service.hpp b/asio/include/asio/detail/reactive_dgram_socket_service.hpp index c761d12f..bce98995 100644 --- a/asio/include/asio/detail/reactive_dgram_socket_service.hpp +++ b/asio/include/asio/detail/reactive_dgram_socket_service.hpp @@ -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 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 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, diff --git a/asio/include/asio/detail/reactive_socket_acceptor_service.hpp b/asio/include/asio/detail/reactive_socket_acceptor_service.hpp index a04b7eed..db415751 100644 --- a/asio/include/asio/detail/reactive_socket_acceptor_service.hpp +++ b/asio/include/asio/detail/reactive_socket_acceptor_service.hpp @@ -182,7 +182,7 @@ public: public: accept_handler(impl_type impl, Demuxer& demuxer, basic_stream_socket& 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& 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 void async_accept(impl_type& impl, - basic_stream_socket& peer, - Handler handler, Completion_Context& context) + basic_stream_socket& 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& 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& 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& peer, - Address& peer_address, Handler handler, Completion_Context& context) + Address& peer_address, Handler handler, Completion_Context context) { if (peer.impl() != invalid_socket) { diff --git a/asio/include/asio/detail/reactive_socket_connector_service.hpp b/asio/include/asio/detail/reactive_socket_connector_service.hpp index e34c9812..be92dbde 100644 --- a/asio/include/asio/detail/reactive_socket_connector_service.hpp +++ b/asio/include/asio/detail/reactive_socket_connector_service.hpp @@ -167,7 +167,7 @@ public: connect_handler(impl_type impl, socket_type new_socket, Demuxer& demuxer, basic_stream_socket& 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& 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& peer, const Address& peer_address, Handler handler, - Completion_Context& context) + Completion_Context context) { if (peer.impl() != invalid_socket) { diff --git a/asio/include/asio/detail/reactive_stream_socket_service.hpp b/asio/include/asio/detail/reactive_stream_socket_service.hpp index 29dce4b0..51aece8a 100644 --- a/asio/include/asio/detail/reactive_stream_socket_service.hpp +++ b/asio/include/asio/detail/reactive_stream_socket_service.hpp @@ -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 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( @@ -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 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( diff --git a/asio/include/asio/detail/reactive_timer_service.hpp b/asio/include/asio/detail/reactive_timer_service.hpp index 20db66e1..7a67f678 100644 --- a/asio/include/asio/detail/reactive_timer_service.hpp +++ b/asio/include/asio/detail/reactive_timer_service.hpp @@ -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 - 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(), diff --git a/asio/include/asio/detail/task_demuxer_service.hpp b/asio/include/asio/detail/task_demuxer_service.hpp index 53d8eb36..93a17df3 100644 --- a/asio/include/asio/detail/task_demuxer_service.hpp +++ b/asio/include/asio/detail/task_demuxer_service.hpp @@ -157,7 +157,7 @@ public: // Notify the demuxer that an operation has completed. template - 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 - 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. diff --git a/asio/include/asio/null_completion_context.hpp b/asio/include/asio/null_completion_context.hpp index 6cef12ee..b9704a1c 100644 --- a/asio/include/asio/null_completion_context.hpp +++ b/asio/include/asio/null_completion_context.hpp @@ -17,48 +17,15 @@ #include "asio/detail/push_options.hpp" -#include "asio/detail/push_options.hpp" -#include -#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 - struct global - { - static Type instance; - }; - - template Type global::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::instance; - } - /// Attempt to acquire the right to make an upcall. /** * This function is called to attempt to obtain the right to make an upcall diff --git a/asio/include/asio/recv.hpp b/asio/include/asio/recv.hpp index bd167716..e98636dd 100644 --- a/asio/include/asio/recv.hpp +++ b/asio/include/asio/recv.hpp @@ -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 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(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 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(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(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 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 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); diff --git a/asio/include/asio/send.hpp b/asio/include/asio/send.hpp index 485576b9..26977ec4 100644 --- a/asio/include/asio/send.hpp +++ b/asio/include/asio/send.hpp @@ -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 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(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 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(s, data, diff --git a/asio/src/tests/dispatcher_test.cpp b/asio/src/tests/dispatcher_test.cpp index a3bac355..ff70dbb4 100644 --- a/asio/src/tests/dispatcher_test.cpp +++ b/asio/src/tests/dispatcher_test.cpp @@ -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";