diff --git a/doc/requirements/asynchronous_operations.qbk b/doc/requirements/asynchronous_operations.qbk index b067c4ff..1ce88363 100644 --- a/doc/requirements/asynchronous_operations.qbk +++ b/doc/requirements/asynchronous_operations.qbk @@ -254,8 +254,10 @@ type `Executor2` obtained by performing [heading Outstanding work] -Until the asynchronous operation has completed, the asynchronous operation -shall maintain: +If the operation does not complete immediately (that is, the operation does not +complete within the thread of execution calling the initiating function, before +the initiating function returns) then, until the asynchronous operation has +completed, the asynchronous operation shall maintain: [mdash] an object `work1` of type `executor_work_guard`, initialized as `work1(ex1)`, and where `work1.owns_work() == true`; and @@ -308,18 +310,23 @@ Let `f` be a function object, callable as `f()`, that invokes object, callable as `g()`, that contains a copy of `work2` and when invoked performs `dispatch(ex2, bind_allocator(alloc2, std::move(f)))`. -If an asynchonous operation completes immediately (that is, within the thread -of execution calling the initiating function, and before the initiating -function returns), the completion handler shall be submitted for execution as -if by performing `post(ex1, bind_allocator(alloc2, std::move(g)))`. As an -optimisation, the operation may submit the completion handler for execution by -performing expression `post(ex2, bind_allocator(alloc2, std::move(f)))`, if that -expression is well-formed. +If an asynchonous operation completes immediately (that is, the operation +completes within the thread of execution calling the initiating function, and +before the initiating function returns), the completion handler shall be +submitted for execution as if by performing `post(ex1, bind_allocator(alloc2, +std::move(g)))`. Otherwise, when the operation completes, the completion handler shall be submitted for execution as if by performing `dispatch(ex2, bind_allocator(alloc2, std::move(f)))`. +[heading Optimisation of immediate completion] + +If an asynchronous operation completes immediately then, as an optimisation, +the operation may submit the completion handler for execution by performing +expression `post(ex2, bind_allocator(alloc2, std::move(f)))`, if that +expression is well-formed. + [heading Completion handlers and exceptions] Completion handlers are permitted to throw exceptions. The effect of any diff --git a/include/boost/asio/detail/descriptor_read_op.hpp b/include/boost/asio/detail/descriptor_read_op.hpp index 1328e74a..dd3d15ca 100644 --- a/include/boost/asio/detail/descriptor_read_op.hpp +++ b/include/boost/asio/detail/descriptor_read_op.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -86,6 +87,9 @@ class descriptor_read_op : public descriptor_read_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); descriptor_read_op(const boost::system::error_code& success_ec, @@ -136,6 +140,37 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + descriptor_read_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/descriptor_write_op.hpp b/include/boost/asio/detail/descriptor_write_op.hpp index 23f130ca..6e9efdbb 100644 --- a/include/boost/asio/detail/descriptor_write_op.hpp +++ b/include/boost/asio/detail/descriptor_write_op.hpp @@ -86,6 +86,9 @@ class descriptor_write_op : public descriptor_write_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); descriptor_write_op(const boost::system::error_code& success_ec, @@ -136,6 +139,37 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + descriptor_write_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/dev_poll_reactor.hpp b/include/boost/asio/detail/dev_poll_reactor.hpp index 8ae09fe2..506b1ae6 100644 --- a/include/boost/asio/detail/dev_poll_reactor.hpp +++ b/include/boost/asio/detail/dev_poll_reactor.hpp @@ -87,13 +87,31 @@ public: per_descriptor_data& source_descriptor_data); // Post a reactor operation for immediate completion. - void post_immediate_completion(reactor_op* op, bool is_continuation); + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + BOOST_ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data&, reactor_op* op, - bool is_continuation, bool allow_speculative); + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &epoll_reactor::call_post_immediate_completion, this); + } + // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the diff --git a/include/boost/asio/detail/epoll_reactor.hpp b/include/boost/asio/detail/epoll_reactor.hpp index eac66fb0..7947641f 100644 --- a/include/boost/asio/detail/epoll_reactor.hpp +++ b/include/boost/asio/detail/epoll_reactor.hpp @@ -117,13 +117,30 @@ public: per_descriptor_data& source_descriptor_data); // Post a reactor operation for immediate completion. - void post_immediate_completion(operation* op, bool is_continuation); + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + BOOST_ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative); + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &epoll_reactor::call_post_immediate_completion, this); + } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the diff --git a/include/boost/asio/detail/handler_work.hpp b/include/boost/asio/detail/handler_work.hpp index c3c02d2c..3e03388c 100644 --- a/include/boost/asio/detail/handler_work.hpp +++ b/include/boost/asio/detail/handler_work.hpp @@ -16,9 +16,13 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include +#include #include +#include #include +#include #include #include #include @@ -526,6 +530,34 @@ public: } }; +template +class immediate_handler_work +{ +public: + typedef handler_work handler_work_type; + + explicit immediate_handler_work(BOOST_ASIO_MOVE_ARG(handler_work_type) w) + : handler_work_(BOOST_ASIO_MOVE_CAST(handler_work_type)(w)) + { + } + + template + void complete(Function& function, Handler& handler, const void* io_ex) + { + typedef typename associated_immediate_executor::type + immediate_ex_type; + + immediate_ex_type immediate_ex = (get_associated_immediate_executor)( + handler, *static_cast(io_ex)); + + (initiate_dispatch_with_executor(immediate_ex))( + BOOST_ASIO_MOVE_CAST(Function)(function)); + } + +private: + handler_work_type handler_work_; +}; + } // namespace detail } // namespace asio } // namespace boost diff --git a/include/boost/asio/detail/impl/dev_poll_reactor.hpp b/include/boost/asio/detail/impl/dev_poll_reactor.hpp index 82ff553d..4eea4f15 100644 --- a/include/boost/asio/detail/impl/dev_poll_reactor.hpp +++ b/include/boost/asio/detail/impl/dev_poll_reactor.hpp @@ -28,7 +28,7 @@ namespace asio { namespace detail { inline void dev_poll_reactor::post_immediate_completion( - reactor_op* op, bool is_continuation) + operation* op, bool is_continuation) const { scheduler_.post_immediate_completion(op, is_continuation); } diff --git a/include/boost/asio/detail/impl/dev_poll_reactor.ipp b/include/boost/asio/detail/impl/dev_poll_reactor.ipp index 7558558d..96b4f370 100644 --- a/include/boost/asio/detail/impl/dev_poll_reactor.ipp +++ b/include/boost/asio/detail/impl/dev_poll_reactor.ipp @@ -149,15 +149,24 @@ void dev_poll_reactor::move_descriptor(socket_type, { } +void dev_poll_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast(self)->post_immediate_completion( + op, is_continuation); +} + void dev_poll_reactor::start_op(int op_type, socket_type descriptor, dev_poll_reactor::per_descriptor_data&, reactor_op* op, - bool is_continuation, bool allow_speculative) + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -170,7 +179,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor, if (op->perform()) { lock.unlock(); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } diff --git a/include/boost/asio/detail/impl/epoll_reactor.hpp b/include/boost/asio/detail/impl/epoll_reactor.hpp index 261ff04e..0611bcb7 100644 --- a/include/boost/asio/detail/impl/epoll_reactor.hpp +++ b/include/boost/asio/detail/impl/epoll_reactor.hpp @@ -26,7 +26,7 @@ namespace asio { namespace detail { inline void epoll_reactor::post_immediate_completion( - operation* op, bool is_continuation) + operation* op, bool is_continuation) const { scheduler_.post_immediate_completion(op, is_continuation); } diff --git a/include/boost/asio/detail/impl/epoll_reactor.ipp b/include/boost/asio/detail/impl/epoll_reactor.ipp index a3ecf259..5bbb4342 100644 --- a/include/boost/asio/detail/impl/epoll_reactor.ipp +++ b/include/boost/asio/detail/impl/epoll_reactor.ipp @@ -230,14 +230,23 @@ void epoll_reactor::move_descriptor(socket_type, source_descriptor_data = 0; } +void epoll_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast(self)->post_immediate_completion( + op, is_continuation); +} + void epoll_reactor::start_op(int op_type, socket_type descriptor, epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative) + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { if (!descriptor_data) { op->ec_ = boost::asio::error::bad_descriptor; - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -245,7 +254,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -263,7 +272,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->registered_events_ != 0) descriptor_data->try_speculative_[op_type] = false; descriptor_lock.unlock(); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } @@ -271,7 +280,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->registered_events_ == 0) { op->ec_ = boost::asio::error::operation_not_supported; - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -290,7 +299,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, { op->ec_ = boost::system::error_code(errno, boost::asio::error::get_system_category()); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } @@ -299,7 +308,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, else if (descriptor_data->registered_events_ == 0) { op->ec_ = boost::asio::error::operation_not_supported; - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } else diff --git a/include/boost/asio/detail/impl/kqueue_reactor.hpp b/include/boost/asio/detail/impl/kqueue_reactor.hpp index 39bd087a..91561a87 100644 --- a/include/boost/asio/detail/impl/kqueue_reactor.hpp +++ b/include/boost/asio/detail/impl/kqueue_reactor.hpp @@ -29,7 +29,7 @@ namespace asio { namespace detail { inline void kqueue_reactor::post_immediate_completion( - operation* op, bool is_continuation) + operation* op, bool is_continuation) const { scheduler_.post_immediate_completion(op, is_continuation); } diff --git a/include/boost/asio/detail/impl/kqueue_reactor.ipp b/include/boost/asio/detail/impl/kqueue_reactor.ipp index 9cee0fd8..47a9d4ab 100644 --- a/include/boost/asio/detail/impl/kqueue_reactor.ipp +++ b/include/boost/asio/detail/impl/kqueue_reactor.ipp @@ -191,14 +191,23 @@ void kqueue_reactor::move_descriptor(socket_type, source_descriptor_data = 0; } +void kqueue_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast(self)->post_immediate_completion( + op, is_continuation); +} + void kqueue_reactor::start_op(int op_type, socket_type descriptor, kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative) + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { if (!descriptor_data) { op->ec_ = boost::asio::error::bad_descriptor; - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -206,7 +215,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, if (descriptor_data->shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -221,7 +230,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, if (op->perform()) { descriptor_lock.unlock(); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } @@ -240,7 +249,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, { op->ec_ = boost::system::error_code(errno, boost::asio::error::get_system_category()); - scheduler_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } } diff --git a/include/boost/asio/detail/impl/reactive_descriptor_service.ipp b/include/boost/asio/detail/impl/reactive_descriptor_service.ipp index f508cef4..d7be640f 100644 --- a/include/boost/asio/detail/impl/reactive_descriptor_service.ipp +++ b/include/boost/asio/detail/impl/reactive_descriptor_service.ipp @@ -198,10 +198,10 @@ boost::system::error_code reactive_descriptor_service::cancel( return ec; } -void reactive_descriptor_service::start_op( - reactive_descriptor_service::implementation_type& impl, - int op_type, reactor_op* op, bool is_continuation, - bool is_non_blocking, bool noop) +void reactive_descriptor_service::do_start_op(implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, bool is_non_blocking, + bool noop, void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if (!noop) { @@ -209,13 +209,13 @@ void reactive_descriptor_service::start_op( descriptor_ops::set_internal_non_blocking( impl.descriptor_, impl.state_, true, op->ec_)) { - reactor_.start_op(op_type, impl.descriptor_, - impl.reactor_data_, op, is_continuation, is_non_blocking); + reactor_.start_op(op_type, impl.descriptor_, impl.reactor_data_, op, + is_continuation, is_non_blocking, on_immediate, immediate_arg); return; } } - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } } // namespace detail diff --git a/include/boost/asio/detail/impl/reactive_socket_service_base.ipp b/include/boost/asio/detail/impl/reactive_socket_service_base.ipp index 85c23946..7e40711b 100644 --- a/include/boost/asio/detail/impl/reactive_socket_service_base.ipp +++ b/include/boost/asio/detail/impl/reactive_socket_service_base.ipp @@ -234,10 +234,11 @@ boost::system::error_code reactive_socket_service_base::do_assign( return ec; } -void reactive_socket_service_base::start_op( - reactive_socket_service_base::base_implementation_type& impl, - int op_type, reactor_op* op, bool is_continuation, - bool is_non_blocking, bool noop) +void reactive_socket_service_base::do_start_op( + reactive_socket_service_base::base_implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if (!noop) { @@ -245,31 +246,38 @@ void reactive_socket_service_base::start_op( || socket_ops::set_internal_non_blocking( impl.socket_, impl.state_, true, op->ec_)) { - reactor_.start_op(op_type, impl.socket_, - impl.reactor_data_, op, is_continuation, is_non_blocking); + reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op, + is_continuation, is_non_blocking, on_immediate, immediate_arg); return; } } - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } -void reactive_socket_service_base::start_accept_op( +void reactive_socket_service_base::do_start_accept_op( reactive_socket_service_base::base_implementation_type& impl, - reactor_op* op, bool is_continuation, bool peer_is_open) + reactor_op* op, bool is_continuation, bool peer_is_open, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if (!peer_is_open) - start_op(impl, reactor::read_op, op, is_continuation, true, false); + { + do_start_op(impl, reactor::read_op, op, is_continuation, + true, false, on_immediate, immediate_arg); + } else { op->ec_ = boost::asio::error::already_open; - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } } -void reactive_socket_service_base::start_connect_op( +void reactive_socket_service_base::do_start_connect_op( reactive_socket_service_base::base_implementation_type& impl, - reactor_op* op, bool is_continuation, const void* addr, size_t addrlen) + reactor_op* op, bool is_continuation, const void* addr, size_t addrlen, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg) { if ((impl.state_ & socket_ops::non_blocking) || socket_ops::set_internal_non_blocking( @@ -281,14 +289,14 @@ void reactive_socket_service_base::start_connect_op( || op->ec_ == boost::asio::error::would_block) { op->ec_ = boost::system::error_code(); - reactor_.start_op(reactor::connect_op, impl.socket_, - impl.reactor_data_, op, is_continuation, false); + reactor_.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_, + op, is_continuation, false, on_immediate, immediate_arg); return; } } } - reactor_.post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); } } // namespace detail diff --git a/include/boost/asio/detail/impl/select_reactor.hpp b/include/boost/asio/detail/impl/select_reactor.hpp index 55fef695..b7d862a0 100644 --- a/include/boost/asio/detail/impl/select_reactor.hpp +++ b/include/boost/asio/detail/impl/select_reactor.hpp @@ -36,7 +36,7 @@ namespace asio { namespace detail { inline void select_reactor::post_immediate_completion( - reactor_op* op, bool is_continuation) + operation* op, bool is_continuation) const { scheduler_.post_immediate_completion(op, is_continuation); } diff --git a/include/boost/asio/detail/impl/select_reactor.ipp b/include/boost/asio/detail/impl/select_reactor.ipp index 188716df..33887e24 100644 --- a/include/boost/asio/detail/impl/select_reactor.ipp +++ b/include/boost/asio/detail/impl/select_reactor.ipp @@ -152,15 +152,23 @@ void select_reactor::move_descriptor(socket_type, { } +void select_reactor::call_post_immediate_completion( + operation* op, bool is_continuation, const void* self) +{ + static_cast(self)->post_immediate_completion( + op, is_continuation); +} + void select_reactor::start_op(int op_type, socket_type descriptor, - select_reactor::per_descriptor_data&, reactor_op* op, - bool is_continuation, bool) + select_reactor::per_descriptor_data&, reactor_op* op, bool is_continuation, + bool, void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { - post_immediate_completion(op, is_continuation); + on_immediate(op, is_continuation, immediate_arg); return; } diff --git a/include/boost/asio/detail/kqueue_reactor.hpp b/include/boost/asio/detail/kqueue_reactor.hpp index 776f69ce..66591433 100644 --- a/include/boost/asio/detail/kqueue_reactor.hpp +++ b/include/boost/asio/detail/kqueue_reactor.hpp @@ -117,13 +117,30 @@ public: per_descriptor_data& source_descriptor_data); // Post a reactor operation for immediate completion. - void post_immediate_completion(operation* op, bool is_continuation); + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + BOOST_ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, reactor_op* op, - bool is_continuation, bool allow_speculative); + bool is_continuation, bool allow_speculative, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &kqueue_reactor::call_post_immediate_completion, this); + } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index 628fe7ae..3a0e8b6e 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -23,6 +23,7 @@ && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) #include +#include #include #include #include @@ -228,19 +229,20 @@ public: switch (w) { case posix::descriptor_base::wait_read: - op_type = reactor::read_op; - break; + op_type = reactor::read_op; + break; case posix::descriptor_base::wait_write: - op_type = reactor::write_op; - break; + op_type = reactor::write_op; + break; case posix::descriptor_base::wait_error: - op_type = reactor::except_op; - break; - default: - p.p->ec_ = boost::asio::error::invalid_argument; - reactor_.post_immediate_completion(p.p, is_continuation); - p.v = p.p = 0; - return; + op_type = reactor::except_op; + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + start_op(impl, reactor::read_op, p.p, + is_continuation, false, true, &io_ex, 0); + p.v = p.p = 0; + return; } // Optionally register for per-operation cancellation. @@ -251,7 +253,7 @@ public: &reactor_, &impl.reactor_data_, impl.descriptor_, op_type); } - start_op(impl, op_type, p.p, is_continuation, false, false); + start_op(impl, op_type, p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -325,7 +327,7 @@ public: start_op(impl, reactor::write_op, p.p, is_continuation, true, buffer_sequence_adapter::all_empty(buffers)); + ConstBufferSequence>::all_empty(buffers), &io_ex, 0); p.v = p.p = 0; } @@ -358,7 +360,8 @@ public: BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_write_some(null_buffers)")); - start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -433,7 +436,7 @@ public: start_op(impl, reactor::read_op, p.p, is_continuation, true, buffer_sequence_adapter::all_empty(buffers)); + MutableBufferSequence>::all_empty(buffers), &io_ex, 0); p.v = p.p = 0; } @@ -466,14 +469,47 @@ public: BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_read_some(null_buffers)")); - start_op(impl, reactor::read_op, p.p, is_continuation, false, false); + start_op(impl, reactor::read_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } private: // Start the asynchronous operation. - BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + BOOST_ASIO_DECL void do_start_op(implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous operation for handlers that are specialised for + // immediate completion. + template + void start_op(implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, + const void* io_ex, ...) + { + return do_start_op(impl, op_type, op, is_continuation, + is_non_blocking, noop, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template + void start_op(implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, const void*, + typename enable_if< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >::type*) + { + return do_start_op(impl, op_type, op, is_continuation, is_non_blocking, + noop, &reactor::call_post_immediate_completion, &reactor_); + } // Helper class used to implement per-operation cancellation class reactor_op_cancellation diff --git a/include/boost/asio/detail/reactive_null_buffers_op.hpp b/include/boost/asio/detail/reactive_null_buffers_op.hpp index 7e700b78..0773d74a 100644 --- a/include/boost/asio/detail/reactive_null_buffers_op.hpp +++ b/include/boost/asio/detail/reactive_null_buffers_op.hpp @@ -34,6 +34,9 @@ template class reactive_null_buffers_op : public reactor_op { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); reactive_null_buffers_op(const boost::system::error_code& success_ec, @@ -86,6 +89,35 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_null_buffers_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/reactive_socket_accept_op.hpp b/include/boost/asio/detail/reactive_socket_accept_op.hpp index a1905f66..d42322eb 100644 --- a/include/boost/asio/detail/reactive_socket_accept_op.hpp +++ b/include/boost/asio/detail/reactive_socket_accept_op.hpp @@ -96,6 +96,9 @@ class reactive_socket_accept_op : public reactive_socket_accept_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); reactive_socket_accept_op(const boost::system::error_code& success_ec, @@ -152,6 +155,40 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_accept_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + o->do_assign(); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; @@ -168,6 +205,9 @@ class reactive_socket_move_accept_op : Protocol> { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); reactive_socket_move_accept_op(const boost::system::error_code& success_ec, @@ -229,6 +269,43 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_move_accept_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + // On success, assign new connection to peer socket object. + o->do_assign(); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2 + handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, + BOOST_ASIO_MOVE_CAST(peer_socket_type)(*o)); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: typedef typename Protocol::socket::template rebind_executor::other peer_socket_type; diff --git a/include/boost/asio/detail/reactive_socket_connect_op.hpp b/include/boost/asio/detail/reactive_socket_connect_op.hpp index 2746440e..7349aafe 100644 --- a/include/boost/asio/detail/reactive_socket_connect_op.hpp +++ b/include/boost/asio/detail/reactive_socket_connect_op.hpp @@ -63,6 +63,9 @@ template class reactive_socket_connect_op : public reactive_socket_connect_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); reactive_socket_connect_op(const boost::system::error_code& success_ec, @@ -113,6 +116,38 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_connect_op* o + (static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/reactive_socket_recv_op.hpp b/include/boost/asio/detail/reactive_socket_recv_op.hpp index 7b28472f..20074831 100644 --- a/include/boost/asio/detail/reactive_socket_recv_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recv_op.hpp @@ -98,6 +98,9 @@ class reactive_socket_recv_op : public reactive_socket_recv_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); reactive_socket_recv_op(const boost::system::error_code& success_ec, @@ -149,6 +152,37 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_recv_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp index 4bec488f..998440ea 100644 --- a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -100,6 +100,9 @@ class reactive_socket_recvfrom_op : public reactive_socket_recvfrom_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); reactive_socket_recvfrom_op(const boost::system::error_code& success_ec, @@ -154,6 +157,38 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp b/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp index 23b4476a..89232b8b 100644 --- a/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp @@ -81,6 +81,9 @@ class reactive_socket_recvmsg_op : public reactive_socket_recvmsg_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); reactive_socket_recvmsg_op(const boost::system::error_code& success_ec, @@ -135,6 +138,38 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_recvmsg_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/reactive_socket_send_op.hpp b/include/boost/asio/detail/reactive_socket_send_op.hpp index 51f6ba7e..df46b5a1 100644 --- a/include/boost/asio/detail/reactive_socket_send_op.hpp +++ b/include/boost/asio/detail/reactive_socket_send_op.hpp @@ -101,6 +101,9 @@ class reactive_socket_send_op : public reactive_socket_send_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); reactive_socket_send_op(const boost::system::error_code& success_ec, @@ -152,6 +155,38 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_send_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/reactive_socket_sendto_op.hpp b/include/boost/asio/detail/reactive_socket_sendto_op.hpp index 30e60378..ab0143ca 100644 --- a/include/boost/asio/detail/reactive_socket_sendto_op.hpp +++ b/include/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -94,6 +94,9 @@ class reactive_socket_sendto_op : public reactive_socket_sendto_op_base { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); reactive_socket_sendto_op(const boost::system::error_code& success_ec, @@ -146,6 +149,37 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_socket_sendto_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + BOOST_ASIO_ERROR_LOCATION(o->ec_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 5f468c50..06da20ed 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -307,7 +307,8 @@ public: BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to")); - start_op(impl, reactor::write_op, p.p, is_continuation, true, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, true, false, &io_ex, 0); p.v = p.p = 0; } @@ -340,7 +341,8 @@ public: BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to(null_buffers)")); - start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -431,7 +433,7 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, true, false); + p.p, is_continuation, true, false, &io_ex, 0); p.v = p.p = 0; } @@ -470,7 +472,7 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, false, false); + p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -536,7 +538,7 @@ public: BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); - start_accept_op(impl, p.p, is_continuation, peer.is_open()); + start_accept_op(impl, p.p, is_continuation, peer.is_open(), &io_ex, 0); p.v = p.p = 0; } @@ -573,7 +575,7 @@ public: BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); - start_accept_op(impl, p.p, is_continuation, false); + start_accept_op(impl, p.p, is_continuation, false, &io_ex, 0); p.v = p.p = 0; } #endif // defined(BOOST_ASIO_HAS_MOVE) @@ -618,7 +620,7 @@ public: &impl, impl.socket_, "async_connect")); start_connect_op(impl, p.p, is_continuation, - peer_endpoint.data(), peer_endpoint.size()); + peer_endpoint.data(), peer_endpoint.size(), &io_ex, 0); p.v = p.p = 0; } }; diff --git a/include/boost/asio/detail/reactive_socket_service_base.hpp b/include/boost/asio/detail/reactive_socket_service_base.hpp index 63b154e4..6dc76483 100644 --- a/include/boost/asio/detail/reactive_socket_service_base.hpp +++ b/include/boost/asio/detail/reactive_socket_service_base.hpp @@ -218,20 +218,21 @@ public: int op_type; switch (w) { - case socket_base::wait_read: - op_type = reactor::read_op; - break; - case socket_base::wait_write: - op_type = reactor::write_op; - break; - case socket_base::wait_error: - op_type = reactor::except_op; - break; - default: - p.p->ec_ = boost::asio::error::invalid_argument; - reactor_.post_immediate_completion(p.p, is_continuation); - p.v = p.p = 0; - return; + case socket_base::wait_read: + op_type = reactor::read_op; + break; + case socket_base::wait_write: + op_type = reactor::write_op; + break; + case socket_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + start_op(impl, reactor::read_op, p.p, + is_continuation, false, true, &io_ex, 0); + p.v = p.p = 0; + return; } // Optionally register for per-operation cancellation. @@ -242,7 +243,7 @@ public: &reactor_, &impl.reactor_data_, impl.socket_, op_type); } - start_op(impl, op_type, p.p, is_continuation, false, false); + start_op(impl, op_type, p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -314,7 +315,7 @@ public: start_op(impl, reactor::write_op, p.p, is_continuation, true, ((impl.state_ & socket_ops::stream_oriented) && buffer_sequence_adapter::all_empty(buffers))); + ConstBufferSequence>::all_empty(buffers)), &io_ex, 0); p.v = p.p = 0; } @@ -346,7 +347,8 @@ public: BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send(null_buffers)")); - start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + start_op(impl, reactor::write_op, p.p, + is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -423,7 +425,7 @@ public: (flags & socket_base::message_out_of_band) == 0, ((impl.state_ & socket_ops::stream_oriented) && buffer_sequence_adapter::all_empty(buffers))); + MutableBufferSequence>::all_empty(buffers)), &io_ex, 0); p.v = p.p = 0; } @@ -459,7 +461,7 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, false, false); + p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -531,7 +533,7 @@ public: (in_flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, p.p, is_continuation, - (in_flags & socket_base::message_out_of_band) == 0, false); + (in_flags & socket_base::message_out_of_band) == 0, false, &io_ex, 0); p.v = p.p = 0; } @@ -572,7 +574,7 @@ public: start_op(impl, (in_flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - p.p, is_continuation, false, false); + p.p, is_continuation, false, false, &io_ex, 0); p.v = p.p = 0; } @@ -588,16 +590,111 @@ protected: const native_handle_type& native_socket, boost::system::error_code& ec); // Start the asynchronous read or write operation. - BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type, - reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + BOOST_ASIO_DECL void do_start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous operation for handlers that are specialised for + // immediate completion. + template + void start_op(base_implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, + const void* io_ex, ...) + { + return do_start_op(impl, op_type, op, is_continuation, + is_non_blocking, noop, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template + void start_op(base_implementation_type& impl, int op_type, Op* op, + bool is_continuation, bool is_non_blocking, bool noop, const void*, + typename enable_if< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >::type*) + { + return do_start_op(impl, op_type, op, is_continuation, is_non_blocking, + noop, &reactor::call_post_immediate_completion, &reactor_); + } // Start the asynchronous accept operation. - BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl, - reactor_op* op, bool is_continuation, bool peer_is_open); + BOOST_ASIO_DECL void do_start_accept_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous accept operation for handlers that are specialised + // for immediate completion. + template + void start_accept_op(base_implementation_type& impl, Op* op, + bool is_continuation, bool peer_is_open, const void* io_ex, ...) + { + return do_start_accept_op(impl, op, is_continuation, + peer_is_open, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template + void start_accept_op(base_implementation_type& impl, Op* op, + bool is_continuation, bool peer_is_open, const void*, + typename enable_if< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >::type*) + { + return do_start_accept_op(impl, op, is_continuation, peer_is_open, + &reactor::call_post_immediate_completion, &reactor_); + } // Start the asynchronous connect operation. - BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl, - reactor_op* op, bool is_continuation, const void* addr, size_t addrlen); + BOOST_ASIO_DECL void do_start_connect_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, const void* addr, size_t addrlen, + void (*on_immediate)(operation* op, bool, const void*), + const void* immediate_arg); + + // Start the asynchronous operation for handlers that are specialised for + // immediate completion. + template + void start_connect_op(base_implementation_type& impl, + Op* op, bool is_continuation, const void* addr, + size_t addrlen, const void* io_ex, ...) + { + return do_start_connect_op(impl, op, is_continuation, + addr, addrlen, &Op::do_immediate, io_ex); + } + + // Start the asynchronous operation for handlers that are not specialised for + // immediate completion. + template + void start_connect_op(base_implementation_type& impl, Op* op, + bool is_continuation, const void* addr, size_t addrlen, const void*, + typename enable_if< + is_same< + typename associated_immediate_executor< + typename Op::handler_type, + typename Op::io_executor_type + >::asio_associated_immediate_executor_is_unspecialised, + void + >::value + >::type*) + { + return do_start_connect_op(impl, op, is_continuation, addr, + addrlen, &reactor::call_post_immediate_completion, &reactor_); + } // Helper class used to implement per-operation cancellation class reactor_op_cancellation diff --git a/include/boost/asio/detail/reactive_wait_op.hpp b/include/boost/asio/detail/reactive_wait_op.hpp index 8e60fd4d..a9bf01e0 100644 --- a/include/boost/asio/detail/reactive_wait_op.hpp +++ b/include/boost/asio/detail/reactive_wait_op.hpp @@ -34,6 +34,9 @@ template class reactive_wait_op : public reactor_op { public: + typedef Handler handler_type; + typedef IoExecutor io_executor_type; + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); reactive_wait_op(const boost::system::error_code& success_ec, @@ -86,6 +89,35 @@ public: } } + static void do_immediate(operation* base, bool, const void* io_ex) + { + // Take ownership of the handler object. + reactive_wait_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Take ownership of the operation's outstanding work. + immediate_handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_, io_ex); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + private: Handler handler_; handler_work work_; diff --git a/include/boost/asio/detail/select_reactor.hpp b/include/boost/asio/detail/select_reactor.hpp index 9a73d8f9..a4b8b81a 100644 --- a/include/boost/asio/detail/select_reactor.hpp +++ b/include/boost/asio/detail/select_reactor.hpp @@ -95,12 +95,29 @@ public: per_descriptor_data& descriptor_data, reactor_op* op); // Post a reactor operation for immediate completion. - void post_immediate_completion(reactor_op* op, bool is_continuation); + void post_immediate_completion(operation* op, bool is_continuation) const; + + // Post a reactor operation for immediate completion. + BOOST_ASIO_DECL static void call_post_immediate_completion( + operation* op, bool is_continuation, const void* self); // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool is_continuation, bool); + per_descriptor_data&, reactor_op* op, bool is_continuation, bool, + void (*on_immediate)(operation*, bool, const void*), + const void* immediate_arg); + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) + { + start_op(op_type, descriptor, descriptor_data, + op, is_continuation, allow_speculative, + &select_reactor::call_post_immediate_completion, this); + } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the diff --git a/test/archetypes/async_result.hpp b/test/archetypes/async_result.hpp index e59f4c8f..5c6c6938 100644 --- a/test/archetypes/async_result.hpp +++ b/test/archetypes/async_result.hpp @@ -12,9 +12,14 @@ #define ARCHETYPES_ASYNC_RESULT_HPP #include +#include namespace archetypes { +struct immediate_handler +{ +}; + struct lazy_handler { }; @@ -25,7 +30,7 @@ struct concrete_handler; template struct concrete_handler { - concrete_handler(lazy_handler) + concrete_handler() { } @@ -43,18 +48,48 @@ private: template struct concrete_handler { - concrete_handler(lazy_handler) + concrete_handler() { } - void operator()(typename boost::asio::decay::type, typename boost::asio::decay::type) + void operator()(typename boost::asio::decay::type, + typename boost::asio::decay::type) + { + } +}; + +template +struct immediate_concrete_handler : concrete_handler +{ + typedef boost::asio::system_executor immediate_executor_type; + + immediate_concrete_handler(immediate_handler) + { + } + + immediate_executor_type get_immediate_executor() const BOOST_ASIO_NOEXCEPT + { + return immediate_executor_type(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) + immediate_concrete_handler(immediate_concrete_handler&&) {} +private: + immediate_concrete_handler(const immediate_concrete_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +template +struct lazy_concrete_handler : concrete_handler +{ + lazy_concrete_handler(lazy_handler) { } #if defined(BOOST_ASIO_HAS_MOVE) - concrete_handler(concrete_handler&&) {} + lazy_concrete_handler(lazy_concrete_handler&&) {} private: - concrete_handler(const concrete_handler&); + lazy_concrete_handler(const lazy_concrete_handler&); #endif // defined(BOOST_ASIO_HAS_MOVE) }; @@ -63,12 +98,39 @@ private: namespace boost { namespace asio { +template +class async_result +{ +public: + // The concrete completion handler type. + typedef archetypes::immediate_concrete_handler + completion_handler_type; + + // The return type of the initiating function. + typedef void return_type; + + // Construct an async_result from a given handler. + explicit async_result(completion_handler_type&) + { + } + + // Obtain the value to be returned from the initiating function. + void get() + { + } + +private: + // Disallow copying and assignment. + async_result(const async_result&) BOOST_ASIO_DELETED; + async_result& operator=(const async_result&) BOOST_ASIO_DELETED; +}; + template class async_result { public: // The concrete completion handler type. - typedef archetypes::concrete_handler completion_handler_type; + typedef archetypes::lazy_concrete_handler completion_handler_type; // The return type of the initiating function. typedef int return_type; diff --git a/test/generic/datagram_protocol.cpp b/test/generic/datagram_protocol.cpp index 983bacc8..caaafd69 100644 --- a/test/generic/datagram_protocol.cpp +++ b/test/generic/datagram_protocol.cpp @@ -20,6 +20,7 @@ #include #include #include "../unit_test.hpp" +#include "../archetypes/async_result.hpp" #if defined(__cplusplus_cli) || defined(__cplusplus_winrt) # define generic cpp_generic @@ -65,6 +66,7 @@ void test() socket_base::message_flags in_flags = 0; socket_base::send_buffer_size socket_option; socket_base::bytes_readable io_control_command; + archetypes::immediate_handler immediate; boost::system::error_code ec; // basic_datagram_socket constructors. @@ -143,6 +145,7 @@ void test() socket1.connect(dp::endpoint(), ec); socket1.async_connect(dp::endpoint(), connect_handler); + socket1.async_connect(dp::endpoint(), immediate); socket1.set_option(socket_option); socket1.set_option(socket_option, ec); @@ -184,6 +187,12 @@ void test() socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); socket1.async_send(null_buffers(), in_flags, send_handler); + socket1.async_send(buffer(mutable_char_buffer), immediate); + socket1.async_send(buffer(const_char_buffer), immediate); + socket1.async_send(null_buffers(), immediate); + socket1.async_send(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_send(buffer(const_char_buffer), in_flags, immediate); + socket1.async_send(null_buffers(), in_flags, immediate); socket1.send_to(buffer(mutable_char_buffer), dp::endpoint()); @@ -216,6 +225,18 @@ void test() dp::endpoint(), in_flags, send_handler); socket1.async_send_to(null_buffers(), dp::endpoint(), in_flags, send_handler); + socket1.async_send_to(buffer(mutable_char_buffer), + dp::endpoint(), immediate); + socket1.async_send_to(buffer(const_char_buffer), + dp::endpoint(), immediate); + socket1.async_send_to(null_buffers(), + dp::endpoint(), immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + dp::endpoint(), in_flags, immediate); + socket1.async_send_to(buffer(const_char_buffer), + dp::endpoint(), in_flags, immediate); + socket1.async_send_to(null_buffers(), + dp::endpoint(), in_flags, immediate); socket1.receive(buffer(mutable_char_buffer)); socket1.receive(null_buffers()); @@ -229,6 +250,10 @@ void test() socket1.async_receive(buffer(mutable_char_buffer), in_flags, receive_handler); socket1.async_receive(null_buffers(), in_flags, receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), immediate); + socket1.async_receive(null_buffers(), immediate); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_receive(null_buffers(), in_flags, immediate); dp::endpoint endpoint; socket1.receive_from(buffer(mutable_char_buffer), endpoint); @@ -246,6 +271,14 @@ void test() endpoint, in_flags, receive_handler); socket1.async_receive_from(null_buffers(), endpoint, in_flags, receive_handler); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, immediate); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, immediate); } catch (std::exception&) { diff --git a/test/generic/raw_protocol.cpp b/test/generic/raw_protocol.cpp index 0a273927..f5d835f8 100644 --- a/test/generic/raw_protocol.cpp +++ b/test/generic/raw_protocol.cpp @@ -20,6 +20,7 @@ #include #include #include "../unit_test.hpp" +#include "../archetypes/async_result.hpp" #if defined(__cplusplus_cli) || defined(__cplusplus_winrt) # define generic cpp_generic @@ -65,6 +66,7 @@ void test() socket_base::message_flags in_flags = 0; socket_base::send_buffer_size socket_option; socket_base::bytes_readable io_control_command; + archetypes::immediate_handler immediate; boost::system::error_code ec; // basic_raw_socket constructors. @@ -143,6 +145,7 @@ void test() socket1.connect(rp::endpoint(), ec); socket1.async_connect(rp::endpoint(), connect_handler); + socket1.async_connect(rp::endpoint(), immediate); socket1.set_option(socket_option); socket1.set_option(socket_option, ec); @@ -184,6 +187,12 @@ void test() socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); socket1.async_send(null_buffers(), in_flags, send_handler); + socket1.async_send(buffer(mutable_char_buffer), immediate); + socket1.async_send(buffer(const_char_buffer), immediate); + socket1.async_send(null_buffers(), immediate); + socket1.async_send(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_send(buffer(const_char_buffer), in_flags, immediate); + socket1.async_send(null_buffers(), in_flags, immediate); socket1.send_to(buffer(mutable_char_buffer), rp::endpoint()); @@ -216,6 +225,18 @@ void test() rp::endpoint(), in_flags, send_handler); socket1.async_send_to(null_buffers(), rp::endpoint(), in_flags, send_handler); + socket1.async_send_to(buffer(mutable_char_buffer), + rp::endpoint(), immediate); + socket1.async_send_to(buffer(const_char_buffer), + rp::endpoint(), immediate); + socket1.async_send_to(null_buffers(), + rp::endpoint(), immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + rp::endpoint(), in_flags, immediate); + socket1.async_send_to(buffer(const_char_buffer), + rp::endpoint(), in_flags, immediate); + socket1.async_send_to(null_buffers(), + rp::endpoint(), in_flags, immediate); socket1.receive(buffer(mutable_char_buffer)); socket1.receive(null_buffers()); @@ -229,6 +250,11 @@ void test() socket1.async_receive(buffer(mutable_char_buffer), in_flags, receive_handler); socket1.async_receive(null_buffers(), in_flags, receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), immediate); + socket1.async_receive(null_buffers(), immediate); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + immediate); + socket1.async_receive(null_buffers(), in_flags, immediate); rp::endpoint endpoint; socket1.receive_from(buffer(mutable_char_buffer), endpoint); @@ -246,6 +272,14 @@ void test() endpoint, in_flags, receive_handler); socket1.async_receive_from(null_buffers(), endpoint, in_flags, receive_handler); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, immediate); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, immediate); } catch (std::exception&) { diff --git a/test/generic/seq_packet_protocol.cpp b/test/generic/seq_packet_protocol.cpp index def0c40c..a92814f9 100644 --- a/test/generic/seq_packet_protocol.cpp +++ b/test/generic/seq_packet_protocol.cpp @@ -19,6 +19,7 @@ #include #include #include "../unit_test.hpp" +#include "../archetypes/async_result.hpp" #if defined(__cplusplus_cli) || defined(__cplusplus_winrt) # define generic cpp_generic @@ -64,6 +65,7 @@ void test() socket_base::message_flags out_flags = 0; socket_base::send_buffer_size socket_option; socket_base::bytes_readable io_control_command; + archetypes::immediate_handler immediate; boost::system::error_code ec; // basic_seq_packet_socket constructors. @@ -139,6 +141,7 @@ void test() socket1.connect(spp::endpoint(), ec); socket1.async_connect(spp::endpoint(), connect_handler); + socket1.async_connect(spp::endpoint(), immediate); socket1.set_option(socket_option); socket1.set_option(socket_option, ec); @@ -174,6 +177,9 @@ void test() socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); socket1.async_send(null_buffers(), in_flags, send_handler); + socket1.async_send(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_send(buffer(const_char_buffer), in_flags, immediate); + socket1.async_send(null_buffers(), in_flags, immediate); socket1.receive(buffer(mutable_char_buffer), out_flags); socket1.receive(null_buffers(), out_flags); @@ -188,6 +194,11 @@ void test() socket1.async_receive(buffer(mutable_char_buffer), in_flags, out_flags, receive_handler); socket1.async_receive(null_buffers(), in_flags, out_flags, receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), out_flags, immediate); + socket1.async_receive(null_buffers(), out_flags, immediate); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + out_flags, immediate); + socket1.async_receive(null_buffers(), in_flags, out_flags, immediate); } catch (std::exception&) { diff --git a/test/generic/stream_protocol.cpp b/test/generic/stream_protocol.cpp index e7ec1c2f..2aa2c09d 100644 --- a/test/generic/stream_protocol.cpp +++ b/test/generic/stream_protocol.cpp @@ -20,6 +20,7 @@ #include #include #include "../unit_test.hpp" +#include "../archetypes/async_result.hpp" #if defined(__cplusplus_cli) || defined(__cplusplus_winrt) # define generic cpp_generic @@ -73,6 +74,7 @@ void test() socket_base::message_flags in_flags = 0; socket_base::keep_alive socket_option; socket_base::bytes_readable io_control_command; + archetypes::immediate_handler immediate; boost::system::error_code ec; // basic_stream_socket constructors. @@ -159,6 +161,7 @@ void test() socket1.connect(sp::endpoint(), ec); socket1.async_connect(sp::endpoint(), connect_handler); + socket1.async_connect(sp::endpoint(), immediate); socket1.set_option(socket_option); socket1.set_option(socket_option, ec); @@ -200,6 +203,12 @@ void test() socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); socket1.async_send(null_buffers(), in_flags, send_handler); + socket1.async_send(buffer(mutable_char_buffer), immediate); + socket1.async_send(buffer(const_char_buffer), immediate); + socket1.async_send(null_buffers(), immediate); + socket1.async_send(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_send(buffer(const_char_buffer), in_flags, immediate); + socket1.async_send(null_buffers(), in_flags, immediate); socket1.receive(buffer(mutable_char_buffer)); socket1.receive(null_buffers()); @@ -213,6 +222,11 @@ void test() socket1.async_receive(buffer(mutable_char_buffer), in_flags, receive_handler); socket1.async_receive(null_buffers(), in_flags, receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), immediate); + socket1.async_receive(null_buffers(), immediate); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + immediate); + socket1.async_receive(null_buffers(), in_flags, immediate); socket1.write_some(buffer(mutable_char_buffer)); socket1.write_some(buffer(const_char_buffer)); @@ -224,6 +238,9 @@ void test() socket1.async_write_some(buffer(mutable_char_buffer), write_some_handler); socket1.async_write_some(buffer(const_char_buffer), write_some_handler); socket1.async_write_some(null_buffers(), write_some_handler); + socket1.async_write_some(buffer(mutable_char_buffer), immediate); + socket1.async_write_some(buffer(const_char_buffer), immediate); + socket1.async_write_some(null_buffers(), immediate); socket1.read_some(buffer(mutable_char_buffer)); socket1.read_some(buffer(mutable_char_buffer), ec); @@ -231,6 +248,8 @@ void test() socket1.async_read_some(buffer(mutable_char_buffer), read_some_handler); socket1.async_read_some(null_buffers(), read_some_handler); + socket1.async_read_some(buffer(mutable_char_buffer), immediate); + socket1.async_read_some(null_buffers(), immediate); } catch (std::exception&) { diff --git a/test/ip/icmp.cpp b/test/ip/icmp.cpp index ad8f1aed..a738206c 100644 --- a/test/ip/icmp.cpp +++ b/test/ip/icmp.cpp @@ -86,6 +86,7 @@ void test() archetypes::gettable_socket_option gettable_socket_option2; archetypes::gettable_socket_option gettable_socket_option3; archetypes::io_control_command io_control_command; + archetypes::immediate_handler immediate; archetypes::lazy_handler lazy; boost::system::error_code ec; @@ -193,6 +194,8 @@ void test() connect_handler()); socket1.async_connect(ip::icmp::endpoint(ip::icmp::v6(), 0), connect_handler()); + socket1.async_connect(ip::icmp::endpoint(ip::icmp::v4(), 0), immediate); + socket1.async_connect(ip::icmp::endpoint(ip::icmp::v6(), 0), immediate); int i1 = socket1.async_connect(ip::icmp::endpoint(ip::icmp::v4(), 0), lazy); (void)i1; int i2 = socket1.async_connect(ip::icmp::endpoint(ip::icmp::v6(), 0), lazy); @@ -256,6 +259,12 @@ void test() socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler()); socket1.async_send(buffer(const_char_buffer), in_flags, send_handler()); socket1.async_send(null_buffers(), in_flags, send_handler()); + socket1.async_send(buffer(mutable_char_buffer), immediate); + socket1.async_send(buffer(const_char_buffer), immediate); + socket1.async_send(null_buffers(), immediate); + socket1.async_send(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_send(buffer(const_char_buffer), in_flags, immediate); + socket1.async_send(null_buffers(), in_flags, immediate); int i3 = socket1.async_send(buffer(mutable_char_buffer), lazy); (void)i3; int i4 = socket1.async_send(buffer(const_char_buffer), lazy); @@ -330,6 +339,30 @@ void test() ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, send_handler()); socket1.async_send_to(null_buffers(), ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), immediate); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), immediate); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, immediate); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, immediate); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, immediate); int i9 = socket1.async_send_to(buffer(mutable_char_buffer), ip::icmp::endpoint(ip::icmp::v4(), 0), lazy); (void)i9; @@ -379,6 +412,10 @@ void test() socket1.async_receive(buffer(mutable_char_buffer), in_flags, receive_handler()); socket1.async_receive(null_buffers(), in_flags, receive_handler()); + socket1.async_receive(buffer(mutable_char_buffer), immediate); + socket1.async_receive(null_buffers(), immediate); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_receive(null_buffers(), in_flags, immediate); int i21 = socket1.async_receive(buffer(mutable_char_buffer), lazy); (void)i21; int i22 = socket1.async_receive(null_buffers(), lazy); @@ -405,6 +442,14 @@ void test() endpoint, in_flags, receive_handler()); socket1.async_receive_from(null_buffers(), endpoint, in_flags, receive_handler()); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, immediate); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, immediate); int i25 = socket1.async_receive_from(buffer(mutable_char_buffer), endpoint, lazy); (void)i25; diff --git a/test/ip/tcp.cpp b/test/ip/tcp.cpp index 083baf66..e60542e0 100644 --- a/test/ip/tcp.cpp +++ b/test/ip/tcp.cpp @@ -239,6 +239,7 @@ void test() archetypes::gettable_socket_option gettable_socket_option2; archetypes::gettable_socket_option gettable_socket_option3; archetypes::io_control_command io_control_command; + archetypes::immediate_handler immediate; archetypes::lazy_handler lazy; boost::system::error_code ec; @@ -346,6 +347,8 @@ void test() connect_handler()); socket1.async_connect(ip::tcp::endpoint(ip::tcp::v6(), 0), connect_handler()); + socket1.async_connect(ip::tcp::endpoint(ip::tcp::v4(), 0), immediate); + socket1.async_connect(ip::tcp::endpoint(ip::tcp::v6(), 0), immediate); int i1 = socket1.async_connect(ip::tcp::endpoint(ip::tcp::v4(), 0), lazy); (void)i1; int i2 = socket1.async_connect(ip::tcp::endpoint(ip::tcp::v6(), 0), lazy); @@ -395,6 +398,7 @@ void test() socket1.wait(socket_base::wait_write, ec); socket1.async_wait(socket_base::wait_read, wait_handler()); + socket1.async_wait(socket_base::wait_read, immediate); int i3 = socket1.async_wait(socket_base::wait_write, lazy); (void)i3; @@ -426,6 +430,16 @@ void test() socket1.async_send(mutable_buffers, in_flags, send_handler()); socket1.async_send(const_buffers, in_flags, send_handler()); socket1.async_send(null_buffers(), in_flags, send_handler()); + socket1.async_send(buffer(mutable_char_buffer), immediate); + socket1.async_send(buffer(const_char_buffer), immediate); + socket1.async_send(mutable_buffers, immediate); + socket1.async_send(const_buffers, immediate); + socket1.async_send(null_buffers(), immediate); + socket1.async_send(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_send(buffer(const_char_buffer), in_flags, immediate); + socket1.async_send(mutable_buffers, in_flags, immediate); + socket1.async_send(const_buffers, in_flags, immediate); + socket1.async_send(null_buffers(), in_flags, immediate); int i4 = socket1.async_send(buffer(mutable_char_buffer), lazy); (void)i4; int i5 = socket1.async_send(buffer(const_char_buffer), lazy); @@ -464,6 +478,12 @@ void test() receive_handler()); socket1.async_receive(mutable_buffers, in_flags, receive_handler()); socket1.async_receive(null_buffers(), in_flags, receive_handler()); + socket1.async_receive(buffer(mutable_char_buffer), immediate); + socket1.async_receive(mutable_buffers, immediate); + socket1.async_receive(null_buffers(), immediate); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_receive(mutable_buffers, in_flags, immediate); + socket1.async_receive(null_buffers(), in_flags, immediate); int i14 = socket1.async_receive(buffer(mutable_char_buffer), lazy); (void)i14; int i15 = socket1.async_receive(mutable_buffers, lazy); @@ -494,6 +514,11 @@ void test() socket1.async_write_some(mutable_buffers, write_some_handler()); socket1.async_write_some(const_buffers, write_some_handler()); socket1.async_write_some(null_buffers(), write_some_handler()); + socket1.async_write_some(buffer(mutable_char_buffer), immediate); + socket1.async_write_some(buffer(const_char_buffer), immediate); + socket1.async_write_some(mutable_buffers, immediate); + socket1.async_write_some(const_buffers, immediate); + socket1.async_write_some(null_buffers(), immediate); int i20 = socket1.async_write_some(buffer(mutable_char_buffer), lazy); (void)i20; int i21 = socket1.async_write_some(buffer(const_char_buffer), lazy); @@ -515,6 +540,9 @@ void test() socket1.async_read_some(buffer(mutable_char_buffer), read_some_handler()); socket1.async_read_some(mutable_buffers, read_some_handler()); socket1.async_read_some(null_buffers(), read_some_handler()); + socket1.async_read_some(buffer(mutable_char_buffer), immediate); + socket1.async_read_some(mutable_buffers, immediate); + socket1.async_read_some(null_buffers(), immediate); int i25 = socket1.async_read_some(buffer(mutable_char_buffer), lazy); (void)i25; int i26 = socket1.async_read_some(mutable_buffers, lazy); @@ -767,6 +795,7 @@ void test() archetypes::gettable_socket_option gettable_socket_option2; archetypes::gettable_socket_option gettable_socket_option3; archetypes::io_control_command io_control_command; + archetypes::immediate_handler immediate; archetypes::lazy_handler lazy; boost::system::error_code ec; @@ -883,6 +912,7 @@ void test() acceptor1.wait(socket_base::wait_write, ec); acceptor1.async_wait(socket_base::wait_read, wait_handler()); + acceptor1.async_wait(socket_base::wait_read, immediate); int i1 = acceptor1.async_wait(socket_base::wait_write, lazy); (void)i1; @@ -914,6 +944,8 @@ void test() acceptor1.async_accept(peer_socket1, accept_handler()); acceptor1.async_accept(peer_socket1, peer_endpoint, accept_handler()); + acceptor1.async_accept(peer_socket1, immediate); + acceptor1.async_accept(peer_socket1, peer_endpoint, immediate); int i2 = acceptor1.async_accept(peer_socket1, lazy); (void)i2; int i3 = acceptor1.async_accept(peer_socket1, peer_endpoint, lazy); @@ -921,6 +953,8 @@ void test() acceptor1.async_accept(peer_socket2, accept_handler()); acceptor1.async_accept(peer_socket2, peer_endpoint, accept_handler()); + acceptor1.async_accept(peer_socket2, immediate); + acceptor1.async_accept(peer_socket2, peer_endpoint, immediate); int i4 = acceptor1.async_accept(peer_socket2, lazy); (void)i4; int i5 = acceptor1.async_accept(peer_socket2, peer_endpoint, lazy); @@ -935,6 +969,12 @@ void test() acceptor1.async_accept(ioc, peer_endpoint, move_accept_handler()); acceptor1.async_accept(ioc_ex, peer_endpoint, move_accept_handler()); acceptor1.async_accept(ioc_ex, peer_endpoint, move_accept_ioc_handler()); + acceptor1.async_accept(immediate); + acceptor1.async_accept(ioc, immediate); + acceptor1.async_accept(ioc_ex, immediate); + acceptor1.async_accept(peer_endpoint, immediate); + acceptor1.async_accept(ioc, peer_endpoint, immediate); + acceptor1.async_accept(ioc_ex, peer_endpoint, immediate); #endif // defined(BOOST_ASIO_HAS_MOVE) } catch (std::exception&) diff --git a/test/ip/udp.cpp b/test/ip/udp.cpp index e586697d..2285f9b1 100644 --- a/test/ip/udp.cpp +++ b/test/ip/udp.cpp @@ -102,6 +102,7 @@ void test() archetypes::gettable_socket_option gettable_socket_option2; archetypes::gettable_socket_option gettable_socket_option3; archetypes::io_control_command io_control_command; + archetypes::immediate_handler immediate; archetypes::lazy_handler lazy; boost::system::error_code ec; @@ -209,6 +210,8 @@ void test() connect_handler()); socket1.async_connect(ip::udp::endpoint(ip::udp::v6(), 0), connect_handler()); + socket1.async_connect(ip::udp::endpoint(ip::udp::v4(), 0), immediate); + socket1.async_connect(ip::udp::endpoint(ip::udp::v6(), 0), immediate); int i1 = socket1.async_connect(ip::udp::endpoint(ip::udp::v4(), 0), lazy); (void)i1; int i2 = socket1.async_connect(ip::udp::endpoint(ip::udp::v6(), 0), lazy); @@ -258,6 +261,7 @@ void test() socket1.wait(socket_base::wait_write, ec); socket1.async_wait(socket_base::wait_read, wait_handler()); + socket1.async_wait(socket_base::wait_read, immediate); int i3 = socket1.async_wait(socket_base::wait_write, lazy); (void)i3; @@ -279,6 +283,12 @@ void test() socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler()); socket1.async_send(buffer(const_char_buffer), in_flags, send_handler()); socket1.async_send(null_buffers(), in_flags, send_handler()); + socket1.async_send(buffer(mutable_char_buffer), immediate); + socket1.async_send(buffer(const_char_buffer), immediate); + socket1.async_send(null_buffers(), immediate); + socket1.async_send(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_send(buffer(const_char_buffer), in_flags, immediate); + socket1.async_send(null_buffers(), in_flags, immediate); int i4 = socket1.async_send(buffer(mutable_char_buffer), lazy); (void)i4; int i5 = socket1.async_send(buffer(const_char_buffer), lazy); @@ -353,6 +363,30 @@ void test() ip::udp::endpoint(ip::udp::v4(), 0), in_flags, send_handler()); socket1.async_send_to(null_buffers(), ip::udp::endpoint(ip::udp::v6(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), immediate); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), immediate); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, immediate); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, immediate); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, immediate); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, immediate); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, immediate); int i10 = socket1.async_send_to(buffer(mutable_char_buffer), ip::udp::endpoint(ip::udp::v4(), 0), lazy); (void)i10; @@ -402,6 +436,10 @@ void test() socket1.async_receive(buffer(mutable_char_buffer), in_flags, receive_handler()); socket1.async_receive(null_buffers(), in_flags, receive_handler()); + socket1.async_receive(buffer(mutable_char_buffer), immediate); + socket1.async_receive(null_buffers(), immediate); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, immediate); + socket1.async_receive(null_buffers(), in_flags, immediate); int i22 = socket1.async_receive(buffer(mutable_char_buffer), lazy); (void)i22; int i23 = socket1.async_receive(null_buffers(), lazy); @@ -428,6 +466,14 @@ void test() endpoint, in_flags, receive_handler()); socket1.async_receive_from(null_buffers(), endpoint, in_flags, receive_handler()); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, immediate); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, immediate); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, immediate); int i26 = socket1.async_receive_from(buffer(mutable_char_buffer), endpoint, lazy); (void)i26; diff --git a/test/posix/stream_descriptor.cpp b/test/posix/stream_descriptor.cpp index 3d104673..629c6849 100644 --- a/test/posix/stream_descriptor.cpp +++ b/test/posix/stream_descriptor.cpp @@ -55,6 +55,7 @@ void test() char mutable_char_buffer[128] = ""; const char const_char_buffer[128] = ""; posix::descriptor_base::bytes_readable io_control_command; + archetypes::immediate_handler immediate; archetypes::lazy_handler lazy; boost::system::error_code ec; @@ -134,6 +135,7 @@ void test() descriptor1.wait(posix::descriptor_base::wait_write, ec); descriptor1.async_wait(posix::descriptor_base::wait_read, &wait_handler); + descriptor1.async_wait(posix::descriptor_base::wait_read, immediate); int i1 = descriptor1.async_wait(posix::descriptor_base::wait_write, lazy); (void)i1; @@ -152,6 +154,9 @@ void test() write_some_handler); descriptor1.async_write_some(null_buffers(), write_some_handler); + descriptor1.async_write_some(buffer(mutable_char_buffer), immediate); + descriptor1.async_write_some(buffer(const_char_buffer), immediate); + descriptor1.async_write_some(null_buffers(), immediate); int i2 = descriptor1.async_write_some(buffer(mutable_char_buffer), lazy); (void)i2; int i3 = descriptor1.async_write_some(buffer(const_char_buffer), lazy); @@ -165,6 +170,8 @@ void test() descriptor1.async_read_some(buffer(mutable_char_buffer), read_some_handler); descriptor1.async_read_some(null_buffers(), read_some_handler); + descriptor1.async_read_some(buffer(mutable_char_buffer), immediate); + descriptor1.async_read_some(null_buffers(), immediate); int i5 = descriptor1.async_read_some(buffer(mutable_char_buffer), lazy); (void)i5; int i6 = descriptor1.async_read_some(null_buffers(), lazy);