1.. _module-pw_async2: 2 3============= 4pw_async2 5============= 6.. pigweed-module:: 7 :name: pw_async2 8 9 - **Simple Ownership**: Say goodbye to that jumble of callbacks and shared 10 state! Complex tasks with many concurrent elements can be expressed by 11 simply combining smaller tasks. 12 - **Efficient**: No dynamic memory allocation required. 13 - **Pluggable**: Your existing event loop, work queue, or task scheduler 14 can run the ``Dispatcher`` without any extra threads. 15 - **Coroutine-capable**: C++20 coroutines and Rust ``async fn`` work just 16 like other tasks, and can easily plug into an existing ``pw_async2`` 17 systems. 18 19:cpp:class:`pw::async2::Task` is Pigweed's async primitive. ``Task`` objects 20are cooperatively-scheduled "threads" which yield to the 21:cpp:class:`pw::async2::Dispatcher` when waiting. When the ``Task`` is able to make 22progress, the ``Dispatcher`` will run it again. For example: 23 24.. code-block:: cpp 25 26 #include "pw_async2/dispatcher.h" 27 #include "pw_async2/poll.h" 28 29 #include "pw_result/result.h" 30 31 using ::pw::async2::Context; 32 using ::pw::async2::Poll; 33 using ::pw::async2::Ready; 34 using ::pw::async2::Pending; 35 using ::pw::async2::Task; 36 37 class ReceiveAndSend: public Task { 38 public: 39 ReceiveAndSend(Receiver receiver, Sender sender): 40 receiver_(receiver), sender_(sender) {} 41 42 Poll<> Pend(Context& cx) { 43 if (!send_future_) { 44 // ``PendReceive`` checks for available data or errors. 45 // 46 // If no data is available, it will grab a ``Waker`` from 47 // ``cx.Waker()`` and return ``Pending``. When data arrives, 48 // it will call ``waker.Wake()`` which tells the ``Dispatcher`` to 49 // ``Pend`` this ``Task`` again. 50 Poll<pw::Result<Data>> new_data = receiver_.PendReceive(cx); 51 if (new_data.is_pending()) { 52 // The ``Task`` is still waiting on data. Return ``Pending``, 53 // yielding to the dispatcher. ``Pend`` will be called again when 54 // data becomes available. 55 return Pending(); 56 } 57 if (!new_data->ok()) { 58 PW_LOG_ERROR("Receiving failed: %s", data->status().str()); 59 // The ``Task`` completed; 60 return Ready(); 61 } 62 Data& data = **new_data; 63 send_future_ = sender_.Send(std::move(data)); 64 } 65 // ``PendSend`` attempts to send ``data_``, returning ``Pending`` if 66 // ``sender_`` was not yet able to accept ``data_``. 67 Poll<pw::Status> sent = send_future_.Pend(cx); 68 if (sent.is_pending()) { 69 return Pending(); 70 } 71 if (!sent->ok()) { 72 PW_LOG_ERROR("Sending failed: %s", sent->str()); 73 } 74 return Ready(); 75 } 76 private: 77 Receiver receiver_; 78 Sender sender_; 79 80 // ``SendFuture`` is some type returned by `Sender::Send` that offers a 81 // ``Pend`` method similar to the one on ``Task``. 82 std::optional<SendFuture> send_future_ = std::nullopt; 83 }; 84 85Tasks can then be run on a :cpp:class:`pw::async2::Dispatcher` using the 86:cpp:func:`pw::async2::Dispatcher::Post` method: 87 88.. code-block:: cpp 89 90 #include "pw_async2/dispatcher.h" 91 92 int main() { 93 ReceiveAndSendTask task(SomeMakeReceiverFn(), SomeMakeSenderFn()); 94 Dispatcher dispatcher; 95 dispatcher.Post(task); 96 dispatcher.RunUntilComplete(task); 97 return 0; 98 } 99 100.. _module-pw_async2-coroutines: 101 102---------- 103Coroutines 104---------- 105C++20 users can also define tasks using coroutines! 106 107.. literalinclude:: examples/coro.cc 108 :language: cpp 109 :linenos: 110 :start-after: [pw_async2-examples-coro-injection] 111 :end-before: [pw_async2-examples-coro-injection] 112 113Any value with a ``Poll<T> Pend(Context&)`` method can be passed to 114``co_await``, which will return with a ``T`` when the result is ready. 115 116To return from a coroutine, ``co_return <expression>`` must be used instead of 117the usual ``return <expression>`` syntax. Because of this, the 118:c:macro:`PW_TRY` and :c:macro:`PW_TRY_ASSIGN` macros are not usable within 119coroutines. :c:macro:`PW_CO_TRY` and :c:macro:`PW_CO_TRY_ASSIGN` should be 120used instead. 121 122For a more detailed explanation of Pigweed's coroutine support, see the 123documentation on the :cpp:class:`pw::async2::Coro<T>` type. 124 125----------------- 126C++ API reference 127----------------- 128.. doxygenclass:: pw::async2::Task 129 :members: 130 131.. doxygenclass:: pw::async2::Poll 132 :members: 133 134.. doxygenfunction:: pw::async2::Ready() 135 136.. doxygenfunction:: pw::async2::Ready(std::in_place_t, Args&&... args) 137 138.. doxygenfunction:: pw::async2::Ready(T&& value) 139 140.. doxygenfunction:: pw::async2::Pending() 141 142.. doxygenclass:: pw::async2::Context 143 :members: 144 145.. doxygenclass:: pw::async2::Waker 146 :members: 147 148.. doxygenclass:: pw::async2::Dispatcher 149 :members: 150 151.. doxygenclass:: pw::async2::Coro 152 :members: 153 154.. doxygenclass:: pw::async2::CoroContext 155 :members: 156 157------------- 158C++ Utilities 159------------- 160.. doxygenfunction:: pw::async2::AllocateTask(pw::allocator::Allocator& allocator, Pendable&& pendable) 161 162.. doxygenfunction:: pw::async2::AllocateTask(pw::allocator::Allocator& allocator, Args&&... args) 163 164.. doxygenclass:: pw::async2::PendFuncTask 165 :members: 166 167.. doxygenclass:: pw::async2::PendableAsTask 168 :members: 169 170.. toctree:: 171 :hidden: 172 :maxdepth: 1 173 174 Backends <backends> 175