diff --git a/doc/history.qbk b/doc/history.qbk index ab2af9ff..f71bcccb 100644 --- a/doc/history.qbk +++ b/doc/history.qbk @@ -7,7 +7,32 @@ [section:history Revision History] -[heading Asio 1.22.1 / Boost 1.79 beta] +[heading Asio 1.22.2 / Boost 1.79] + +* On Windows, changed the file support to open files using the same sharing mode + as `fopen()`. +* On Linux, fixed the UNIX domain sockets implementation to correctly handle + `EAGAIN` as an indication of an in-progress connect operation. +* Fixed `experimental::basic_channel::reset()` and + `experimental::basic_concurrent_channel::reset()` so that they work correctly + for an unclosed channel. +* Fixed potential undefined behaviour in the `experimental::promise` operations + `race()` and `all()`. +* Changed the `co_spawn` implementation to explicitly dispatch cancellation + signals through the specified executor, if the the completion handler has an + associated executor of its own. +* Added more detailed reference documentation to `make_strand()`, + `make_work_guard()`, `ip::address_v4`, `ip::address_v6`, + `experimental::basic_channel`, and `experimental::basic_concurrent_channel`. +* Re-arranged and extended the Overview documentation to cover files, pipes, + `async_compose`, `experimental::deferred`, `experimental::parallel_group`, + `experimental::promise`, channels, and completion token adapters. +* Reverted the `io_context` reference documentation to use `executor_work_guard` + when preventing the `io_context` from running out of work. +* Removed references to `deadline_timer` from the Overview documentation. +* Added reference documentation cross-references to asynchronous model elements. + +[heading Asio 1.22.1] * Added `bind_allocator`, to simplify associating a custom allocator with a completion token or handler. @@ -1550,8 +1575,8 @@ support for returning a C++11 `std::future` from an asynchronous operation's initiating function. For example: `future = my_socket.async_read_some(my_buffer, asio::use_future);`. - For further information, see [link boost_asio.overview.cpp2011.futures C++ - 2011 Support - Futures]. + For further information, see [link boost_asio.overview.composition.futures + Futures]. * Promoted the stackless coroutine class and macros to be part of Asio's documented interface, rather than part of the HTTP server 4 example. For further information, see [link boost_asio.overview.composition.coroutine diff --git a/doc/overview.qbk b/doc/overview.qbk index a03bffd2..3116dbd5 100644 --- a/doc/overview.qbk +++ b/doc/overview.qbk @@ -35,16 +35,25 @@ * [link boost_asio.overview.composition Composition and Completion Tokens] * [link boost_asio.overview.composition.coroutine Stackless Coroutines] * [link boost_asio.overview.composition.spawn Stackful Coroutines] + * [link boost_asio.overview.composition.futures Futures] * [link boost_asio.overview.composition.cpp20_coroutines C++20 Coroutines Support] * [link boost_asio.overview.composition.coro Resumable C++20 Coroutines (experimental)] + * [link boost_asio.overview.composition.deferred Deferred Operations (experimental)] + * [link boost_asio.overview.composition.promises Promises (experimental)] + * [link boost_asio.overview.composition.parallel_group Co-ordinating Parallel Operations (experimental)] + * [link boost_asio.overview.composition.compose Compositions as Asynchronous Operations] + * [link boost_asio.overview.composition.token_adapters Completion Token Adapters] * [link boost_asio.overview.networking Networking] * [link boost_asio.overview.networking.protocols TCP, UDP and ICMP] * [link boost_asio.overview.networking.other_protocols Support for Other Protocols] * [link boost_asio.overview.networking.iostreams Socket Iostreams] * [link boost_asio.overview.networking.bsd_sockets The BSD Socket API and Boost.Asio] * [link boost_asio.overview.timers Timers] +* [link boost_asio.overview.files Files] +* [link boost_asio.overview.pipes Pipes] * [link boost_asio.overview.serial_ports Serial Ports] * [link boost_asio.overview.signals Signal Handling] +* [link boost_asio.overview.channels Channels (experimental)] * [link boost_asio.overview.posix POSIX-Specific Functionality] * [link boost_asio.overview.posix.local UNIX Domain Sockets] * [link boost_asio.overview.posix.stream_descriptor Stream-Oriented File Descriptors] @@ -62,7 +71,6 @@ * [link boost_asio.overview.cpp2011.atomic Atomics] * [link boost_asio.overview.cpp2011.shared_ptr Shared Pointers] * [link boost_asio.overview.cpp2011.chrono Chrono] - * [link boost_asio.overview.cpp2011.futures Futures] * [link boost_asio.overview.implementation Platform-Specific Implementation Notes] [include overview/rationale.qbk] @@ -101,13 +109,25 @@ * [link boost_asio.overview.composition.coroutine Stackless Coroutines] * [link boost_asio.overview.composition.spawn Stackful Coroutines] +* [link boost_asio.overview.composition.futures Futures] * [link boost_asio.overview.composition.cpp20_coroutines C++20 Coroutines Support] * [link boost_asio.overview.composition.coro Resumable C++20 Coroutines (experimental)] +* [link boost_asio.overview.composition.deferred Deferred Operations (experimental)] +* [link boost_asio.overview.composition.promises Promises (experimental)] +* [link boost_asio.overview.composition.parallel_group Co-ordinating Parallel Operations (experimental)] +* [link boost_asio.overview.composition.compose Compositions as Asynchronous Operations] +* [link boost_asio.overview.composition.token_adapters Completion Token Adapters] [include overview/coroutine.qbk] [include overview/spawn.qbk] +[include overview/futures.qbk] [include overview/cpp20_coroutines.qbk] [include overview/coro.qbk] +[include overview/deferred.qbk] +[include overview/promises.qbk] +[include overview/parallel_group.qbk] +[include overview/compose.qbk] +[include overview/token_adapters.qbk] [endsect] @@ -126,8 +146,11 @@ [endsect] [include overview/timers.qbk] +[include overview/files.qbk] +[include overview/pipes.qbk] [include overview/serial_ports.qbk] [include overview/signals.qbk] +[include overview/channels.qbk] [include overview/posix.qbk] [include overview/windows.qbk] [include overview/ssl.qbk] diff --git a/doc/overview/channels.qbk b/doc/overview/channels.qbk new file mode 100644 index 00000000..7119e147 --- /dev/null +++ b/doc/overview/channels.qbk @@ -0,0 +1,56 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:channels Channels] + +[note This is an experimental feature.] + +The templates +[link boost_asio.reference.experimental__basic_channel experimental::basic_channel] +and [link boost_asio.reference.experimental__basic_concurrent_channel +experimental::basic_concurrent_channel], with aliases `experimental::channel` +and `experimental::concurrent_channel`, may be used to send messages between +different parts of the same application. A ['message] is defined as a +collection of arguments to be passed to a completion handler, and the set of +messages supported by a channel is specified by its template parameters. +Messages may be sent and received using asynchronous or non-blocking +synchronous operations. + +For example: + + // Create a channel with no buffer space. + channel ch(ctx); + + // The call to try_send fails as there is no buffer + // space and no waiting receive operations. + bool ok = ch.try_send(boost::asio::error::eof, 123); + assert(!ok); + + // The async_send operation is outstanding until + // a receive operation consumes the message. + ch.async_send(boost::asio::error::eof, 123, + [](error_code ec) + { + // ... + }); + + // The async_receive consumes the message. Both the + // async_send and async_receive operations complete + // immediately. + ch.async_receive( + [](error_code ec, size_t n) + { + // ... + }); + +[heading See Also] + +[link boost_asio.reference.experimental__basic_channel experimental::basic_channel], +[link boost_asio.reference.experimental__basic_concurrent_channel experimental::basic_concurrent_channel], +[link boost_asio.examples.cpp20_examples.channels Channels examples (C++20)]. + +[endsect] diff --git a/doc/overview/compose.qbk b/doc/overview/compose.qbk new file mode 100644 index 00000000..20097a8e --- /dev/null +++ b/doc/overview/compose.qbk @@ -0,0 +1,101 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:compose Compositions as Asynchronous Operations] + +Application developers may wish to package their own compositions as conforming +[link boost_asio.overview.model.async_ops asynchronous operations] within the [link +boost_asio.overview.model asynchronous model]. Doing so facilitates seamless +composition of these operations together with the operations already provided +by Boost.Asio. + +While these operations may be written from scratch to conform with the [link +boost_asio.reference.asynchronous_operations requirements on asynchronous +operations], Boost.Asio includes the [link boost_asio.reference.async_compose +`async_compose`] function to simplify this process. The `async_compose` +implementation automatically provides an intermediate completion handler that +correctly propagates the [link boost_asio.overview.model.associators associated +characteristics] and tracks outstanding work against the I/O executor and +completion executor. + +The following example illustrates an asynchronous echo loop (i.e. read, +followed by write, and so on), expressed as a simple state machine. + + struct async_echo_implementation + { + tcp::socket& socket_; + boost::asio::mutable_buffer buffer_; + enum { starting, reading, writing } state_; + + template + void operator()(Self& self, + boost::system::error_code error = {}, + std::size_t n = 0) + { + switch (state_) + { + case starting: + state_ = reading; + socket_.async_read_some( + buffer_, std::move(self)); + break; + case reading: + if (error) + { + self.complete(error, 0); + } + else + { + state_ = writing; + boost::asio::async_write(socket_, buffer_, + boost::asio::transfer_exactly(n), + std::move(self)); + } + break; + case writing: + self.complete(error, n); + break; + } + } + }; + +This implementation is then used in an initiating function, which trivially +wraps `async_compose`: + + template + auto async_echo(tcp::socket& socket, + boost::asio::mutable_buffer buffer, + CompletionToken&& token) -> + typename boost::asio::async_result< + typename std::decay::type, + void(boost::system::error_code, std::size_t)>::return_type + { + return boost::asio::async_compose( + async_echo_implementation{socket, buffer, + async_echo_implementation::starting}, + token, socket); + } + +Here, `async_compose` is first passed the function object that contains the +implementation of the composed asynchronous operation. The first argument to +the function object is a non-const reference to the enclosing intermediate +completion handler. The remaining arguments are any arguments that originate +from the completion handlers of any asynchronous operations performed by the +implementation. + +The `async_compose` function is also passed the completion token, and zero or +more I/O objects or I/O executors for which outstanding work must be +maintained. + +[heading See Also] + +[link boost_asio.reference.async_compose async_compose], +[link boost_asio.examples.cpp11_examples.operations Operations examples (C++11)], +[link boost_asio.examples.cpp14_examples.operations Operations examples (C++14)]. + +[endsect] diff --git a/doc/overview/cpp2011.qbk b/doc/overview/cpp2011.qbk index 88d72da3..e69deb41 100644 --- a/doc/overview/cpp2011.qbk +++ b/doc/overview/cpp2011.qbk @@ -22,8 +22,6 @@ [link boost_asio.overview.cpp2011.chrono Chrono] -[link boost_asio.overview.cpp2011.futures Futures] - [section:move_objects Movable I/O Objects] @@ -214,37 +212,4 @@ class template may be used with either. [endsect] -[section:futures Futures] - -The `boost::asio::use_future` special value provides first-class support for returning a -C++11 `std::future` from an asynchronous operation's initiating function. - -To use `boost::asio::use_future`, pass it to an asynchronous operation instead of -a normal completion handler. For example: - - std::future length = - my_socket.async_read_some(my_buffer, boost::asio::use_future); - -Where a handler signature has the form: - - void handler(boost::system::error_code ec, result_type result); - -the initiating function returns a `std::future` templated on `result_type`. -In the above example, this is `std::size_t`. If the asynchronous operation -fails, the `error_code` is converted into a `system_error` exception and -passed back to the caller through the future. - -Where a handler signature has the form: - - void handler(boost::system::error_code ec); - -the initiating function returns `std::future`. As above, an error -is passed back in the future as a `system_error` exception. - -[link boost_asio.reference.use_future use_future], -[link boost_asio.reference.use_future_t use_future_t], -[link boost_asio.examples.cpp11_examples.futures Futures example (C++11)]. - -[endsect] - [endsect] diff --git a/doc/overview/deferred.qbk b/doc/overview/deferred.qbk new file mode 100644 index 00000000..fe253f54 --- /dev/null +++ b/doc/overview/deferred.qbk @@ -0,0 +1,56 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:deferred Deferred Operations] + +[note This is an experimental feature.] + +The [link boost_asio.reference.experimental__deferred `experimental::deferred`], +completion token takes a call to an asynchronous operation's initiating +function and turns it into a function object that accepts a completion token. +For example: + + auto deferred_op = + timer.async_wait( + boost::asio::experimental::deferred); + ... + std::move(deferred_op)( + [](boost::system::error_code ec){ ... }); + +or: + + auto deferred_op = + timer.async_wait( + boost::asio::experimental::deferred); + ... + std::future = + std::move(deferred_op)( + boost::asio::use_future); + +The deferred token also supports chaining, to create simple compositions: + + auto deferred_op = + timer.async_wait( + boost::asio::experimental::deferred( + [&](boost::system::error_code ec) + { + timer.expires_after( + std::chrono::seconds(1)); + + return timer.async_wait( + boost::asio::experimental::deferred); + }); + ... + std::future = std::move(deferred_op)(boost::asio::use_future); + +[heading See Also] + +[link boost_asio.reference.experimental__deferred experimental::deferred], +[link boost_asio.reference.experimental__deferred_t experimental::deferred_t], +[link boost_asio.examples.cpp14_examples.deferred Deferred examples (C++14)]. + +[endsect] diff --git a/doc/overview/files.qbk b/doc/overview/files.qbk new file mode 100644 index 00000000..39151407 --- /dev/null +++ b/doc/overview/files.qbk @@ -0,0 +1,49 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:files Files] + +[note This feature requires I/O completion ports on Windows, and io_uring on +Linux (define `BOOST_ASIO_HAS_IO_URING` to enable).] + +Boost.Asio provides support for manipulating stream-oriented and random-access files. +For example, to write to a newly created stream-oriented file: + + boost::asio::stream_file file( + my_io_context, "/path/to/file", + boost::asio::stream_file::write_only + | boost::asio::stream_file::create + | boost::asio::stream_file::truncate); + + file.async_write_some(my_buffer, + [](error_code e, size_t n) + { + // ... + }); + +or to read from a random-access file: + + boost::asio::random_access_file file( + my_io_context, "/path/to/file", + boost::asio::random_access_file::read_only); + + file.async_read_some_at(1234, my_buffer, + [](error_code e, size_t n) + { + // ... + }); + +[heading See Also] + +[link boost_asio.reference.basic_file basic_file], +[link boost_asio.reference.basic_random_access_file basic_random_access_file], +[link boost_asio.reference.basic_stream_file basic_stream_file], +[link boost_asio.reference.file_base file_base], +[link boost_asio.reference.random_access_file random_access_file], +[link boost_asio.reference.stream_file stream_file]. + +[endsect] diff --git a/doc/overview/futures.qbk b/doc/overview/futures.qbk new file mode 100644 index 00000000..8fe26153 --- /dev/null +++ b/doc/overview/futures.qbk @@ -0,0 +1,41 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:futures Futures] + +The `boost::asio::use_future` completion token provides first-class support for +returning a `std::future` from an asynchronous operation's initiating function. + +To use `boost::asio::use_future`, pass it to an asynchronous operation instead of +a completion handler. For example: + + std::future length = + my_socket.async_read_some(my_buffer, boost::asio::use_future); + +Where a completion signature has the form: + + void handler(boost::system::error_code ec, result_type result); + +the initiating function returns a `std::future` templated on `result_type`. +In the above example, this is `std::size_t`. If the asynchronous operation +fails, the `error_code` is converted into a `system_error` exception and +passed back to the caller through the future. + +Where a completion signature has the form: + + void handler(boost::system::error_code ec); + +the initiating function returns `std::future`. As above, an error +is passed back in the future as a `system_error` exception. + +[heading See Also] + +[link boost_asio.reference.use_future use_future], +[link boost_asio.reference.use_future_t use_future_t], +[link boost_asio.examples.cpp11_examples.futures Futures example (C++11)]. + +[endsect] diff --git a/doc/overview/model/higher_levels.qbk b/doc/overview/model/higher_levels.qbk index c66d7a9c..1d26ffb7 100644 --- a/doc/overview/model/higher_levels.qbk +++ b/doc/overview/model/higher_levels.qbk @@ -25,7 +25,7 @@ facilities, such as: * Completion tokens that facilitate different composition mechanisms, such as [link boost_asio.overview.composition.cpp20_coroutines C++ coroutines], [link boost_asio.overview.composition.spawn stackful coroutines], [link - boost_asio.overview.cpp2011.futures futures], and [link + boost_asio.overview.composition.futures futures], and [link boost_asio.reference.experimental__deferred deferred operations]. * High level support for C++ coroutines that combines support executors and diff --git a/doc/overview/parallel_group.qbk b/doc/overview/parallel_group.qbk new file mode 100644 index 00000000..bf706232 --- /dev/null +++ b/doc/overview/parallel_group.qbk @@ -0,0 +1,65 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:parallel_group Co-ordinating Parallel Operations] + +[note This is an experimental feature.] + +The [link boost_asio.reference.experimental__make_parallel_group +`experimental::make_parallel_group`] function may be used to launch work that +is performed in parallel, and wait for one or all of the operations to +complete. A `parallel_group` implements automatic cancellation of incomplete +operations. For example: + + experimental::make_parallel_group( + [&](auto token) + { + return stream.async_read_some(boost::asio::buffer(data), token); + }, + [&](auto token) + { + return timer.async_wait(token); + } + ).async_wait( + experimental::wait_for_one(), + []( + std::array completion_order, + boost::system::error_code ec1, std::size_t n1, + boost::system::error_code ec2 + ) + { + // ... + } + ); + +The conditions for completion of the group may be specified using one of the +four provided function objects [link boost_asio.reference.experimental__wait_for_all +`wait_for_all`], [link boost_asio.reference.experimental__wait_for_one +`wait_for_one`], [link boost_asio.reference.experimental__wait_for_one_success +`wait_for_one_success`], [link boost_asio.reference.experimental__wait_for_one_error +`wait_for_one_error`], or with a custom function. + +The `parallel_group` facility can also be combined with [link +boost_asio.reference.experimental__deferred `experimental::deferred`] as follows: + + experimental::make_parallel_group( + stream.async_read_some(boost::asio::buffer(data), experimental::deferred), + timer.async_wait(experimental::deferred) + ).async_wait( + // ... + ); + +Note: for maximum flexibility, `parallel_group` does not propagate the +executor automatically to the operations within the group. + +[heading See Also] + +[link boost_asio.reference.experimental__make_parallel_group experimental::make_parallel_group], +[link boost_asio.reference.experimental__parallel_group experimental::parallel_group], +[link boost_asio.examples.cpp14_examples.parallel_groups Parallel Groups examples (C++14)]. + +[endsect] diff --git a/doc/overview/pipes.qbk b/doc/overview/pipes.qbk new file mode 100644 index 00000000..c0ff2d28 --- /dev/null +++ b/doc/overview/pipes.qbk @@ -0,0 +1,38 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:pipes Pipes] + +Boost.Asio provides support for portable anonymous pipes on POSIX and Windows (when +I/O completion ports are available). For example, to create and use a +connected pair of pipe objects: + + boost::asio::readable_pipe read_end(my_io_context); + boost::asio::writable_pipe write_end(my_io_context); + boost::asio::connect_pipe(read_end, write_end); + + write_end.async_write_some(my_write_buffer, + [](boost::system::error_code e, size_t n) + { + // ... + }); + + read_end.async_read_some(my_read_buffer, + [](boost::system::error_code e, size_t n) + { + // ... + }); + +[heading See Also] + +[link boost_asio.reference.basic_readable_pipe basic_readable_pipe], +[link boost_asio.reference.basic_writable_pipe basic_writable_pipe], +[link boost_asio.reference.connect_pipe connect_pipe], +[link boost_asio.reference.readable_pipe readable_pipe], +[link boost_asio.reference.writable_pipe writable_pipe]. + +[endsect] diff --git a/doc/overview/promises.qbk b/doc/overview/promises.qbk new file mode 100644 index 00000000..b89058ec --- /dev/null +++ b/doc/overview/promises.qbk @@ -0,0 +1,79 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:promises Promises] + +[note This is an experimental feature.] + +The [link boost_asio.reference.experimental__promise_lt__void_lp_Ts_ellipsis__rp__comma__Executor__gt_ +`experimental::promise`] type and [link boost_asio.reference.experimental__use_promise +`experimental::use_promise`] completion token allow eager execution and +synchronisation of asynchronous operations. For example: + + auto promise = async_read( + stream, boost::asio::buffer(my_buffer), + boost::asio::experimental::use_promise); + + ... do other stuff while the read is going on ... + + promise.async_wait( // completion the operation + [](error_code ec, std::size_t bytes_read) + { + ... + }); + +Promises can be safely disregarded if the result is no longer required. +Different operations can be combined to either wait for all to complete or for +one to complete (and cancel the rest). For example, to wait for one to +complete: + + auto timeout_promise = + timer.async_wait( + boost::asio::experimental::use_promise); + + auto read_promise = async_read( + stream, boost::asio::buffer(my_buffer), + boost::asio::experimental::use_promise); + + auto promise = + boost::asio::experimental::promise<>::race( + timeout_promise, read_promise); + + promise.async_wait( + [](std::variant> v) + { + if (v.index() == 0) {} //timed out + else if (v.index() == 1) // completed in time + }); + +or to wait for all to complete: + + auto write_promise = async_write( + stream, boost::asio::buffer(my_write_buffer), + boost::asio::experimental::use_promise); + + auto read_promise = async_read( + stream, boost::asio::buffer(my_buffer), + boost::asio::experimental::use_promise); + + auto promise = + boost::asio::experimental::promise<>::all( + write_promise, read_promise); + + promise.async_wait( + [](std::tuple write_result, + std::tuple read_result) + { + // ... + }); + +[heading See Also] + +[link boost_asio.reference.experimental__promise_lt__void_lp_Ts_ellipsis__rp__comma__Executor__gt_ promise], +[link boost_asio.reference.experimental__use_promise use_promise]. + +[endsect] diff --git a/doc/overview/timers.qbk b/doc/overview/timers.qbk index 7dd304d6..fbd62594 100644 --- a/doc/overview/timers.qbk +++ b/doc/overview/timers.qbk @@ -16,8 +16,8 @@ relative time one may write: io_context i; ... - deadline_timer t(i); - t.expires_from_now(boost::posix_time::seconds(5)); + steady_timer t(i); + t.expires_after(chrono::seconds(5)); t.wait(); More commonly, a program will perform an asynchronous wait operation on a @@ -27,26 +27,27 @@ timer: ... io_context i; ... - deadline_timer t(i); - t.expires_from_now(boost::posix_time::milliseconds(400)); + steady_timer t(i); + t.expires_after(chrono::milliseconds(400)); t.async_wait(handler); ... i.run(); -The deadline associated with a timer may also be obtained as a relative time: +The deadline associated with a timer may also be obtained as an absolute time: - boost::posix_time::time_duration time_until_expiry - = t.expires_from_now(); + steady_timer::time_point time_of_expiry = t.expiry(); -or as an absolute time to allow composition of timers: +which allows composition of timers: - deadline_timer t2(i); - t2.expires_at(t.expires_at() + boost::posix_time::seconds(30)); + steady_timer t2(i); + t2.expires_at(t.expiry() + chrono::seconds(30)); [heading See Also] -[link boost_asio.reference.basic_deadline_timer basic_deadline_timer], -[link boost_asio.reference.deadline_timer deadline_timer], +[link boost_asio.reference.basic_waitable_timer basic_waitable_timer], +[link boost_asio.reference.steady_timer steady_timer], +[link boost_asio.reference.system_timer system_timer], +[link boost_asio.reference.high_resolution_timer high_resolution_timer], [link boost_asio.tutorial.tuttimer1 timer tutorials]. [endsect] diff --git a/doc/overview/token_adapters.qbk b/doc/overview/token_adapters.qbk new file mode 100644 index 00000000..49d1273c --- /dev/null +++ b/doc/overview/token_adapters.qbk @@ -0,0 +1,216 @@ +[/ + / Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:token_adapters Completion Token Adapters] + +A ['completion token adapter] is a utility that can be generically applied to a +[link boost_asio.overview.model.completion_tokens completion token], to produce a new +completion token with modified behaviour. Common uses of completion token +adapters include: + +* Automatically wrapping the completion handler to add [link + boost_asio.overview.model.associators associated characteristics]. + +* Transforming the completion signature and arguments passed to the completion + handler. + +Boost.Asio includes a number of completion token adapters as described below. + +[heading bind_executor, bind_allocator, and bind_cancellation_slot] + +The [link boost_asio.reference.bind_executor `bind_executor`] function adapts a +completion token to imbue the completion handler with an [link +boost_asio.overview.model.executors associated executor]. + +This example shows the `bind_executor` adapter applied to a lambda, to specify +that the handler should execute in the specified strand. The arguments to the +completion handler are passed through as-is. + + my_socket.async_read_some(my_buffer, + boost::asio::bind_executor(my_strand, + [](boost::system::error_code error, std::size_t bytes_transferred) + { + // ... + })); + +When applied to completion tokens that cause the initiating function to produce +a result, such as [link boost_asio.reference.use_awaitable `use_awaitable`], the +result is returned unmodified. + + boost::asio::awaitable my_coroutine() + { + // ... + std::size_t bytes_transferred = + co_await my_socket.async_read_some(my_buffer, + boost::asio::bind_executor(my_strand, boost::asio::use_awaitable)); + // ... + } + +The [link boost_asio.reference.bind_allocator `bind_allocator`] and [link +boost_asio.reference.bind_cancellation_slot `bind_cancellation_slot`] adapters work +similarly, to imbue the completion handler with an [link +boost_asio.overview.model.allocators associated allocator] or [link +boost_asio.overview.model.cancellation associated cancellation slot] respectively. + +[heading redirect_error] + +The [link boost_asio.reference.redirect_error `redirect_error`] function adapts a +completion token to capture the `error_code` produced by an operation into a +specified variable. In doing so, it modifies the completion signature to remove +the initial `error_code` parameter. + +This example shows the `redirect_error` adapter applied to a lambda, to specify +that the error should be captured into `my_error`. The `error_code` is no +longer passed to the completion handler, but the remaining arguments are passed +through as-is. + + boost::system::error_code my_error; // N.B. must be valid until operation completes + // ... + my_socket.async_read_some(my_buffer, + boost::asio::redirect_error( + [](std::size_t bytes_transferred) + { + // ... + }, my_error)); + +When applied to completion tokens that cause the initiating function to produce +a result, such as [link boost_asio.reference.use_awaitable `use_awaitable`], the +result is returned unmodified. However, if the operation fails, the `co_await` +expression will no longer throw an exception on resumption. + + boost::asio::awaitable my_coroutine() + { + // ... + boost::system::error_code my_error; + std::size_t bytes_transferred = + co_await my_socket.async_read_some(my_buffer, + boost::asio::redirect_error(boost::asio::use_awaitable, my_error)); + // ... + } + +[heading as_tuple] + +[note This is an experimental feature.] + +The [link boost_asio.reference.experimental__as_tuple `experimental::as_tuple`] +adapter can be used to specify that the completion handler arguments should be +combined into a single tuple argument. + +For example, the `as_tuple` adapter may be used in conjunction with [link +boost_asio.reference.use_awaitable `use_awaitable`] and structured bindings as +follows: + + auto [e, n] = + co_await my_socket.async_read_some(my_buffer, + boost::asio::experimental::as_tuple(boost::asio::use_awaitable)); + +This adapter may also be used as a default completion token: + + using default_token = boost::asio::experimental::as_tuple_t>; + using tcp_socket = default_token::as_default_on_t; + // ... + boost::asio::awaitable do_read(tcp_socket my_socket) + { + // ... + auto [e, n] = co_await my_socket.async_read_some(my_buffer); + // ... + } + +[heading as_single] + +[note This is an experimental feature.] + +The [link boost_asio.reference.experimental__as_single `experimental::as_single`] +adapter can be used to specify that the completion handler +arguments should be combined into a single argument. For completion signatures +with a single parameter, the argument is passed through as-is. For signatures +with two or more parameters, the arguments are combined into a tuple. + +For example, when applied to a timer wait operation, the single `error_code` +argument is passed directly to the completion handler: + + my_timer.async_wait( + boost::asio::experimental::as_single( + [](boost::system::error_code error) + { + // ... + })); + +When applied to a socket read operation, where the completion signature +specifies two parameters, the handler is passed the result as a tuple: + + my_socket.async_read_some(my_buffer, + boost::asio::experimental::as_single, + [](std::tuple result) + { + // ... + })); + +[heading append] + +[note This is an experimental feature.] + +The [link boost_asio.reference.experimental__append `experimental::append`] +completion token adapter can be used to pass additional completion handler +arguments at the end of the completion signature. + +For example: + + timer.async_wait( + boost::asio::experimental::append( + [](boost::system::error_code ec, int i) + { + // ... + }, + 42) + ); + + std::future f = timer.async_wait( + boost::asio::experimental::append( + boost::asio::use_future, + 42 + ) + ); + +[heading prepend] + +[note This is an experimental feature.] + +The [link boost_asio.reference.experimental__prepend `experimental::prepend`] +completion token adapter can be used to pass additional completion handler +arguments before the existing completion handler arguments. + +For example: + + timer.async_wait( + boost::asio::experimental::prepend( + [](int i, boost::system::error_code ec) + { + // ... + }, + 42) + ); + + std::future> f = timer.async_wait( + boost::asio::experimental::prepend( + boost::asio::use_future, + 42 + ) + ); + +[heading See Also] + +[link boost_asio.reference.bind_executor bind_executor], +[link boost_asio.reference.bind_allocator bind_allocator], +[link boost_asio.reference.bind_cancellation_slot bind_cancellation_slot], +[link boost_asio.reference.redirect_error redirect_error], +[link boost_asio.reference.experimental__as_tuple experimental::as_tuple], +[link boost_asio.reference.experimental__as_single experimental::as_single], +[link boost_asio.reference.experimental__append experimental::append], +[link boost_asio.reference.experimental__prepend experimental::prepend]. + +[endsect] diff --git a/doc/platform_macros.qbk b/doc/platform_macros.qbk index c115faed..24e8bfb6 100644 --- a/doc/platform_macros.qbk +++ b/doc/platform_macros.qbk @@ -30,13 +30,6 @@ with Boost.Asio's needs. ] [`BOOST_ASIO_DISABLE_ALIAS_TEMPLATES`] ] - [ - [`BOOST_ASIO_HAS_ALIGNED_NEW`] - [ - Support for operator new with alignment argument. - ] - [`BOOST_ASIO_DISABLE_ALIGNED_NEW`] - ] [ [`BOOST_ASIO_HAS_ALIGNOF`] [ @@ -82,7 +75,7 @@ with Boost.Asio's needs. [ [`BOOST_ASIO_HAS_BOOST_CONFIG`] [ - + Boost.Config library is available. ] [] ] @@ -198,6 +191,13 @@ with Boost.Asio's needs. ] [`BOOST_ASIO_DISABLE_DEV_POLL`] ] + [ + [`BOOST_ASIO_HAS_ENUM_CLASS`] + [ + Support enum classes on compilers known to allow them. + ] + [`BOOST_ASIO_DISABLE_ENUM_CLASS`] + ] [ [`BOOST_ASIO_HAS_EPOLL`] [ @@ -212,6 +212,13 @@ with Boost.Asio's needs. ] [`BOOST_ASIO_DISABLE_EVENTFD`] ] + [ + [`BOOST_ASIO_HAS_FILE`] + [ + Files. + ] + [`BOOST_ASIO_DISABLE_FILE`] + ] [ [`BOOST_ASIO_HAS_GETADDRINFO`] [ @@ -233,6 +240,13 @@ with Boost.Asio's needs. ] [`BOOST_ASIO_DISABLE_IOCP`] ] + [ + [`BOOST_ASIO_HAS_IO_URING_AS_DEFAULT`] + [ + Linux: io_uring is used instead of epoll. + ] + [] + ] [ [`BOOST_ASIO_HAS_KQUEUE`] [ @@ -268,6 +282,13 @@ with Boost.Asio's needs. ] [`BOOST_ASIO_DISABLE_NOEXCEPT`] ] + [ + [`BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE`] + [ + Support noexcept on function types on compilers known to allow it. + ] + [`BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE`] + ] [ [`BOOST_ASIO_HAS_NULLPTR`] [ @@ -275,6 +296,13 @@ with Boost.Asio's needs. ] [`BOOST_ASIO_DISABLE_NULLPTR`] ] + [ + [`BOOST_ASIO_HAS_PIPE`] + [ + Pipes. + ] + [`BOOST_ASIO_DISABLE_PIPE`] + ] [ [`BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR`] [ @@ -359,6 +387,13 @@ with Boost.Asio's needs. ] [`BOOST_ASIO_DISABLE_STD_ADDRESSOF`] ] + [ + [`BOOST_ASIO_HAS_STD_ALIGNED_ALLOC`] + [ + Standard library support for aligned allocation. + ] + [`BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC`] + ] [ [`BOOST_ASIO_HAS_STD_ALLOCATOR_ARG`] [ diff --git a/doc/reference.qbk b/doc/reference.qbk index 7518fd5c..538d4ee5 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -67468,7 +67468,7 @@ The [link boost_asio.reference.basic_writable_pipe `basic_writable_pipe`] class [indexterm1 boost_asio.indexterm.basic_yield_context..basic_yield_context] -A completion token that represents the currently executing coroutine. +A [link boost_asio.overview.model.completion_tokens completion token] that represents the currently executing coroutine. template< @@ -78857,7 +78857,7 @@ Submits a completion token or function object for execution. [indexterm1 boost_asio.indexterm.detached..detached] -A special value, similar to std::nothrow. +A [link boost_asio.overview.model.completion_tokens completion token] object used to specify that an asynchronous operation is detached. constexpr detached_t detached; @@ -78880,7 +78880,7 @@ See the documentation for [link boost_asio.reference.detached_t `detached_t`] fo [indexterm1 boost_asio.indexterm.detached_t..detached_t] -Class used to specify that an asynchronous operation is detached. +A [link boost_asio.overview.model.completion_tokens completion token] type used to specify that an asynchronous operation is detached. class detached_t @@ -91460,7 +91460,7 @@ Destructor. [indexterm1 boost_asio.indexterm.executor_work_guard..executor_work_guard] -An object of type `executor_work_guard` controls ownership of executor work within a scope. +An object of type `executor_work_guard` controls ownership of outstanding executor work within a scope. template< @@ -91805,7 +91805,7 @@ Constructor. [indexterm1 boost_asio.indexterm.experimental__as_single..experimental::as_single] -Create a completion token to specify that the completion handler arguments should be combined into a single argument. +Adapt a [link boost_asio.overview.model.completion_tokens completion token] to specify that the completion handler arguments should be combined into a single argument. template< @@ -91829,7 +91829,7 @@ Create a completion token to specify that the completion handler arguments shoul [indexterm1 boost_asio.indexterm.experimental__as_single_t..experimental::as_single_t] -Completion token type used to specify that the completion handler arguments should be combined into a single argument. +A [link boost_asio.overview.model.completion_tokens completion token] adapter used to specify that the completion handler arguments should be combined into a single argument. template< @@ -92185,7 +92185,7 @@ Convert the specified executor to the inner executor type, then use that to cons [indexterm1 boost_asio.indexterm.experimental__as_tuple..experimental::as_tuple] -Create a completion token to specify that the completion handler arguments should be combined into a single tuple argument. +Adapt a [link boost_asio.overview.model.completion_tokens completion token] to specify that the completion handler arguments should be combined into a single tuple argument. template< @@ -92209,7 +92209,7 @@ Create a completion token to specify that the completion handler arguments shoul [indexterm1 boost_asio.indexterm.experimental__as_tuple_t..experimental::as_tuple_t] -Completion token type used to specify that the completion handler arguments should be combined into a single tuple argument. +A [link boost_asio.overview.model.completion_tokens completion token] adapter used to specify that the completion handler arguments should be combined into a single tuple argument. template< @@ -93027,6 +93027,63 @@ A channel for messages. ] +The [link boost_asio.reference.experimental__basic_channel `experimental::basic_channel`] class template is used for sending messages between different parts of the same application. A ['message] is defined as a collection of arguments to be passed to a completion handler, and the set of messages supported by a channel is specified by its `Traits` and `Signatures...` template parameters. Messages may be sent and received using asynchronous or non-blocking synchronous operations. + +Unless customising the traits, applications will typically use the `experimental::channel` alias template. For example: + + void send_loop(int i, steady_timer& timer, + channel& ch) + { + if (i < 10) + { + timer.expires_after(chrono::seconds(1)); + timer.async_wait( + [i, &timer, &ch](error_code error) + { + if (!error) + { + ch.async_send(error_code(), i, + [i, &timer, &ch](error_code error) + { + if (!error) + { + send_loop(i + 1, timer, ch); + } + }); + } + }); + } + else + { + ch.close(); + } + } + + void receive_loop(channel& ch) + { + ch.async_receive( + [&ch](error_code error, int i) + { + if (!error) + { + std::cout << "Received " << i << "\n"; + receive_loop(ch); + } + }); + } + + + + + +[heading Thread Safety] + +['Distinct] ['objects:] Safe. + +['Shared] ['objects:] Unsafe. + +The [link boost_asio.reference.experimental__basic_channel `experimental::basic_channel`] class template is not thread-safe, and would typically be used for passing messages between application code that runs on the same thread or in the same strand. Consider using [link boost_asio.reference.experimental__basic_concurrent_channel `experimental::basic_concurrent_channel`], and its alias template `experimental::concurrent_channel`, to pass messages between code running in different threads. + [heading Requirements] ['Header: ][^boost/asio/experimental/basic_channel.hpp] @@ -93276,7 +93333,7 @@ Cancel all asynchronous operations waiting on the channel. void cancel(); -All outstanding send operations will complete with the error `boost::asio::experimental::error::channel_canceld`. Outstanding receive operations complete with the result as determined by the channel traits. +All outstanding send operations will complete with the error `boost::asio::experimental::error::channel_cancelled`. Outstanding receive operations complete with the result as determined by the channel traits. [endsect] @@ -93744,6 +93801,63 @@ The channel type when rebound to the specified executor. ] +The [link boost_asio.reference.experimental__basic_channel `experimental::basic_channel`] class template is used for sending messages between different parts of the same application. A ['message] is defined as a collection of arguments to be passed to a completion handler, and the set of messages supported by a channel is specified by its `Traits` and `Signatures...` template parameters. Messages may be sent and received using asynchronous or non-blocking synchronous operations. + +Unless customising the traits, applications will typically use the `experimental::channel` alias template. For example: + + void send_loop(int i, steady_timer& timer, + channel& ch) + { + if (i < 10) + { + timer.expires_after(chrono::seconds(1)); + timer.async_wait( + [i, &timer, &ch](error_code error) + { + if (!error) + { + ch.async_send(error_code(), i, + [i, &timer, &ch](error_code error) + { + if (!error) + { + send_loop(i + 1, timer, ch); + } + }); + } + }); + } + else + { + ch.close(); + } + } + + void receive_loop(channel& ch) + { + ch.async_receive( + [&ch](error_code error, int i) + { + if (!error) + { + std::cout << "Received " << i << "\n"; + receive_loop(ch); + } + }); + } + + + + + +[heading Thread Safety] + +['Distinct] ['objects:] Safe. + +['Shared] ['objects:] Unsafe. + +The [link boost_asio.reference.experimental__basic_channel `experimental::basic_channel`] class template is not thread-safe, and would typically be used for passing messages between application code that runs on the same thread or in the same strand. Consider using [link boost_asio.reference.experimental__basic_concurrent_channel `experimental::basic_concurrent_channel`], and its alias template `experimental::concurrent_channel`, to pass messages between code running in different threads. + [heading Requirements] @@ -93885,6 +93999,63 @@ A channel for messages. ] +The [link boost_asio.reference.experimental__basic_concurrent_channel `experimental::basic_concurrent_channel`] class template is used for sending messages between different parts of the same application. A ['message] is defined as a collection of arguments to be passed to a completion handler, and the set of messages supported by a channel is specified by its `Traits` and `Signatures...` template parameters. Messages may be sent and received using asynchronous or non-blocking synchronous operations. + +Unless customising the traits, applications will typically use the `experimental::concurrent_channel` alias template. For example: + + void send_loop(int i, steady_timer& timer, + concurrent_channel& ch) + { + if (i < 10) + { + timer.expires_after(chrono::seconds(1)); + timer.async_wait( + [i, &timer, &ch](error_code error) + { + if (!error) + { + ch.async_send(error_code(), i, + [i, &timer, &ch](error_code error) + { + if (!error) + { + send_loop(i + 1, timer, ch); + } + }); + } + }); + } + else + { + ch.close(); + } + } + + void receive_loop(concurent_channel& ch) + { + ch.async_receive( + [&ch](error_code error, int i) + { + if (!error) + { + std::cout << "Received " << i << "\n"; + receive_loop(ch); + } + }); + } + + + + + +[heading Thread Safety] + +['Distinct] ['objects:] Safe. + +['Shared] ['objects:] Safe. + +The [link boost_asio.reference.experimental__basic_concurrent_channel `experimental::basic_concurrent_channel`] class template is thread-safe, and would typically be used for passing messages between application code that run on different threads. Consider using [link boost_asio.reference.experimental__basic_channel `experimental::basic_channel`], and its alias template `experimental::channel`, to pass messages between code running in a single thread or on the same strand. + [heading Requirements] ['Header: ][^boost/asio/experimental/basic_concurrent_channel.hpp] @@ -94115,7 +94286,7 @@ Cancel all asynchronous operations waiting on the channel. void cancel(); -All outstanding send operations will complete with the error `boost::asio::experimental::error::channel_canceld`. Outstanding receive operations complete with the result as determined by the channel traits. +All outstanding send operations will complete with the error `boost::asio::experimental::error::channel_cancelled`. Outstanding receive operations complete with the result as determined by the channel traits. [endsect] @@ -94583,6 +94754,63 @@ The channel type when rebound to the specified executor. ] +The [link boost_asio.reference.experimental__basic_concurrent_channel `experimental::basic_concurrent_channel`] class template is used for sending messages between different parts of the same application. A ['message] is defined as a collection of arguments to be passed to a completion handler, and the set of messages supported by a channel is specified by its `Traits` and `Signatures...` template parameters. Messages may be sent and received using asynchronous or non-blocking synchronous operations. + +Unless customising the traits, applications will typically use the `experimental::concurrent_channel` alias template. For example: + + void send_loop(int i, steady_timer& timer, + concurrent_channel& ch) + { + if (i < 10) + { + timer.expires_after(chrono::seconds(1)); + timer.async_wait( + [i, &timer, &ch](error_code error) + { + if (!error) + { + ch.async_send(error_code(), i, + [i, &timer, &ch](error_code error) + { + if (!error) + { + send_loop(i + 1, timer, ch); + } + }); + } + }); + } + else + { + ch.close(); + } + } + + void receive_loop(concurent_channel& ch) + { + ch.async_receive( + [&ch](error_code error, int i) + { + if (!error) + { + std::cout << "Received " << i << "\n"; + receive_loop(ch); + } + }); + } + + + + + +[heading Thread Safety] + +['Distinct] ['objects:] Safe. + +['Shared] ['objects:] Safe. + +The [link boost_asio.reference.experimental__basic_concurrent_channel `experimental::basic_concurrent_channel`] class template is thread-safe, and would typically be used for passing messages between application code that run on different threads. Consider using [link boost_asio.reference.experimental__basic_channel `experimental::basic_channel`], and its alias template `experimental::channel`, to pass messages between code running in a single thread or on the same strand. + [heading Requirements] @@ -95657,7 +95885,7 @@ Whether or not the coroutine is noexcept. [indexterm1 boost_asio.indexterm.experimental__deferred..experimental::deferred] -A special value, similar to std::nothrow. +A [link boost_asio.overview.model.completion_tokens completion token] object used to specify that an asynchronous operation should return a function object to lazily launch the operation. constexpr deferred_t deferred; @@ -96160,7 +96388,7 @@ The [link boost_asio.reference.experimental__deferred_t `experimental::deferred_ - auto my_sender + auto my_deferred_op = my_socket.async_read_some(my_buffer, boost::asio::experimental::deferred); @@ -96402,7 +96630,7 @@ The [link boost_asio.reference.experimental__deferred_t `experimental::deferred_ - auto my_sender + auto my_deferred_op = my_socket.async_read_some(my_buffer, boost::asio::experimental::deferred); @@ -96869,7 +97097,7 @@ Launches the group and asynchronously waits for completion. [[cancellation_condition][A function object, called on completion of an operation within the group, that is used to determine whether to cancel the remaining operations. The function object is passed the arguments of the completed operation's handler. To trigger cancellation of the remaining operations, it must return a [link boost_asio.reference.cancellation_type `cancellation_type`] value other than `boost::asio::cancellation_type::none`.]] -[[token][A completion token whose signature is comprised of a `std::array` indicating the completion order of the operations, followed by all operations' completion handler arguments.]] +[[token][A [link boost_asio.overview.model.completion_tokens completion token] whose signature is comprised of a `std::array` indicating the completion order of the operations, followed by all operations' completion handler arguments.]] ] @@ -97517,7 +97745,7 @@ The primary template is not defined. [indexterm1 boost_asio.indexterm.experimental__use_coro..experimental::use_coro] -A completion token object that represents the currently executing resumable coroutine. +A [link boost_asio.overview.model.completion_tokens completion token] object that represents the currently executing resumable coroutine. constexpr use_coro_t use_coro; @@ -97540,7 +97768,7 @@ See the documentation for boost::asio::use\_coro\_t for a usage example. [indexterm1 boost_asio.indexterm.experimental__use_coro_t..experimental::use_coro_t] -A completion token that represents the currently executing resumable coroutine. +A [link boost_asio.overview.model.completion_tokens completion token] that represents the currently executing resumable coroutine. template< @@ -103370,41 +103598,13 @@ For example: -Some applications may need to prevent an [link boost_asio.reference.io_context `io_context`] object's `run()` call from returning when there is no more work to do. For example, the [link boost_asio.reference.io_context `io_context`] may be being run in a background thread that is launched prior to the application's asynchronous operations. The `run()` call may be kept running by creating an executor that tracks work against the [link boost_asio.reference.io_context `io_context`]: +Some applications may need to prevent an [link boost_asio.reference.io_context `io_context`] object's `run()` call from returning when there is no more work to do. For example, the [link boost_asio.reference.io_context `io_context`] may be being run in a background thread that is launched prior to the application's asynchronous operations. The `run()` call may be kept running by using the [link boost_asio.reference.make_work_guard `make_work_guard`] function to create an object of type boost::asio::executor\_work\_guard: boost::asio::io_context io_context; - auto work = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); - ... - - - - -If using C++03, which lacks automatic variable type deduction, you may compute the return type of the require call: - - - - boost::asio::io_context io_context; - typename boost::asio::require_result< - boost::asio::io_context::executor_type, - boost::asio::exeution::outstanding_work_t::tracked_t> - work = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); - ... - - - - -or store the result in the type-erasing executor wrapper, [link boost_asio.reference.any_io_executor `any_io_executor`]: - - - - boost::asio::io_context io_context; - boost::asio::any_io_executor work - = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); + boost::asio::executor_work_guard + = boost::asio::make_work_guard(io_context); ... @@ -103412,16 +103612,15 @@ or store the result in the type-erasing executor wrapper, [link boost_asio.refer To effect a shutdown, the application will then need to call the [link boost_asio.reference.io_context `io_context`] object's `stop()` member function. This will cause the [link boost_asio.reference.io_context `io_context`] `run()` call to return as soon as possible, abandoning unfinished operations and without permitting ready handlers to be dispatched. -Alternatively, if the application requires that all operations and handlers be allowed to finish normally, store the work-tracking executor in an [link boost_asio.reference.any_io_executor `any_io_executor`] object, so that it may be explicitly reset. +Alternatively, if the application requires that all operations and handlers be allowed to finish normally, the work object may be explicitly reset. boost::asio::io_context io_context; - boost::asio::any_io_executor work - = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); + boost::asio::executor_work_guard + = boost::asio::make_work_guard(io_context); ... - work = boost::asio::any_io_executor(); // Allow run() to exit. + work.reset(); // Allow run() to exit. @@ -107033,41 +107232,13 @@ For example: -Some applications may need to prevent an [link boost_asio.reference.io_context `io_context`] object's `run()` call from returning when there is no more work to do. For example, the [link boost_asio.reference.io_context `io_context`] may be being run in a background thread that is launched prior to the application's asynchronous operations. The `run()` call may be kept running by creating an executor that tracks work against the [link boost_asio.reference.io_context `io_context`]: +Some applications may need to prevent an [link boost_asio.reference.io_context `io_context`] object's `run()` call from returning when there is no more work to do. For example, the [link boost_asio.reference.io_context `io_context`] may be being run in a background thread that is launched prior to the application's asynchronous operations. The `run()` call may be kept running by using the [link boost_asio.reference.make_work_guard `make_work_guard`] function to create an object of type boost::asio::executor\_work\_guard: boost::asio::io_context io_context; - auto work = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); - ... - - - - -If using C++03, which lacks automatic variable type deduction, you may compute the return type of the require call: - - - - boost::asio::io_context io_context; - typename boost::asio::require_result< - boost::asio::io_context::executor_type, - boost::asio::exeution::outstanding_work_t::tracked_t> - work = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); - ... - - - - -or store the result in the type-erasing executor wrapper, [link boost_asio.reference.any_io_executor `any_io_executor`]: - - - - boost::asio::io_context io_context; - boost::asio::any_io_executor work - = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); + boost::asio::executor_work_guard + = boost::asio::make_work_guard(io_context); ... @@ -107075,16 +107246,15 @@ or store the result in the type-erasing executor wrapper, [link boost_asio.refer To effect a shutdown, the application will then need to call the [link boost_asio.reference.io_context `io_context`] object's `stop()` member function. This will cause the [link boost_asio.reference.io_context `io_context`] `run()` call to return as soon as possible, abandoning unfinished operations and without permitting ready handlers to be dispatched. -Alternatively, if the application requires that all operations and handlers be allowed to finish normally, store the work-tracking executor in an [link boost_asio.reference.any_io_executor `any_io_executor`] object, so that it may be explicitly reset. +Alternatively, if the application requires that all operations and handlers be allowed to finish normally, the work object may be explicitly reset. boost::asio::io_context io_context; - boost::asio::any_io_executor work - = boost::asio::require(io_context.get_executor(), - boost::asio::execution::outstanding_work.tracked); + boost::asio::executor_work_guard + = boost::asio::make_work_guard(io_context); ... - work = boost::asio::any_io_executor(); // Allow run() to exit. + work.reset(); // Allow run() to exit. @@ -108216,6 +108386,13 @@ Default constructor. address_v4(); +Initialises the `address_v4` object such that: +* `to_bytes()` yields `{0, 0, 0, 0}`; and + +* `to_uint() == 0`. + + + [endsect] @@ -108231,6 +108408,20 @@ Construct an address from raw bytes. const bytes_type & bytes); +Initialises the `address_v4` object such that `to_bytes() == bytes`. + + +[heading Exceptions] + + +[variablelist + +[[out_of_range][Thrown if any element in `bytes` is not in the range `0 - 0xFF`. Note that no range checking is required for platforms where `std::numeric_limits::max()` is `0xFF`. ]] + +] + + + [endsect] @@ -108246,6 +108437,8 @@ Construct an address from an unsigned integer in host byte order. uint_type addr); +Initialises the `address_v4` object such that `to_uint() == addr`. + [endsect] @@ -108277,6 +108470,15 @@ Obtain an address object that represents any address. static address_v4 any(); +This functions returns an address that represents the "any" address `0.0.0.0`. + + +[heading Return Value] + +A default-constructed `address_v4` object. + + + [endsect] @@ -108309,6 +108511,15 @@ Obtain an address object that represents the broadcast address. static address_v4 broadcast(); +This function returns an address that represents the broadcast address `255.255.255.255`. + + +[heading Return Value] + +`address_v4(0xFFFFFFFF)`. + + + [endsect] @@ -108499,6 +108710,15 @@ Determine whether the address is a loopback address. bool is_loopback() const; +This function tests whether the address is in the address block `127.0.0.0/8`, which corresponds to the address range `127.0.0.0 - 127.255.255.255`. + + +[heading Return Value] + +`(to_uint() & 0xFF000000) == 0x7F000000`. + + + [endsect] @@ -108513,6 +108733,15 @@ Determine whether the address is a multicast address. bool is_multicast() const; +This function tests whether the address is in the multicast address block `224.0.0.0/4`, which corresponds to the address range `224.0.0.0 - 239.255.255.255`. + + +[heading Return Value] + +`(to_uint() & 0xF0000000) == 0xE0000000`. + + + [endsect] @@ -108527,6 +108756,15 @@ Determine whether the address is unspecified. bool is_unspecified() const; +This function tests whether the address is the unspecified address `0.0.0.0`. + + +[heading Return Value] + +`to_uint() == 0`. + + + [endsect] @@ -108541,6 +108779,15 @@ Obtain an address object that represents the loopback address. static address_v4 loopback(); +This function returns an address that represents the well-known loopback address `127.0.0.1`. + + +[heading Return Value] + +`address_v4(0x7F000001)`. + + + [endsect] @@ -108847,6 +109094,15 @@ Compare addresses for ordering. const address_v4 & a2); +Compares two addresses in host byte order. + + +[heading Return Value] + +`a1.to_uint() < a2.to_uint()`. + + + [heading Requirements] ['Header: ][^boost/asio/ip/address_v4.hpp] @@ -108977,6 +109233,15 @@ Compare addresses for ordering. const address_v4 & a2); +Compares two addresses in host byte order. + + +[heading Return Value] + +`a1.to_uint() <= a2.to_uint()`. + + + [heading Requirements] ['Header: ][^boost/asio/ip/address_v4.hpp] @@ -109036,6 +109301,15 @@ Compare addresses for ordering. const address_v4 & a2); +Compares two addresses in host byte order. + + +[heading Return Value] + +`a1.to_uint() > a2.to_uint()`. + + + [heading Requirements] ['Header: ][^boost/asio/ip/address_v4.hpp] @@ -109058,6 +109332,15 @@ Compare addresses for ordering. const address_v4 & a2); +Compares two addresses in host byte order. + + +[heading Return Value] + +`a1.to_uint() >= a2.to_uint()`. + + + [heading Requirements] ['Header: ][^boost/asio/ip/address_v4.hpp] @@ -109495,6 +109778,13 @@ Default constructor. address_v6(); +Initialises the `address_v6` object such that: +* `to_bytes()` yields `{0, 0, ..., 0}`; and + +* `scope_id() == 0`. + + + [endsect] @@ -109511,6 +109801,23 @@ Construct an address from raw bytes and scope ID. scope_id_type scope_id = 0); +Initialises the `address_v6` object such that: +* `to_bytes() == bytes`; and + +* `this->scope_id() == scope_id`. + + +[heading Exceptions] + + +[variablelist + +[[out_of_range][Thrown if any element in `bytes` is not in the range `0 - 0xFF`. Note that no range checking is required for platforms where `std::numeric_limits::max()` is `0xFF`. ]] + +] + + + [endsect] @@ -109542,6 +109849,15 @@ Obtain an address object that represents any address. static address_v6 any(); +This functions returns an address that represents the "any" address `::`. + + +[heading Return Value] + +A default-constructed `address_v6` object. + + + [endsect] @@ -109686,6 +110002,8 @@ Determine whether the address is a loopback address. bool is_loopback() const; +This function tests whether the address is the loopback address `::1`. + [endsect] @@ -109798,6 +110116,8 @@ Determine whether the address is unspecified. bool is_unspecified() const; +This function tests whether the address is the loopback address `::`. + [endsect] @@ -109840,6 +110160,8 @@ Obtain an address object that represents the loopback address. static address_v6 loopback(); +This function returns an address that represents the well-known loopback address `::1`. + [endsect] @@ -110337,7 +110659,19 @@ The scope ID of the address. scope_id_type id); -Modifies the scope ID associated with the IPv6 address. +Modifies the scope ID associated with the IPv6 address. + + +[heading Parameters] + + +[variablelist + +[[id][The new scope ID. ]] + +] + + [endsect] @@ -128024,6 +128358,23 @@ Create a [link boost_asio.reference.strand `strand`] object for an executor. +[heading Parameters] + + +[variablelist + +[[ex][An executor.]] + +] + + +[heading Return Value] + +A strand constructed with the specified executor. + + + + [endsect] @@ -128042,6 +128393,23 @@ Create a [link boost_asio.reference.strand `strand`] object for an execution con +[heading Parameters] + + +[variablelist + +[[ctx][An execution context, from which an executor will be obtained.]] + +] + + +[heading Return Value] + +A strand constructed with the execution context's executor, obtained by performing `ctx.get_executor()`. + + + + [endsect] @@ -128118,6 +128486,23 @@ Create an [link boost_asio.reference.executor_work_guard `executor_work_guard`] +[heading Parameters] + + +[variablelist + +[[ex][An executor.]] + +] + + +[heading Return Value] + +A work guard constructed with the specified executor. + + + + [endsect] @@ -128136,6 +128521,23 @@ Create an [link boost_asio.reference.executor_work_guard `executor_work_guard`] +[heading Parameters] + + +[variablelist + +[[ctx][An execution context, from which an executor will be obtained.]] + +] + + +[heading Return Value] + +A work guard constructed with the execution context's executor, obtained by performing `ctx.get_executor()`. + + + + [endsect] @@ -128156,6 +128558,23 @@ Create an [link boost_asio.reference.executor_work_guard `executor_work_guard`] +[heading Parameters] + + +[variablelist + +[[t][An arbitrary object, such as a completion handler, for which the associated executor will be obtained.]] + +] + + +[heading Return Value] + +A work guard constructed with the associated executor of the object `t`, which is obtained as if by calling `get_associated_executor(t)`. + + + + [endsect] @@ -128176,6 +128595,25 @@ Create an [link boost_asio.reference.executor_work_guard `executor_work_guard`] +[heading Parameters] + + +[variablelist + +[[t][An arbitrary object, such as a completion handler, for which the associated executor will be obtained.]] + +[[ex][An executor to be used as the candidate object when determining the associated executor.]] + +] + + +[heading Return Value] + +A work guard constructed with the associated executor of the object `t`, which is obtained as if by calling `get_associated_executor(t, ex)`. + + + + [endsect] @@ -128199,6 +128637,25 @@ Create an [link boost_asio.reference.executor_work_guard `executor_work_guard`] +[heading Parameters] + + +[variablelist + +[[t][An arbitrary object, such as a completion handler, for which the associated executor will be obtained.]] + +[[ctx][An execution context, from which an executor is obtained to use as the candidate object for determining the associated executor.]] + +] + + +[heading Return Value] + +A work guard constructed with the associated executor of the object `t`, which is obtained as if by calling `get_associated_executor(t, ctx.get_executor())`. + + + + [endsect] @@ -140169,7 +140626,7 @@ The uses a simple strategy where a limited number of small memory blocks are ca [indexterm1 boost_asio.indexterm.redirect_error..redirect_error] -Create a completion token to capture error\_code values to a variable. +Adapt a [link boost_asio.overview.model.completion_tokens completion token] to capture error\_code values to a variable. template< @@ -140194,7 +140651,7 @@ Create a completion token to capture error\_code values to a variable. [indexterm1 boost_asio.indexterm.redirect_error_t..redirect_error_t] -Completion token type used to specify that an error produced by an asynchronous operation is captured to an error\_code variable. +A [link boost_asio.overview.model.completion_tokens completion token] adapter used to specify that an error produced by an asynchronous operation is captured to an error\_code variable. template< @@ -152227,7 +152684,7 @@ Returns an awaitable object that may be used to reset the cancellation state of constexpr unspecified reset_cancellation_state(); -Let `P` be the cancellation slot associated with the current coroutine's `co\_spawn` completion handler. Assigns a new [link boost_asio.reference.cancellation_state `cancellation_state`] object `S`, constructed as `S(P)`, into the current coroutine's cancellation state object. +Let `P` be the cancellation slot associated with the current coroutine's [link boost_asio.reference.co_spawn `co_spawn`] completion handler. Assigns a new [link boost_asio.reference.cancellation_state `cancellation_state`] object `S`, constructed as `S(P)`, into the current coroutine's cancellation state object. [heading Example] @@ -152268,7 +152725,7 @@ Returns an awaitable object that may be used to reset the cancellation state of Filter && filter); -Let `P` be the cancellation slot associated with the current coroutine's `co\_spawn` completion handler. Assigns a new [link boost_asio.reference.cancellation_state `cancellation_state`] object `S`, constructed as `S(P, std::forward(filter))`, into the current coroutine's cancellation state object. +Let `P` be the cancellation slot associated with the current coroutine's [link boost_asio.reference.co_spawn `co_spawn`] completion handler. Assigns a new [link boost_asio.reference.cancellation_state `cancellation_state`] object `S`, constructed as `S(P, std::forward(filter))`, into the current coroutine's cancellation state object. [heading Example] @@ -152312,7 +152769,7 @@ Returns an awaitable object that may be used to reset the cancellation state of OutFilter && out_filter); -Let `P` be the cancellation slot associated with the current coroutine's `co\_spawn` completion handler. Assigns a new [link boost_asio.reference.cancellation_state `cancellation_state`] object `S`, constructed as `S(P, std::forward(in_filter), std::forward(out_filter))`, into the current coroutine's cancellation state object. +Let `P` be the cancellation slot associated with the current coroutine's [link boost_asio.reference.co_spawn `co_spawn`] completion handler. Assigns a new [link boost_asio.reference.cancellation_state `cancellation_state`] object `S`, constructed as `S(P, std::forward(in_filter), std::forward(out_filter))`, into the current coroutine's cancellation state object. [heading Example] @@ -155431,7 +155888,7 @@ Reading until a buffer is full or contains exactly 64 bytes: [indexterm1 boost_asio.indexterm.use_awaitable..use_awaitable] -A completion token object that represents the currently executing coroutine. +A [link boost_asio.overview.model.completion_tokens completion token] object that represents the currently executing coroutine. constexpr use_awaitable_t use_awaitable; @@ -155454,7 +155911,7 @@ See the documentation for [link boost_asio.reference.use_awaitable_t `use_awaita [indexterm1 boost_asio.indexterm.use_awaitable_t..use_awaitable_t] -A completion token that represents the currently executing coroutine. +A [link boost_asio.overview.model.completion_tokens completion token] that represents the currently executing coroutine. template< @@ -155722,7 +156179,7 @@ Construct the adapted executor from the inner executor type. [indexterm1 boost_asio.indexterm.use_future..use_future] -A completion token object that causes an asynchronous operation to return a future. +A [link boost_asio.overview.model.completion_tokens completion token] object that causes an asynchronous operation to return a future. constexpr use_future_t use_future; @@ -155745,7 +156202,7 @@ See the documentation for [link boost_asio.reference.use_future_t `use_future_t` [indexterm1 boost_asio.indexterm.use_future_t..use_future_t] -A completion token type that causes an asynchronous operation to return a future. +A [link boost_asio.overview.model.completion_tokens completion token] type that causes an asynchronous operation to return a future. template< @@ -164411,7 +164868,7 @@ The number of bytes written. If an error occurs, returns the total number of byt [indexterm1 boost_asio.indexterm.yield_context..yield_context] -Context object that represents the currently executing coroutine. +A [link boost_asio.overview.model.completion_tokens completion token] object that represents the currently executing coroutine. typedef basic_yield_context< unspecified > yield_context; diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 21c52c43..d319c4b2 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -17,13 +17,13 @@ The tutorial programs in this first section introduce the fundamental concepts r * [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously] -* [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler] +* [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler] -* [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler] +* [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler] -* [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs] +* [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs] @@ -94,7 +94,8 @@ All programs that use asio need to have at least one I/O execution context, such -Next we declare an object of type boost::asio::steady\_timer. The core asio classes that provide I/O functionality (or as in this case timer functionality) always take a reference to an io\_context as their first constructor argument. The second argument to the constructor sets the timer to expire 5 seconds from now. +Next we declare an object of type boost::asio::steady\_timer. The core asio classes that provide I/O functionality (or as in this case timer functionality) always take an executor, or a reference to an execution context (such as +[link boost_asio.reference.io_context io_context]), as their first constructor argument. The second argument to the constructor sets the timer to expire 5 seconds from now. @@ -166,7 +167,7 @@ Return to [link boost_asio.tutorial.tuttimer1 Timer.1 - Using a timer synchronou [section:tuttimer2 Timer.2 - Using a timer asynchronously] -This tutorial program demonstrates how to use asio's asynchronous callback functionality by modifying the program from tutorial Timer.1 to perform an asynchronous wait on the timer. +This tutorial program demonstrates how to use asio's asynchronous functionality by modifying the program from tutorial Timer.1 to perform an asynchronous wait on the timer. @@ -178,7 +179,7 @@ This tutorial program demonstrates how to use asio's asynchronous callback funct -Using asio's asynchronous functionality means having a callback function that will be called when an asynchronous operation completes. In this program we define a function called `print` to be called when the asynchronous wait finishes. +Using asio's asynchronous functionality means supplying a [link boost_asio.overview.model.completion_tokens completion token], which determines how the result will be delivered to a [*completion handler] when an [link boost_asio.overview.model.async_ops asynchronous operation] completes. In this program we define a function called `print` to be called when the asynchronous wait finishes. @@ -195,7 +196,7 @@ Using asio's asynchronous functionality means having a callback function that wi -Next, instead of doing a blocking wait as in tutorial Timer.1, we call the [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function to perform an asynchronous wait. When calling this function we pass the `print` callback handler that was defined above. +Next, instead of doing a blocking wait as in tutorial Timer.1, we call the [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function to perform an asynchronous wait. When calling this function we pass the `print` function that was defined above. ``''''''`` t.async_wait(&print); @@ -204,9 +205,9 @@ Next, instead of doing a blocking wait as in tutorial Timer.1, we call the [link Finally, we must call the [link boost_asio.reference.io_context.run io_context::run()] member function on the io\_context object. -The asio library provides a guarantee that callback handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Therefore unless the [link boost_asio.reference.io_context.run io_context::run()] function is called the callback for the asynchronous wait completion will never be invoked. +The asio library provides a guarantee that completion handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Therefore unless the [link boost_asio.reference.io_context.run io_context::run()] function is called the completion handler for the asynchronous wait completion will never be invoked. -The [link boost_asio.reference.io_context.run io_context::run()] function will also continue to run while there is still "work" to do. In this example, the work is the asynchronous wait on the timer, so the call will not return until the timer has expired and the callback has completed. +The [link boost_asio.reference.io_context.run io_context::run()] function will also continue to run while there is still "work" to do. In this example, the work is the asynchronous wait on the timer, so the call will not return until the timer has expired and the completion handler has returned. It is important to remember to give the io\_context some work to do before calling [link boost_asio.reference.io_context.run io_context::run()]. For example, if we had omitted the above call to [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()], the io\_context would not have had any work to do, and consequently [link boost_asio.reference.io_context.run io_context::run()] would have returned immediately. @@ -224,7 +225,7 @@ Return to the [link boost_asio.tutorial tutorial index] Previous: [link boost_asio.tutorial.tuttimer1 Timer.1 - Using a timer synchronously] -Next: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler] +Next: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler] @@ -267,7 +268,7 @@ Return to [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchrono [endsect] -[section:tuttimer3 Timer.3 - Binding arguments to a handler] +[section:tuttimer3 Timer.3 - Binding arguments to a completion handler] In this tutorial we will modify the program from tutorial Timer.2 so that the timer fires once a second. This will show how to pass additional parameters to your handler function. @@ -282,15 +283,18 @@ In this tutorial we will modify the program from tutorial Timer.2 so that the ti -To implement a repeating timer using asio you need to change the timer's expiry time in your callback function, and to then start a new asynchronous wait. Obviously this means that the callback function will need to be able to access the timer object. To this end we add two new parameters to the `print` function: +To implement a repeating timer using asio you need to change the timer's expiry time in your completion handler, and to then start a new asynchronous wait. Obviously this means that the completion handler will need to be able to access the timer object. To this end we add two new parameters to the `print` function: -* A pointer to a timer object. +* a pointer to a timer object; and -* A counter so that we can stop the program when the timer fires for the sixth time. +* a counter so that we can stop the program when the timer fires for the sixth time +at the end of the parameter list. + + ``''''''``void print(const boost::system::error_code& /*e*/, ``''''''`` boost::asio::steady_timer* t, int* count) @@ -316,11 +320,11 @@ Next we move the expiry time for the timer along by one second from the previous -Then we start a new asynchronous wait on the timer. As you can see, the boost::bind() function is used to associate the extra parameters with your callback handler. The [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function expects a handler function (or function object) with the signature `void(const boost::system::error_code&)`. Binding the additional parameters converts your `print` function into a function object that matches the signature correctly. +Then we start a new asynchronous wait on the timer. As you can see, the boost::bind() function is used to associate the extra parameters with your completion handler. The [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function expects a handler function (or function object) with the signature `void(const boost::system::error_code&)`. Binding the additional parameters converts your `print` function into a function object that matches the signature correctly. See the [@http://www.boost.org/libs/bind/bind.html Boost.Bind documentation] for more information on how to use boost::bind(). -In this example, the boost::asio::placeholders::error argument to boost::bind() is a named placeholder for the error object passed to the handler. When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In tutorial Timer.4 you will see that this placeholder may be elided if the parameter is not needed by the callback handler. +In this example, the boost::asio::placeholders::error argument to boost::bind() is a named placeholder for the error object passed to the handler. When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In tutorial Timer.4 you will see that this placeholder may be elided if the parameter is not needed by the completion handler. ``''''''`` t->async_wait(boost::bind(print, @@ -370,7 +374,7 @@ Return to the [link boost_asio.tutorial tutorial index] Previous: [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously] -Next: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler] +Next: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler] @@ -421,15 +425,15 @@ Next: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a ``''''''`` return 0; ``''''''``} -Return to [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler] +Return to [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler] [endsect] [endsect] -[section:tuttimer4 Timer.4 - Using a member function as a handler] +[section:tuttimer4 Timer.4 - Using a member function as a completion handler] -In this tutorial we will see how to use a class member function as a callback handler. The program should execute identically to the tutorial program from tutorial Timer.3. +In this tutorial we will see how to use a class member function as a completion handler. The program should execute identically to the tutorial program from tutorial Timer.3. @@ -442,7 +446,7 @@ In this tutorial we will see how to use a class member function as a callback ha -Instead of defining a free function `print` as the callback handler, as we did in the earlier tutorial programs, we now define a class called `printer`. +Instead of defining a free function `print` as the completion handler, as we did in the earlier tutorial programs, we now define a class called `printer`. @@ -462,7 +466,7 @@ The constructor of this class will take a reference to the io\_context object an -The boost::bind() function works just as well with class member functions as with free functions. Since all non-static class member functions have an implicit `this` parameter, we need to bind `this` to the function. As in tutorial Timer.3, boost::bind() converts our callback handler (now a member function) into a function object that can be invoked as though it has the signature `void(const boost::system::error_code&)`. +The boost::bind() function works just as well with class member functions as with free functions. Since all non-static class member functions have an implicit `this` parameter, we need to bind `this` to the function. As in tutorial Timer.3, boost::bind() converts our completion handler (now a member function) into a function object that can be invoked as though it has the signature `void(const boost::system::error_code&)`. You will note that the boost::asio::placeholders::error placeholder is not specified here, as the `print` member function does not accept an error object as a parameter. @@ -525,9 +529,9 @@ See the [link boost_asio.tutorial.tuttimer4.src full source listing] Return to the [link boost_asio.tutorial tutorial index] -Previous: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler] +Previous: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler] -Next: [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs] +Next: [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs] @@ -591,18 +595,18 @@ Next: [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in mu ``''''''`` return 0; ``''''''``} -Return to [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler] +Return to [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler] [endsect] [endsect] -[section:tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs] +[section:tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs] This tutorial demonstrates the use of the -[link boost_asio.reference.strand strand] class template to synchronise callback handlers in a multithreaded program. +[link boost_asio.reference.strand strand] class template to synchronise completion handlers in a multithreaded program. -The previous four tutorials avoided the issue of handler synchronisation by calling the [link boost_asio.reference.io_context.run io_context::run()] function from one thread only. As you already know, the asio library provides a guarantee that callback handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Consequently, calling [link boost_asio.reference.io_context.run io_context::run()] from only one thread ensures that callback handlers cannot run concurrently. +The previous four tutorials avoided the issue of handler synchronisation by calling the [link boost_asio.reference.io_context.run io_context::run()] function from one thread only. As you already know, the asio library provides a guarantee that completion handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Consequently, calling [link boost_asio.reference.io_context.run io_context::run()] from only one thread ensures that completion handlers cannot run concurrently. The single threaded approach is usually the best place to start when developing applications using asio. The downside is the limitations it places on programs, particularly servers, including: @@ -655,7 +659,7 @@ The -When initiating the asynchronous operations, each callback handler is "bound" to an boost::asio::strand object. The boost::asio::bind\_executor() function returns a new handler that automatically dispatches its contained handler through the +When initiating the asynchronous operations, each completion handler is "bound" to an boost::asio::strand object. The boost::asio::bind\_executor() function returns a new handler that automatically dispatches its contained handler through the [link boost_asio.reference.strand strand] object. By binding the handlers to the same [link boost_asio.reference.strand strand], we are ensuring that they cannot execute concurrently. @@ -738,7 +742,7 @@ See the [link boost_asio.tutorial.tuttimer5.src full source listing] Return to the [link boost_asio.tutorial tutorial index] -Previous: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler] +Previous: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler] @@ -829,7 +833,7 @@ Previous: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function ``''''''`` return 0; ``''''''``} -Return to [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs] +Return to [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs] [endsect] diff --git a/doc/tutorial.xsl b/doc/tutorial.xsl index 24b5877a..68bcb012 100644 --- a/doc/tutorial.xsl +++ b/doc/tutorial.xsl @@ -340,6 +340,16 @@ + + [link boost_asio.overview.model.async_ops + + ] + + + [link boost_asio.overview.model.completion_tokens + + ] + [link boost_asio.tutorial. diff --git a/doc/using.qbk b/doc/using.qbk index 09ba02e2..aaffe919 100644 --- a/doc/using.qbk +++ b/doc/using.qbk @@ -424,9 +424,4 @@ A mailing list specifically for Boost.Asio may be found on access is provided via [@http://dir.gmane.org/gmane.comp.lib.boost.asio.user Gmane]. -[heading Wiki] - -Users are encouraged to share examples, tips and FAQs on the Boost.Asio wiki, -which is located at [@http://think-async.com/Asio/]. - [endsect] diff --git a/example/cpp03/tutorial/timer_dox.txt b/example/cpp03/tutorial/timer_dox.txt index 56dd30a4..fc9128c0 100644 --- a/example/cpp03/tutorial/timer_dox.txt +++ b/example/cpp03/tutorial/timer_dox.txt @@ -30,8 +30,9 @@ boost::asio::io_context first thing in the main function. Next we declare an object of type boost::asio::steady_timer. The core asio classes that provide I/O functionality (or as in this case timer functionality) always -take a reference to an io_context as their first constructor argument. The -second argument to the constructor sets the timer to expire 5 seconds from now. +take an executor, or a reference to an execution context (such as +boost::asio::io_context), as their first constructor argument. The second argument to +the constructor sets the timer to expire 5 seconds from now. \until boost::asio::steady_timer @@ -66,41 +67,42 @@ Return to \ref tuttimer1 /** \page tuttimer2 Timer.2 - Using a timer asynchronously -This tutorial program demonstrates how to use asio's asynchronous callback -functionality by modifying the program from tutorial Timer.1 to perform an -asynchronous wait on the timer. +This tutorial program demonstrates how to use asio's asynchronous functionality +by modifying the program from tutorial Timer.1 to perform an asynchronous wait +on the timer. \dontinclude timer2/timer.cpp \skip #include \until asio.hpp -Using asio's asynchronous functionality means having a callback -function that will be called when an asynchronous operation completes. In this -program we define a function called print to be called when the -asynchronous wait finishes. +Using asio's asynchronous functionality means supplying a @ref completion_token, +which determines how the result will be delivered to a completion +handler when an @ref asynchronous_operation completes. In this program we +define a function called print to be called when the asynchronous wait +finishes. \until boost::asio::steady_timer Next, instead of doing a blocking wait as in tutorial Timer.1, we call the boost::asio::steady_timer::async_wait() function to perform an asynchronous wait. When calling this function we pass the print -callback handler that was defined above. +function that was defined above. \skipline async_wait Finally, we must call the boost::asio::io_context::run() member function on the io_context object. -The asio library provides a guarantee that callback handlers will only +The asio library provides a guarantee that completion handlers will only be called from threads that are currently calling boost::asio::io_context::run(). -Therefore unless the boost::asio::io_context::run() function is called the callback for -the asynchronous wait completion will never be invoked. +Therefore unless the boost::asio::io_context::run() function is called the completion +handler for the asynchronous wait completion will never be invoked. The boost::asio::io_context::run() function will also continue to run while there is still "work" to do. In this example, the work is the asynchronous wait on the timer, so the call will not return until the timer has expired and the -callback has completed. +completion handler has returned. It is important to remember to give the io_context some work to do before calling boost::asio::io_context::run(). For example, if we had omitted the above call @@ -125,7 +127,7 @@ Return to \ref tuttimer2 */ /** -\page tuttimer3 Timer.3 - Binding arguments to a handler +\page tuttimer3 Timer.3 - Binding arguments to a completion handler In this tutorial we will modify the program from tutorial Timer.2 so that the timer fires once a second. This will show how to pass additional parameters to @@ -137,15 +139,17 @@ your handler function. \until bind.hpp To implement a repeating timer using asio you need to change -the timer's expiry time in your callback function, and to then start a new -asynchronous wait. Obviously this means that the callback function will need +the timer's expiry time in your completion handler, and to then start a new +asynchronous wait. Obviously this means that the completion handler will need to be able to access the timer object. To this end we add two new parameters to the print function: -\li A pointer to a timer object. +\li a pointer to a timer object; and -\li A counter so that we can stop the program when the timer fires for the -sixth time. +\li a counter so that we can stop the program when the timer fires for the +sixth time + +at the end of the parameter list. \until { @@ -168,7 +172,7 @@ whole-second mark due to any delays in processing the handler. Then we start a new asynchronous wait on the timer. As you can see, the boost::bind() function is used to associate the extra parameters -with your callback handler. The boost::asio::steady_timer::async_wait() function +with your completion handler. The boost::asio::steady_timer::async_wait() function expects a handler function (or function object) with the signature void(const boost::system::error_code&). Binding the additional parameters converts your print function into a function object that matches the @@ -182,7 +186,7 @@ named placeholder for the error object passed to the handler. When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In tutorial Timer.4 you will see that this placeholder may be elided if the parameter is not needed by -the callback handler. +the completion handler. \until boost::asio::io_context @@ -217,9 +221,9 @@ Return to \ref tuttimer3 */ /** -\page tuttimer4 Timer.4 - Using a member function as a handler +\page tuttimer4 Timer.4 - Using a member function as a completion handler -In this tutorial we will see how to use a class member function as a callback +In this tutorial we will see how to use a class member function as a completion handler. The program should execute identically to the tutorial program from tutorial Timer.3. @@ -229,7 +233,7 @@ tutorial Timer.3. \until bind.hpp Instead of defining a free function print as the -callback handler, as we did in the earlier tutorial programs, we now define a +completion handler, as we did in the earlier tutorial programs, we now define a class called printer. \until public @@ -244,7 +248,7 @@ The boost::bind() function works just as well with class member functions as with free functions. Since all non-static class member functions have an implicit this parameter, we need to bind this to the function. As in tutorial Timer.3, boost::bind() -converts our callback handler (now a member function) into a function object +converts our completion handler (now a member function) into a function object that can be invoked as though it has the signature void(const boost::system::error_code&). @@ -286,17 +290,17 @@ Return to \ref tuttimer4 */ /** -\page tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs +\page tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs This tutorial demonstrates the use of the boost::asio::strand class template to -synchronise callback handlers in a multithreaded program. +synchronise completion handlers in a multithreaded program. The previous four tutorials avoided the issue of handler synchronisation by calling the boost::asio::io_context::run() function from one thread only. As you -already know, the asio library provides a guarantee that callback handlers will -only be called from threads that are currently calling +already know, the asio library provides a guarantee that completion handlers +will only be called from threads that are currently calling boost::asio::io_context::run(). Consequently, calling boost::asio::io_context::run() from -only one thread ensures that callback handlers cannot run concurrently. +only one thread ensures that completion handlers cannot run concurrently. The single threaded approach is usually the best place to start when developing applications using asio. The downside is the limitations it places @@ -338,7 +342,7 @@ object. \until { -When initiating the asynchronous operations, each callback handler is "bound" +When initiating the asynchronous operations, each completion handler is "bound" to an boost::asio::strand object. The boost::asio::bind_executor() function returns a new handler that automatically dispatches its contained handler through the boost::asio::strand object. By diff --git a/include/boost/asio/detached.hpp b/include/boost/asio/detached.hpp index ac3adb28..08390819 100644 --- a/include/boost/asio/detached.hpp +++ b/include/boost/asio/detached.hpp @@ -24,15 +24,15 @@ namespace boost { namespace asio { -/// Class used to specify that an asynchronous operation is detached. +/// A @ref completion_token type used to specify that an asynchronous operation +/// is detached. /** - * The detached_t class is used to indicate that an asynchronous operation is * detached. That is, there is no completion handler waiting for the * operation's result. A detached_t object may be passed as a handler to an * asynchronous operation, typically using the special value * @c boost::asio::detached. For example: - + * * @code my_socket.async_send(my_buffer, boost::asio::detached); * @endcode */ @@ -94,7 +94,8 @@ public: } }; -/// A special value, similar to std::nothrow. +/// A @ref completion_token object used to specify that an asynchronous +/// operation is detached. /** * See the documentation for boost::asio::detached_t for a usage example. */ diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index 145a160f..24b0ea7c 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -24,6 +24,7 @@ # define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 # define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1 #else // defined(BOOST_ASIO_STANDALONE) +// Boost.Config library is available. # include # include # define BOOST_ASIO_HAS_BOOST_CONFIG 1 diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp index ba4c8c43..44c40a69 100644 --- a/include/boost/asio/detail/impl/socket_ops.ipp +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -482,7 +482,12 @@ int connect(socket_type s, const socket_addr_type* addr, get_last_error(ec, result != 0); #if defined(__linux__) if (result != 0 && ec == boost::asio::error::try_again) - ec = boost::asio::error::no_buffer_space; + { + if (addr->sa_family == AF_UNIX) + ec = boost::asio::error::in_progress; + else + ec = boost::asio::error::no_buffer_space; + } #endif // defined(__linux__) return result; } diff --git a/include/boost/asio/detail/impl/win_iocp_file_service.ipp b/include/boost/asio/detail/impl/win_iocp_file_service.ipp index a28e978d..b0785643 100644 --- a/include/boost/asio/detail/impl/win_iocp_file_service.ipp +++ b/include/boost/asio/detail/impl/win_iocp_file_service.ipp @@ -68,6 +68,8 @@ boost::system::error_code win_iocp_file_service::open( else if ((open_flags & file_base::read_write) != 0) access = GENERIC_READ | GENERIC_WRITE; + DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE; + DWORD disposition = 0; if ((open_flags & file_base::create) != 0) { @@ -92,7 +94,7 @@ boost::system::error_code win_iocp_file_service::open( if ((open_flags & file_base::sync_all_on_write) != 0) flags |= FILE_FLAG_WRITE_THROUGH; - HANDLE handle = ::CreateFileA(path, access, 0, 0, disposition, flags, 0); + HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0); if (handle != INVALID_HANDLE_VALUE) { if (disposition == OPEN_ALWAYS && (open_flags & file_base::truncate) != 0) diff --git a/include/boost/asio/executor_work_guard.hpp b/include/boost/asio/executor_work_guard.hpp index aabac6c5..9cb60563 100644 --- a/include/boost/asio/executor_work_guard.hpp +++ b/include/boost/asio/executor_work_guard.hpp @@ -37,8 +37,8 @@ class executor_work_guard; #if defined(GENERATING_DOCUMENTATION) -/// An object of type @c executor_work_guard controls ownership of executor work -/// within a scope. +/// An object of type @c executor_work_guard controls ownership of outstanding +/// executor work within a scope. template class executor_work_guard { @@ -245,6 +245,11 @@ private: #endif // !defined(GENERATING_DOCUMENTATION) /// Create an @ref executor_work_guard object. +/** + * @param ex An executor. + * + * @returns A work guard constructed with the specified executor. + */ template BOOST_ASIO_NODISCARD inline executor_work_guard make_work_guard(const Executor& ex, @@ -256,6 +261,12 @@ make_work_guard(const Executor& ex, } /// Create an @ref executor_work_guard object. +/** + * @param ctx An execution context, from which an executor will be obtained. + * + * @returns A work guard constructed with the execution context's executor, + * obtained by performing ctx.get_executor(). + */ template BOOST_ASIO_NODISCARD inline executor_work_guard @@ -269,6 +280,13 @@ make_work_guard(ExecutionContext& ctx, } /// Create an @ref executor_work_guard object. +/** + * @param t An arbitrary object, such as a completion handler, for which the + * associated executor will be obtained. + * + * @returns A work guard constructed with the associated executor of the object + * @c t, which is obtained as if by calling get_associated_executor(t). + */ template BOOST_ASIO_NODISCARD inline executor_work_guard::type> @@ -288,6 +306,17 @@ make_work_guard(const T& t, } /// Create an @ref executor_work_guard object. +/** + * @param t An arbitrary object, such as a completion handler, for which the + * associated executor will be obtained. + * + * @param ex An executor to be used as the candidate object when determining the + * associated executor. + * + * @returns A work guard constructed with the associated executor of the object + * @c t, which is obtained as if by calling get_associated_executor(t, + * ex). + */ template BOOST_ASIO_NODISCARD inline executor_work_guard::type> @@ -301,6 +330,17 @@ make_work_guard(const T& t, const Executor& ex, } /// Create an @ref executor_work_guard object. +/** + * @param t An arbitrary object, such as a completion handler, for which the + * associated executor will be obtained. + * + * @param ctx An execution context, from which an executor is obtained to use as + * the candidate object for determining the associated executor. + * + * @returns A work guard constructed with the associated executor of the object + * @c t, which is obtained as if by calling get_associated_executor(t, + * ctx.get_executor()). + */ template BOOST_ASIO_NODISCARD inline executor_work_guard::type> diff --git a/include/boost/asio/experimental/as_single.hpp b/include/boost/asio/experimental/as_single.hpp index c0472769..3fc38eb1 100644 --- a/include/boost/asio/experimental/as_single.hpp +++ b/include/boost/asio/experimental/as_single.hpp @@ -24,7 +24,7 @@ namespace boost { namespace asio { namespace experimental { -/// Completion token type used to specify that the completion handler +/// A @ref completion_token adapter used to specify that the completion handler /// arguments should be combined into a single argument. /** * The as_single_t class is used to indicate that any arguments to the @@ -116,8 +116,8 @@ public: CompletionToken token_; }; -/// Create a completion token to specify that the completion handler arguments -/// should be combined into a single argument. +/// Adapt a @ref completion_token to specify that the completion handler +/// arguments should be combined into a single argument. template BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONSTEXPR as_single_t::type> diff --git a/include/boost/asio/experimental/as_tuple.hpp b/include/boost/asio/experimental/as_tuple.hpp index 12552d77..54547af1 100644 --- a/include/boost/asio/experimental/as_tuple.hpp +++ b/include/boost/asio/experimental/as_tuple.hpp @@ -24,7 +24,7 @@ namespace boost { namespace asio { namespace experimental { -/// Completion token type used to specify that the completion handler +/// A @ref completion_token adapter used to specify that the completion handler /// arguments should be combined into a single tuple argument. /** * The as_tuple_t class is used to indicate that any arguments to the @@ -112,8 +112,8 @@ public: CompletionToken token_; }; -/// Create a completion token to specify that the completion handler arguments -/// should be combined into a single tuple argument. +/// Adapt a @ref completion_token to specify that the completion handler +/// arguments should be combined into a single tuple argument. template BOOST_ASIO_NODISCARD inline BOOST_ASIO_CONSTEXPR as_tuple_t::type> diff --git a/include/boost/asio/experimental/basic_channel.hpp b/include/boost/asio/experimental/basic_channel.hpp index ee90c885..ca34c8eb 100644 --- a/include/boost/asio/experimental/basic_channel.hpp +++ b/include/boost/asio/experimental/basic_channel.hpp @@ -33,6 +33,67 @@ namespace detail { } // namespace detail /// A channel for messages. +/** + * The basic_channel class template is used for sending messages between + * different parts of the same application. A message is defined as a + * collection of arguments to be passed to a completion handler, and the set of + * messages supported by a channel is specified by its @c Traits and + * Signatures... template parameters. Messages may be sent and received + * using asynchronous or non-blocking synchronous operations. + * + * Unless customising the traits, applications will typically use the @c + * experimental::channel alias template. For example: + * @code void send_loop(int i, steady_timer& timer, + * channel& ch) + * { + * if (i < 10) + * { + * timer.expires_after(chrono::seconds(1)); + * timer.async_wait( + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * ch.async_send(error_code(), i, + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * send_loop(i + 1, timer, ch); + * } + * }); + * } + * }); + * } + * else + * { + * ch.close(); + * } + * } + * + * void receive_loop(channel& ch) + * { + * ch.async_receive( + * [&ch](error_code error, int i) + * { + * if (!error) + * { + * std::cout << "Received " << i << "\n"; + * receive_loop(ch); + * } + * }); + * } @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * The basic_channel class template is not thread-safe, and would typically be + * used for passing messages between application code that runs on the same + * thread or in the same strand. Consider using @ref basic_concurrent_channel, + * and its alias template @c experimental::concurrent_channel, to pass messages + * between code running in different threads. + */ template class basic_channel #if !defined(GENERATING_DOCUMENTATION) @@ -254,7 +315,7 @@ public: /// Cancel all asynchronous operations waiting on the channel. /** * All outstanding send operations will complete with the error - * @c boost::asio::experimental::error::channel_canceld. Outstanding receive + * @c boost::asio::experimental::error::channel_cancelled. Outstanding receive * operations complete with the result as determined by the channel traits. */ void cancel() diff --git a/include/boost/asio/experimental/basic_concurrent_channel.hpp b/include/boost/asio/experimental/basic_concurrent_channel.hpp index b8b39692..73d00678 100644 --- a/include/boost/asio/experimental/basic_concurrent_channel.hpp +++ b/include/boost/asio/experimental/basic_concurrent_channel.hpp @@ -33,6 +33,67 @@ namespace detail { } // namespace detail /// A channel for messages. +/** + * The basic_concurrent_channel class template is used for sending messages + * between different parts of the same application. A message is + * defined as a collection of arguments to be passed to a completion handler, + * and the set of messages supported by a channel is specified by its @c Traits + * and Signatures... template parameters. Messages may be sent and + * received using asynchronous or non-blocking synchronous operations. + * + * Unless customising the traits, applications will typically use the @c + * experimental::concurrent_channel alias template. For example: + * @code void send_loop(int i, steady_timer& timer, + * concurrent_channel& ch) + * { + * if (i < 10) + * { + * timer.expires_after(chrono::seconds(1)); + * timer.async_wait( + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * ch.async_send(error_code(), i, + * [i, &timer, &ch](error_code error) + * { + * if (!error) + * { + * send_loop(i + 1, timer, ch); + * } + * }); + * } + * }); + * } + * else + * { + * ch.close(); + * } + * } + * + * void receive_loop(concurent_channel& ch) + * { + * ch.async_receive( + * [&ch](error_code error, int i) + * { + * if (!error) + * { + * std::cout << "Received " << i << "\n"; + * receive_loop(ch); + * } + * }); + * } @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * The basic_concurrent_channel class template is thread-safe, and would + * typically be used for passing messages between application code that run on + * different threads. Consider using @ref basic_channel, and its alias template + * @c experimental::channel, to pass messages between code running in a single + * thread or on the same strand. + */ template class basic_concurrent_channel #if !defined(GENERATING_DOCUMENTATION) @@ -261,7 +322,7 @@ public: /// Cancel all asynchronous operations waiting on the channel. /** * All outstanding send operations will complete with the error - * @c boost::asio::experimental::error::channel_canceld. Outstanding receive + * @c boost::asio::experimental::error::channel_cancelled. Outstanding receive * operations complete with the result as determined by the channel traits. */ void cancel() diff --git a/include/boost/asio/experimental/deferred.hpp b/include/boost/asio/experimental/deferred.hpp index a8a79467..afa6f0e8 100644 --- a/include/boost/asio/experimental/deferred.hpp +++ b/include/boost/asio/experimental/deferred.hpp @@ -474,7 +474,7 @@ struct is_deferred > : true_type * operation, typically using the special value @c boost::asio::deferred. For * example: * - * @code auto my_sender + * @code auto my_deferred_op * = my_socket.async_read_some(my_buffer, * boost::asio::experimental::deferred); @endcode * @@ -585,7 +585,8 @@ inline auto operator|(Head head, BOOST_ASIO_MOVE_ARG(Tail) tail) BOOST_ASIO_MOVE_CAST(Tail)(tail)); } -/// A special value, similar to std::nothrow. +/// A @ref completion_token object used to specify that an asynchronous +/// operation should return a function object to lazily launch the operation. /** * See the documentation for boost::asio::experimental::deferred_t for a usage * example. diff --git a/include/boost/asio/experimental/detail/impl/channel_service.hpp b/include/boost/asio/experimental/detail/impl/channel_service.hpp index 29c698d3..29951325 100644 --- a/include/boost/asio/experimental/detail/impl/channel_service.hpp +++ b/include/boost/asio/experimental/detail/impl/channel_service.hpp @@ -182,10 +182,8 @@ void channel_service::reset( typename Mutex::scoped_lock lock(impl.mutex_); - if (impl.receive_state_ == closed) - impl.receive_state_ = block; - if (impl.send_state_ == closed) - impl.send_state_ = impl.max_buffer_size_ ? buffer : block; + impl.receive_state_ = block; + impl.send_state_ = impl.max_buffer_size_ ? buffer : block; impl.buffer_clear(); } diff --git a/include/boost/asio/experimental/parallel_group.hpp b/include/boost/asio/experimental/parallel_group.hpp index cd543108..282be105 100644 --- a/include/boost/asio/experimental/parallel_group.hpp +++ b/include/boost/asio/experimental/parallel_group.hpp @@ -128,7 +128,7 @@ public: * operations, it must return a boost::asio::cancellation_type value other * than boost::asio::cancellation_type::none. * - * @param token A completion token whose signature is comprised of + * @param token A @ref completion_token whose signature is comprised of * a @c std::array indicating the completion order of the * operations, followed by all operations' completion handler arguments. * diff --git a/include/boost/asio/experimental/promise.hpp b/include/boost/asio/experimental/promise.hpp index 5f8812d7..fd66e614 100644 --- a/include/boost/asio/experimental/promise.hpp +++ b/include/boost/asio/experimental/promise.hpp @@ -501,7 +501,10 @@ struct promise throw std::logic_error( "Can't use race on an empty range with deduced executor"); else - return race(std::begin(range)->get_executor(), std::move(range)); + { + auto ex = std::begin(range)->get_executor(); + return race(ex, std::move(range)); + } } template @@ -518,7 +521,10 @@ struct promise throw std::logic_error( "Can't use all on an empty range with deduced executor"); else - return all(std::begin(range)->get_executor(), std::move(range)); + { + auto ex = std::begin(range)->get_executor(); + return all(ex, std::move(range)); + } } private: diff --git a/include/boost/asio/experimental/use_coro.hpp b/include/boost/asio/experimental/use_coro.hpp index da953bd2..e815422d 100644 --- a/include/boost/asio/experimental/use_coro.hpp +++ b/include/boost/asio/experimental/use_coro.hpp @@ -32,7 +32,7 @@ class any_io_executor; namespace experimental { -/// A completion token that represents the currently executing resumable +/// A @ref completion_token that represents the currently executing resumable /// coroutine. /** * The @c use_coro_t class, with its value @c use_coro, is used to represent an @@ -146,8 +146,8 @@ struct use_coro_t #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) }; -/// A completion token object that represents the currently executing resumable -/// coroutine. +/// A @ref completion_token object that represents the currently executing +/// resumable coroutine. /** * See the documentation for boost::asio::use_coro_t for a usage example. */ diff --git a/include/boost/asio/impl/co_spawn.hpp b/include/boost/asio/impl/co_spawn.hpp index 46f65d78..03f82ac0 100644 --- a/include/boost/asio/impl/co_spawn.hpp +++ b/include/boost/asio/impl/co_spawn.hpp @@ -200,6 +200,61 @@ private: awaitable awaitable_; }; +template +class co_spawn_cancellation_handler +{ +public: + co_spawn_cancellation_handler(const Handler& handler, const Executor& ex) + : ex_(boost::asio::get_associated_executor(handler, ex)) + { + } + + cancellation_slot slot() + { + return signal_.slot(); + } + + void operator()(cancellation_type_t type) + { + cancellation_signal* sig = &signal_; + boost::asio::dispatch(ex_, [sig, type]{ sig->emit(type); }); + } + +private: + cancellation_signal signal_; + typename associated_executor::type ex_; +}; + + +template +class co_spawn_cancellation_handler::asio_associated_executor_is_unspecialised, + void + >::value + >::type> +{ +public: + co_spawn_cancellation_handler(const Handler&, const Executor&) + { + } + + cancellation_slot slot() + { + return signal_.slot(); + } + + void operator()(cancellation_type_t type) + { + signal_.emit(type); + } + +private: + cancellation_signal signal_; +}; + template class initiate_co_spawn { @@ -221,17 +276,26 @@ public: void operator()(Handler&& handler, F&& f) const { typedef typename result_of::type awaitable_type; + typedef typename decay::type handler_type; + typedef co_spawn_cancellation_handler< + handler_type, Executor> cancel_handler_type; - cancellation_state proxy_cancel_state( - boost::asio::get_associated_cancellation_slot(handler), - enable_total_cancellation()); + auto slot = boost::asio::get_associated_cancellation_slot(handler); + cancel_handler_type* cancel_handler = slot.is_connected() + ? &slot.template emplace(handler, ex_) + : nullptr; - cancellation_state cancel_state(proxy_cancel_state.slot()); + cancellation_slot proxy_slot( + cancel_handler + ? cancel_handler->slot() + : cancellation_slot()); + + cancellation_state cancel_state(proxy_slot); auto a = (co_spawn_entry_point)(static_cast(nullptr), ex_, std::forward(f), std::forward(handler)); - awaitable_handler(std::move(a), ex_, - proxy_cancel_state.slot(), cancel_state).launch(); + awaitable_handler(std::move(a), + ex_, proxy_slot, cancel_state).launch(); } private: diff --git a/include/boost/asio/io_context.hpp b/include/boost/asio/io_context.hpp index 2cf1e18d..7decac13 100644 --- a/include/boost/asio/io_context.hpp +++ b/include/boost/asio/io_context.hpp @@ -170,30 +170,12 @@ namespace detail { * returning when there is no more work to do. For example, the io_context may * be being run in a background thread that is launched prior to the * application's asynchronous operations. The run() call may be kept running by - * creating an executor that tracks work against the io_context: + * using the @ref make_work_guard function to create an object of type + * boost::asio::executor_work_guard: * * @code boost::asio::io_context io_context; - * auto work = boost::asio::require(io_context.get_executor(), - * boost::asio::execution::outstanding_work.tracked); - * ... @endcode - * - * If using C++03, which lacks automatic variable type deduction, you may - * compute the return type of the require call: - * - * @code boost::asio::io_context io_context; - * typename boost::asio::require_result< - * boost::asio::io_context::executor_type, - * boost::asio::exeution::outstanding_work_t::tracked_t> - * work = boost::asio::require(io_context.get_executor(), - * boost::asio::execution::outstanding_work.tracked); - * ... @endcode - * - * or store the result in the type-erasing executor wrapper, any_io_executor: - * - * @code boost::asio::io_context io_context; - * boost::asio::any_io_executor work - * = boost::asio::require(io_context.get_executor(), - * boost::asio::execution::outstanding_work.tracked); + * boost::asio::executor_work_guard + * = boost::asio::make_work_guard(io_context); * ... @endcode * * To effect a shutdown, the application will then need to call the io_context @@ -202,15 +184,13 @@ namespace detail { * permitting ready handlers to be dispatched. * * Alternatively, if the application requires that all operations and handlers - * be allowed to finish normally, store the work-tracking executor in an - * any_io_executor object, so that it may be explicitly reset. + * be allowed to finish normally, the work object may be explicitly reset. * * @code boost::asio::io_context io_context; - * boost::asio::any_io_executor work - * = boost::asio::require(io_context.get_executor(), - * boost::asio::execution::outstanding_work.tracked); + * boost::asio::executor_work_guard + * = boost::asio::make_work_guard(io_context); * ... - * work = boost::asio::any_io_executor(); // Allow run() to exit. @endcode + * work.reset(); // Allow run() to exit. @endcode */ class io_context : public execution_context diff --git a/include/boost/asio/ip/address_v4.hpp b/include/boost/asio/ip/address_v4.hpp index 1eec2531..e639806b 100644 --- a/include/boost/asio/ip/address_v4.hpp +++ b/include/boost/asio/ip/address_v4.hpp @@ -65,15 +65,31 @@ public: #endif /// Default constructor. + /** + * Initialises the @c address_v4 object such that: + * @li to_bytes() yields {0, 0, 0, 0}; and + * @li to_uint() == 0. + */ address_v4() BOOST_ASIO_NOEXCEPT { addr_.s_addr = 0; } /// Construct an address from raw bytes. + /** + * Initialises the @c address_v4 object such that to_bytes() == + * bytes. + * + * @throws out_of_range Thrown if any element in @c bytes is not in the range + * 0 - 0xFF. Note that no range checking is required for platforms + * where std::numeric_limits::max() is 0xFF. + */ BOOST_ASIO_DECL explicit address_v4(const bytes_type& bytes); /// Construct an address from an unsigned integer in host byte order. + /** + * Initialises the @c address_v4 object such that to_uint() == addr. + */ BOOST_ASIO_DECL explicit address_v4(uint_type addr); /// Copy constructor. @@ -145,9 +161,22 @@ public: #endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. + /** + * This function tests whether the address is in the address block + * 127.0.0.0/8, which corresponds to the address range + * 127.0.0.0 - 127.255.255.255. + * + * @returns (to_uint() & 0xFF000000) == 0x7F000000. + */ BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT; /// Determine whether the address is unspecified. + /** + * This function tests whether the address is the unspecified address + * 0.0.0.0. + * + * @returns to_uint() == 0. + */ BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT; #if !defined(BOOST_ASIO_NO_DEPRECATED) @@ -165,6 +194,13 @@ public: #endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a multicast address. + /** + * This function tests whether the address is in the multicast address block + * 224.0.0.0/4, which corresponds to the address range + * 224.0.0.0 - 239.255.255.255. + * + * @returns (to_uint() & 0xF0000000) == 0xE0000000. + */ BOOST_ASIO_DECL bool is_multicast() const BOOST_ASIO_NOEXCEPT; /// Compare two addresses for equality. @@ -182,6 +218,11 @@ public: } /// Compare addresses for ordering. + /** + * Compares two addresses in host byte order. + * + * @returns a1.to_uint() < a2.to_uint(). + */ friend bool operator<(const address_v4& a1, const address_v4& a2) BOOST_ASIO_NOEXCEPT { @@ -189,6 +230,11 @@ public: } /// Compare addresses for ordering. + /** + * Compares two addresses in host byte order. + * + * @returns a1.to_uint() > a2.to_uint(). + */ friend bool operator>(const address_v4& a1, const address_v4& a2) BOOST_ASIO_NOEXCEPT { @@ -196,6 +242,11 @@ public: } /// Compare addresses for ordering. + /** + * Compares two addresses in host byte order. + * + * @returns a1.to_uint() <= a2.to_uint(). + */ friend bool operator<=(const address_v4& a1, const address_v4& a2) BOOST_ASIO_NOEXCEPT { @@ -203,6 +254,11 @@ public: } /// Compare addresses for ordering. + /** + * Compares two addresses in host byte order. + * + * @returns a1.to_uint() >= a2.to_uint(). + */ friend bool operator>=(const address_v4& a1, const address_v4& a2) BOOST_ASIO_NOEXCEPT { @@ -210,18 +266,36 @@ public: } /// Obtain an address object that represents any address. + /** + * This functions returns an address that represents the "any" address + * 0.0.0.0. + * + * @returns A default-constructed @c address_v4 object. + */ static address_v4 any() BOOST_ASIO_NOEXCEPT { return address_v4(); } /// Obtain an address object that represents the loopback address. + /** + * This function returns an address that represents the well-known loopback + * address 127.0.0.1. + * + * @returns address_v4(0x7F000001). + */ static address_v4 loopback() BOOST_ASIO_NOEXCEPT { return address_v4(0x7F000001); } /// Obtain an address object that represents the broadcast address. + /** + * This function returns an address that represents the broadcast address + * 255.255.255.255. + * + * @returns address_v4(0xFFFFFFFF). + */ static address_v4 broadcast() BOOST_ASIO_NOEXCEPT { return address_v4(0xFFFFFFFF); diff --git a/include/boost/asio/ip/address_v6.hpp b/include/boost/asio/ip/address_v6.hpp index 4a678fc7..0a7ddd04 100644 --- a/include/boost/asio/ip/address_v6.hpp +++ b/include/boost/asio/ip/address_v6.hpp @@ -68,9 +68,23 @@ public: #endif /// Default constructor. + /** + * Initialises the @c address_v6 object such that: + * @li to_bytes() yields {0, 0, ..., 0}; and + * @li scope_id() == 0. + */ BOOST_ASIO_DECL address_v6() BOOST_ASIO_NOEXCEPT; /// Construct an address from raw bytes and scope ID. + /** + * Initialises the @c address_v6 object such that: + * @li to_bytes() == bytes; and + * @li this->scope_id() == scope_id. + * + * @throws out_of_range Thrown if any element in @c bytes is not in the range + * 0 - 0xFF. Note that no range checking is required for platforms + * where std::numeric_limits::max() is 0xFF. + */ BOOST_ASIO_DECL explicit address_v6(const bytes_type& bytes, scope_id_type scope_id = 0); @@ -103,6 +117,8 @@ public: /// The scope ID of the address. /** * Modifies the scope ID associated with the IPv6 address. + * + * @param id The new scope ID. */ void scope_id(scope_id_type id) BOOST_ASIO_NOEXCEPT { @@ -143,9 +159,17 @@ public: #endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. + /** + * This function tests whether the address is the loopback address + * ::1. + */ BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT; /// Determine whether the address is unspecified. + /** + * This function tests whether the address is the loopback address + * ::. + */ BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT; /// Determine whether the address is link local. @@ -218,12 +242,22 @@ public: } /// Obtain an address object that represents any address. + /** + * This functions returns an address that represents the "any" address + * ::. + * + * @returns A default-constructed @c address_v6 object. + */ static address_v6 any() BOOST_ASIO_NOEXCEPT { return address_v6(); } /// Obtain an address object that represents the loopback address. + /** + * This function returns an address that represents the well-known loopback + * address ::1. + */ BOOST_ASIO_DECL static address_v6 loopback() BOOST_ASIO_NOEXCEPT; #if !defined(BOOST_ASIO_NO_DEPRECATED) diff --git a/include/boost/asio/redirect_error.hpp b/include/boost/asio/redirect_error.hpp index f2e83a5a..7d60bf55 100644 --- a/include/boost/asio/redirect_error.hpp +++ b/include/boost/asio/redirect_error.hpp @@ -24,7 +24,7 @@ namespace boost { namespace asio { -/// Completion token type used to specify that an error produced by an +/// A @ref completion_token adapter used to specify that an error produced by an /// asynchronous operation is captured to an error_code variable. /** * The redirect_error_t class is used to indicate that any error_code produced @@ -48,7 +48,7 @@ public: boost::system::error_code& ec_; }; -/// Create a completion token to capture error_code values to a variable. +/// Adapt a @ref completion_token to capture error_code values to a variable. template inline redirect_error_t::type> redirect_error( BOOST_ASIO_MOVE_ARG(CompletionToken) completion_token, diff --git a/include/boost/asio/spawn.hpp b/include/boost/asio/spawn.hpp index 43ad24a4..35263606 100644 --- a/include/boost/asio/spawn.hpp +++ b/include/boost/asio/spawn.hpp @@ -31,7 +31,7 @@ namespace boost { namespace asio { -/// A completion token that represents the currently executing coroutine. +/// A @ref completion_token that represents the currently executing coroutine. /** * The basic_yield_context class is a completion token type that is used to * represent the currently executing stackful coroutine. A basic_yield_context @@ -149,7 +149,8 @@ private: }; #if defined(GENERATING_DOCUMENTATION) -/// Context object that represents the currently executing coroutine. +/// A @ref completion_token object that represents the currently executing +/// coroutine. typedef basic_yield_context yield_context; #else // defined(GENERATING_DOCUMENTATION) typedef basic_yield_context< diff --git a/include/boost/asio/strand.hpp b/include/boost/asio/strand.hpp index ddbf9204..041d891f 100644 --- a/include/boost/asio/strand.hpp +++ b/include/boost/asio/strand.hpp @@ -442,6 +442,11 @@ private: /*@{*/ /// Create a @ref strand object for an executor. +/** + * @param ex An executor. + * + * @returns A strand constructed with the specified executor. + */ template inline strand make_strand(const Executor& ex, typename constraint< @@ -452,6 +457,12 @@ inline strand make_strand(const Executor& ex, } /// Create a @ref strand object for an execution context. +/** + * @param ctx An execution context, from which an executor will be obtained. + * + * @returns A strand constructed with the execution context's executor, obtained + * by performing ctx.get_executor(). + */ template inline strand make_strand(ExecutionContext& ctx, diff --git a/include/boost/asio/this_coro.hpp b/include/boost/asio/this_coro.hpp index 6d5f9b08..2e0c994f 100644 --- a/include/boost/asio/this_coro.hpp +++ b/include/boost/asio/this_coro.hpp @@ -74,7 +74,7 @@ __declspec(selectany) cancellation_state_t cancellation_state; /// of the current coroutine. /** * Let P be the cancellation slot associated with the current - * coroutine's `co_spawn` completion handler. Assigns a new + * coroutine's @ref co_spawn completion handler. Assigns a new * boost::asio::cancellation_state object S, constructed as * S(P), into the current coroutine's cancellation state object. * @@ -96,7 +96,7 @@ reset_cancellation_state(); /// of the current coroutine. /** * Let P be the cancellation slot associated with the current - * coroutine's `co_spawn` completion handler. Assigns a new + * coroutine's @ref co_spawn completion handler. Assigns a new * boost::asio::cancellation_state object S, constructed as S(P, * std::forward(filter)), into the current coroutine's * cancellation state object. @@ -121,7 +121,7 @@ reset_cancellation_state(BOOST_ASIO_MOVE_ARG(Filter) filter); /// of the current coroutine. /** * Let P be the cancellation slot associated with the current - * coroutine's `co_spawn` completion handler. Assigns a new + * coroutine's @ref co_spawn completion handler. Assigns a new * boost::asio::cancellation_state object S, constructed as S(P, * std::forward(in_filter), * std::forward(out_filter)), into the current coroutine's diff --git a/include/boost/asio/use_awaitable.hpp b/include/boost/asio/use_awaitable.hpp index 78c44f05..f3bc66b1 100644 --- a/include/boost/asio/use_awaitable.hpp +++ b/include/boost/asio/use_awaitable.hpp @@ -33,7 +33,7 @@ namespace boost { namespace asio { -/// A completion token that represents the currently executing coroutine. +/// A @ref completion_token that represents the currently executing coroutine. /** * The @c use_awaitable_t class, with its value @c use_awaitable, is used to * represent the currently executing coroutine. This completion token may be @@ -144,7 +144,8 @@ struct use_awaitable_t #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) }; -/// A completion token object that represents the currently executing coroutine. +/// A @ref completion_token object that represents the currently executing +/// coroutine. /** * See the documentation for boost::asio::use_awaitable_t for a usage example. */ diff --git a/include/boost/asio/use_future.hpp b/include/boost/asio/use_future.hpp index a8d9a96f..8c756780 100644 --- a/include/boost/asio/use_future.hpp +++ b/include/boost/asio/use_future.hpp @@ -38,8 +38,8 @@ class packaged_handler; } // namespace detail -/// A completion token type that causes an asynchronous operation to return a -/// future. +/// A @ref completion_token type that causes an asynchronous operation to return +/// a future. /** * The use_future_t class is a completion token type that is used to indicate * that an asynchronous operation should return a std::future object. A @@ -141,8 +141,8 @@ private: std_allocator_void, Allocator>::type allocator_; }; -/// A completion token object that causes an asynchronous operation to return a -/// future. +/// A @ref completion_token object that causes an asynchronous operation to +/// return a future. /** * See the documentation for boost::asio::use_future_t for a usage example. */ diff --git a/include/boost/asio/version.hpp b/include/boost/asio/version.hpp index 9b18c1cf..69f899b7 100644 --- a/include/boost/asio/version.hpp +++ b/include/boost/asio/version.hpp @@ -18,6 +18,6 @@ // BOOST_ASIO_VERSION % 100 is the sub-minor version // BOOST_ASIO_VERSION / 100 % 1000 is the minor version // BOOST_ASIO_VERSION / 100000 is the major version -#define BOOST_ASIO_VERSION 102201 // 1.22.1 +#define BOOST_ASIO_VERSION 102202 // 1.22.2 #endif // BOOST_ASIO_VERSION_HPP