2
0
mirror of https://github.com/boostorg/asio.git synced 2026-01-22 17:12:08 +00:00

47 Commits

Author SHA1 Message Date
Christopher Kohlhoff
84c45dbe48 Add inline_executor. 2025-10-29 22:58:47 +11:00
Christopher Kohlhoff
cd2b1b37ff Fix compilation errors in channel<void(error_code)>. 2025-08-05 08:09:27 +10:00
Christopher Kohlhoff
1afbc5c12b Update copyright notices. 2025-03-04 22:57:26 +11:00
Christopher Kohlhoff
5c01494f70 Promote co_composed to the asio namespace. 2024-07-02 07:54:20 +10:00
Christopher Kohlhoff
e5a93b5e15 Permit an empty variadic list of completion signatures.
An asynchronous operation having no completion signatures signifies that the
operation never completes.
2024-07-02 07:31:07 +10:00
Christopher Kohlhoff
c83ee18458 Clean up spurious white space. 2024-06-27 23:01:17 +10:00
Christopher Kohlhoff
fc1bdcb2d6 Fix experimental::coro compatibility with Apple clang 15. 2024-06-26 22:49:38 +10:00
Christopher Kohlhoff
ac35960f03 Add missing #include to parallel_group header. 2024-03-06 00:52:05 +11:00
Christopher Kohlhoff
c36d3ef338 Update copyright notices. 2024-03-05 07:51:17 +11:00
Christopher Kohlhoff
77bc08c046 Fix compatibility between experimental::channel and any_completion_handler. 2023-11-07 23:20:05 +11:00
Christopher Kohlhoff
e1d4890f02 Add support for two channel payload signatures with c++11. 2023-11-01 23:12:14 +11:00
Christopher Kohlhoff
08b8c3cec3 Add try_send_via_dispatch/try_send_n_via_dispatch functions to channels. 2023-11-01 23:12:14 +11:00
Christopher Kohlhoff
f1662c9eeb Add missing #includes. 2023-10-26 20:15:07 +11:00
Christopher Kohlhoff
a4b0f59b37 Fix incorrect reuse of moved-from result in experimental::promise. 2023-04-04 20:20:47 +10:00
Christopher Kohlhoff
d6a4d3b898 Add interoperability between channels and associated_immediate_executor. 2023-03-08 21:05:44 +11:00
Christopher Kohlhoff
730441dcbb Ensure buffered messages can still be received when channel is closed. 2023-03-06 23:37:39 +11:00
Christopher Kohlhoff
35e93e4e90 Update copyright notices. 2023-03-01 23:03:03 +11:00
Christopher Kohlhoff
56c1f0f647 Cleaned up promise and made it an async_op. 2022-11-03 17:31:32 +11:00
Christopher Kohlhoff
09716d71f3 Enabled deferred awaiting for coros, regularized use_coro, and fixed allocator handling.
This means that use_coro does not return a coro object, just like
use_awaitable does, i.e. it's an overhead that buys us type erasure.
Allocators can now be set for coro by including allocator_arg in the
coro signature.
2022-11-03 17:29:53 +11:00
Christopher Kohlhoff
68ef2b45d4 Add channel buffer specialisation for R(error_code). 2022-11-01 11:35:07 +11:00
Christopher Kohlhoff
1c0f3c36be Add experimental::co_composed.
The following example illustrates a simple asynchronous operation that
implements an echo protocol in terms of a coroutine:

  template <typename CompletionToken>
  auto async_echo(tcp::socket& socket,
      CompletionToken&& token)
  {
    return boost::asio::async_initiate<
      CompletionToken, void(boost::system::error_code)>(
        boost::asio::experimental::co_composed<
          void(boost::system::error_code)>(
            [](auto state, tcp::socket& socket) -> void
            {
              try
              {
                state.throw_if_cancelled(true);
                state.reset_cancellation_state(
                  boost::asio::enable_terminal_cancellation());

                for (;;)
                {
                  char data[1024];
                  std::size_t n = co_await socket.async_read_some(
                      boost::asio::buffer(data), boost::asio::deferred);

                  co_await boost::asio::async_write(socket,
                      boost::asio::buffer(data, n), boost::asio::deferred);
                }
              }
              catch (const boost::system::system_error& e)
              {
                co_return {e.code()};
              }
            }, socket),
        token, std::ref(socket));
  }
2022-11-01 11:35:07 +11:00
Christopher Kohlhoff
46f49024e1 Removed all & race from promise - parallel_group covers most of it now. 2022-06-30 13:41:25 +10:00
Christopher Kohlhoff
4c216747dc Move deferred to the asio namespace.
This is no longer an experimental facility. The names deferred and
deferred_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
2022-06-30 01:08:13 +10:00
Christopher Kohlhoff
34f5627723 Move prepend to the asio namespace.
This is no longer an experimental facility. The names prepend and
prepend_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
2022-06-30 00:43:16 +10:00
Christopher Kohlhoff
f7356fbe90 Move append to the asio namespace.
This is no longer an experimental facility. The names append and
append_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
2022-06-30 00:43:16 +10:00
Christopher Kohlhoff
a312a46715 Move as_tuple to the asio namespace.
This is no longer an experimental facility. The names as_tuple and
as_tuple_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
2022-06-30 00:43:16 +10:00
Christopher Kohlhoff
45bd682d9a Make experimental::prepend compatible with C++11. 2022-06-30 00:43:16 +10:00
Christopher Kohlhoff
6f8e8c847d Make experimental::append compatible with C++11. 2022-06-30 00:43:16 +10:00
Christopher Kohlhoff
001d6213ca Work around shutdown ordering issue in coro/executor test. 2022-03-04 20:56:45 +11:00
Christopher Kohlhoff
31f93ed401 Fix "'this' pointer is null" warnings. 2022-03-02 21:57:42 +11:00
Christopher Kohlhoff
600cf024f1 Add unit test for experimental::as_tuple. 2022-03-02 21:57:42 +11:00
Christopher Kohlhoff
20ed628d43 Fix associator specialisations for append and prepend. 2022-03-02 21:24:01 +11:00
Christopher Kohlhoff
ff58013a23 Update copyright notices. 2022-03-02 21:23:52 +11:00
Christopher Kohlhoff
495e6367af Add experimental support for channels.
This adds experimental::channel and experimental::concurrent_channel.
Channels may be used to send completions as messages. For example:

  // Create a channel with no buffer space.
  channel<void(error_code, size_t)> ch(ctx);

  // The call to try_send fails as there is no buffer
  // space and no waiting receive operations.
  bool ok = ch.try_send(asio::error::eof, 123);
  assert(!ok);

  // The async_send operation blocks until a receive
  // operation consumes the message.
  ch.async_send(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)
      {
        // ...
      });
2021-11-04 01:56:32 +11:00
Christopher Kohlhoff
5b72b72b72 Improvements to asio::experimental::coro.
* Added overload so member functions can provide an explicit executor.
* Added co_spawn for coro tasks.
* Added reference and overview documentation.
* Adopted awaitable cancellation model.
* Refactored implementation.
2021-11-04 01:41:25 +11:00
Christopher Kohlhoff
4ddfe0bfb1 Remove inclusion of boost/scope_exit.hpp. 2021-10-17 11:10:35 +11:00
Klemens
9369dbb269 Gcc fixes for promise & coro. 2021-08-03 17:56:56 +10:00
Christopher Kohlhoff
c1fd78e785 Fix handling of move-only results with awaitable operators && and ||. 2021-07-11 10:20:19 +10:00
Christopher Kohlhoff
ef4e3d873c Add missing #includes for when using separate compilation. 2021-07-08 13:14:30 +10:00
Christopher Kohlhoff
fc486d6530 Fix failure in coro simple_test. 2021-07-07 22:47:10 +10:00
Christopher Kohlhoff
4ca5e6a13a Make promise test more resistant to a heavily loaded test system. 2021-07-05 18:45:03 +10:00
Christopher Kohlhoff
769dc0e149 Add this_coro::throw_if_cancelled.
By default, awaitable<>-based coroutines now throw an exception if they
have been previously cancelled, and then try to perform a co_await
against another awaitable<>.

To disable this behaviour for the current awaitable<>-based "thread",
perform:

    co_await boost::asio::this_coro::throw_if_error(false);

It is then the responsibility of the coroutine implementation to ensure
that it checks the cancellation state of the coroutine manually, by
doing something like:

    auto cs = boost::asio::this_coro::cancellation_state;
    // ...
    if (cs.cancelled() != cancellation_type::none)
    {
      // ... handle cancellation ...
    }
2021-07-04 13:10:27 +10:00
Christopher Kohlhoff
d2ab7b7669 Fix yield input in experimental::coro. 2021-07-04 13:10:27 +10:00
Christopher Kohlhoff
01ca2be880 Ensure experimental::deferred header is self-contained. 2021-07-04 13:10:27 +10:00
Christopher Kohlhoff
f486b43c16 Add operator&& and operator|| for awaitable<>.
The logical operators || and && have been overloaded for awaitable<>, to
allow coroutines to be trivially awaited in parallel.

When awaited using &&, the await expression waits until both operations
have completed successfully. As a "short-circuit" evaluation, if one
operation fails with an exception, the other is immediately cancelled.
For example:

    std::tuple<std::size_t, std::size_t> results =
      co_await (
        async_read(socket, input_buffer, use_awaitable)
          && async_write(socket, output_buffer, use_awaitable)
      );

When awaited using ||, the await expression waits until either operation
succceeds. As a "short-circuit" evaluation, if one operation succeeds
without throwing an exception, the other is immediately cancelled. For
example:

    std::variant<std::size_t, std::monostate> results =
      co_await (
        async_read(socket, input_buffer, use_awaitable)
          || timer.async_wait(use_awaitable)
      );

The operators may be enabled by adding the #include:

    #include <asio/experimental/awaitable_operators.hpp>

and then bringing the contents of the experimental::awaitable_operators
namespace into scope:

    using namespace boost::asio::experimental::awaitable_operators;
2021-07-04 13:05:46 +10:00
klemens-morgenstern
ecca8406c0 Added experimental::coro class template.
The coro type is a C++20 coroutine primitive for resumable functions,
with the ability to combine both asynchronous waiting (co_await) and
yielding (co_yield) into a single, stateful control flow. For example:

    #include <boostasio.hpp>
    #include <boostasio/experimental/coro.hpp>

    using boost::asio::ip::tcp;

    boost::asio::experimental::coro<std::string> reader(tcp::socket& sock)
    {
      std::string buf;
      while (sock.is_open())
      {
        std::size_t n = co_await boost::asio::async_read_until(
            sock, boost::asio::dynamic_buffer(buf), '\n',
            boost::asio::experimental::use_coro);
        co_yield buf.substr(0, n);
        buf.erase(0, n);
      }
    }

    boost::asio::awaitable<void> consumer(tcp::socket sock)
    {
      auto r = reader(sock);
      auto msg1 = co_await r.async_resume(boost::asio::use_awaitable);
      std::cout << "Message 1: " << msg1.value_or("\n");
      auto msg2 = co_await r.async_resume(boost::asio::use_awaitable);
      std::cout << "Message 2: " << msg2.value_or("\n");
    }

    boost::asio::awaitable<void> listen(tcp::acceptor& acceptor)
    {
      for (;;)
      {
        co_spawn(
            acceptor.get_executor(),
            consumer(co_await acceptor.async_accept(boost::asio::use_awaitable)),
            boost::asio::detached);
      }
    }

    int main()
    {
      boost::asio::io_context ctx;
      tcp::acceptor acceptor(ctx, {tcp::v4(), 54321});
      co_spawn(ctx, listen(acceptor), boost::asio::detached);
      ctx.run();
    }
2021-07-01 21:34:51 +10:00
klemens-morgenstern
03ba758437 Added experimental::promise.
The experimental::promise type allows eager execution and
synchronisation of async operations.

    auto promise = async_read(
        stream, asio::buffer(my_buffer),
        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(
        asio::experimental::use_promise);

    auto read_promise = async_read(
        stream, asio::buffer(my_buffer),
        asio::experimental::use_promise);

    auto promise =
      asio::experimental::promise<>::race(
        timeout_promise, read_promise);

    promise.async_wait(
        [](std::variant<error_code, std::tuple<error_code, std::size_t>> 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, asio::buffer(my_write_buffer),
        asio::experimental::use_promise);

    auto read_promise = async_read(
        stream, asio::buffer(my_buffer),
        asio::experimental::use_promise);

    auto promise =
      asio::experimental::promise<>::all(
        write_promise, read_promise);

    promise.async_wait(
        [](std::tuple<error_code, std::size_t> write_result,
          std::tuple<error_code, std::size_t> read_result)
        {
        });
2021-07-01 15:40:28 +10:00