1[/ 2 / Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 3 / 4 / Distributed under the Boost Software License, Version 1.0. (See accompanying 5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 /] 7 8[section:asynchronous_operations Requirements on asynchronous operations] 9 10This section uses the names `Alloc1`, `Alloc2`, `alloc1`, `alloc2`, `Args`, 11`CompletionHandler`, `completion_handler`, `Executor1`, `Executor2`, `ex1`, 12`ex2`, `f`, [^['i]], [^['N]], `Signature`, `token`, [^T[sub ['i]]], [^t[sub 13['i]]], `work1`, and `work2` as placeholders for specifying the requirements 14below. 15 16[heading General asynchronous operation concepts] 17 18An ['initiating function] is a function which may be called to start an 19asynchronous operation. A ['completion handler] is a function object that will 20be invoked, at most once, with the result of the asynchronous operation. 21 22The lifecycle of an asynchronous operation is comprised of the following events 23and phases: 24 25[mdash] Event 1: The asynchronous operation is started by a call to the 26initiating function. 27 28[mdash] Phase 1: The asynchronous operation is now ['outstanding]. 29 30[mdash] Event 2: The externally observable side effects of the asynchronous 31operation, if any, are fully established. The completion handler is submitted 32to an executor. 33 34[mdash] Phase 2: The asynchronous operation is now ['completed]. 35 36[mdash] Event 3: The completion handler is called with the result of the 37asynchronous operation. 38 39In this library, all functions with the prefix `async_` are initiating 40functions. 41 42[heading Completion tokens and handlers] 43 44Initiating functions: 45 46[mdash] are function templates with template parameter `CompletionToken`; 47 48[mdash] accept, as the final parameter, a ['completion token] object `token` 49of type `CompletionToken`; 50 51[mdash] specify a ['completion signature], which is a call signature (C++Std 52[func.def]) `Signature` that determines the arguments to the completion 53handler. 54 55An initiating function determines the type `CompletionHandler` of its 56completion handler function object by performing `typename 57async_result<decay_t<CompletionToken>, Signature>::completion_handler_type`. 58The completion handler object `completion_handler` is initialized with 59`forward<CompletionToken>(token)`. [inline_note No other requirements are 60placed on the type `CompletionToken`.] 61 62The type `CompletionHandler` must satisfy the requirements of `Destructible` 63(C++Std [destructible]) and `MoveConstructible` (C++Std 64[moveconstructible]), and be callable with the specified call signature. 65 66In this library, all initiating functions specify a ['Completion signature] 67element that defines the call signature `Signature`. The ['Completion 68signature] elements in this Technical Specification have named parameters, and 69the results of an asynchronous operation are specified in terms of these names. 70 71[heading Automatic deduction of initiating function return type] 72 73The return type of an initiating function is `typename 74async_result<decay_t<CompletionToken>, Signature>::return_type`. 75 76For the sake of exposition, this library sometimes annotates functions with a 77return type ['[^DEDUCED]]. For every function declaration that returns 78['[^DEDUCED]], the meaning is equivalent to specifying the return type as 79`typename async_result<decay_t<CompletionToken>, Signature>::return_type`. 80 81[heading Production of initiating function return value] 82 83An initiating function produces its return type as follows: 84 85[mdash] constructing an object `result` of type 86`async_result<decay_t<CompletionToken>, Signature>`, initialized as 87`result(completion_handler)`; and 88 89[mdash] using `result.get()` as the operand of the return statement. 90 91\[['Example:] Given an asynchronous operation with ['Completion signature] 92`void(R1 r1, R2 r2)`, an initiating function meeting these requirements may be 93implemented as follows: 94 95 template<class CompletionToken> 96 auto async_xyz(T1 t1, T2 t2, CompletionToken&& token) 97 { 98 typename async_result<decay_t<CompletionToken>, void(R1, R2)>::completion_handler_type 99 completion_handler(forward<CompletionToken>(token)); 100 101 async_result<decay_t<CompletionToken>, void(R1, R2)> result(completion_handler); 102 103 // initiate the operation and cause completion_handler to be invoked with 104 // the result 105 106 return result.get(); 107 } 108 109For convenience, initiating functions may be implemented using the 110`async_completion` template: 111 112 template<class CompletionToken> 113 auto async_xyz(T1 t1, T2 t2, CompletionToken&& token) 114 { 115 async_completion<CompletionToken, void(R1, R2)> init(token); 116 117 // initiate the operation and cause init.completion_handler to be invoked 118 // with the result 119 120 return init.result.get(); 121 } 122 123'''—'''['end example]\] 124 125[heading Lifetime of initiating function arguments] 126 127Unless otherwise specified, the lifetime of arguments to initiating functions 128shall be treated as follows: 129 130[mdash] If the parameter has a pointer type or has a type of lvalue reference 131to non-const, the implementation may assume the validity of the pointee or 132referent, respectively, until the completion handler is invoked. [inline_note 133In other words, the program must guarantee the validity of the argument until 134the completion handler is invoked.] 135 136[mdash] Otherwise, the implementation must not assume the validity of the 137argument after the initiating function completes. [inline_note In other words, 138the program is not required to guarantee the validity of the argument after the 139initiating function completes.] The implementation may make copies of the 140argument, and all copies shall be destroyed no later than immediately after 141invocation of the completion handler. 142 143[heading Non-blocking requirements on initiating functions] 144 145An initiating function shall not block (C++Std [defns.block]) the calling 146thread pending completion of the outstanding operation. 147 148[std_note Initiating functions may still block the calling thread for other 149reasons. For example, an initiating function may lock a mutex in order to 150synchronize access to shared data.] 151 152[heading Associated executor] 153 154Certain objects that participate in asynchronous operations have an 155['associated executor]. These are obtained as specified in the sections below. 156 157[heading Associated I/O executor] 158 159An asynchronous operation has an associated executor satisfying the [link 160boost_asio.reference.Executor1 `Executor`] requirements. If not otherwise specified by 161the asynchronous operation, this associated executor is an object of type 162`system_executor`. 163 164All asynchronous operations in this library have an associated executor object 165that is determined as follows: 166 167[mdash] If the initiating function is a member function, the associated 168executor is that returned by the `get_executor` member function on the same 169object. 170 171[mdash] If the initiating function is not a member function, the associated 172executor is that returned by the `get_executor` member function of the first 173argument to the initiating function. 174 175Let `Executor1` be the type of the associated executor. Let `ex1` be a value of 176type `Executor1`, representing the associated executor object obtained as 177described above. 178 179[heading Associated completion handler executor] 180 181A completion handler object of type `CompletionHandler` has an associated 182executor of type `Executor2` satisfying the [link boost_asio.reference.Executor1 183Executor requirements]. The type `Executor2` is 184`associated_executor_t<CompletionHandler, Executor1>`. Let `ex2` be a value of 185type `Executor2` obtained by performing 186`get_associated_executor(completion_handler, ex1)`. 187 188[heading Outstanding work] 189 190Until the asynchronous operation has completed, the asynchronous operation 191shall maintain: 192 193[mdash] an object `work1` of type `executor_work_guard<Executor1>`, initialized 194as `work1(ex1)`, and where `work1.owns_work() == true`; and 195 196[mdash] an object `work2` of type `executor_work_guard<Executor2>`, initialized 197as `work2(ex2)`, and where `work2.owns_work() == true`. 198 199[heading Allocation of intermediate storage] 200 201Asynchronous operations may allocate memory. [inline_note Such as a data 202structure to store copies of the `completion_handler` object and the initiating 203function's arguments.] 204 205Let `Alloc1` be a type, satisfying the [link boost_asio.reference.ProtoAllocator 206`ProtoAllocator`] requirements, that represents the asynchronous operation's 207default allocation strategy. [inline_note Typically `std::allocator<void>`.] 208Let `alloc1` be a value of type `Alloc1`. 209 210A completion handler object of type `CompletionHandler` has an associated 211allocator object `alloc2` of type `Alloc2` satisfying the [link 212boost_asio.reference.ProtoAllocator `ProtoAllocator`] requirements. The type `Alloc2` 213is `associated_allocator_t<CompletionHandler, Alloc1>`. Let `alloc2` be a value 214of type `Alloc2` obtained by performing 215`get_associated_allocator(completion_handler, alloc1)`. 216 217The asynchronous operations defined in this library: 218 219[mdash] If required, allocate memory using only the completion handler's 220associated allocator. 221 222[mdash] Prior to completion handler execution, deallocate any memory allocated 223using the completion handler's associated allocator. 224 225[std_note The implementation may perform operating system or underlying API 226calls that perform memory allocations not using the associated allocator. 227Invocations of the allocator functions may not introduce data races (See C++Std 228\[res.on.data.races\]).] 229 230[heading Execution of completion handler on completion of asynchronous operation] 231 232Let `Args...` be the argument types of the completion signature `Signature` and 233let [^['N]] be `sizeof...(Args)`. Let [^['i]] be in the range [half_open_range 234`0`,[^['N]]]. Let [^T[sub ['i]]] be the [^['i]]th type in `Args...` and let 235[^t[sub ['i]]] be the [^['i]]th completion handler argument associated with 236[^T[sub ['i]]]. 237 238Let `f` be a function object, callable as `f()`, that invokes 239`completion_handler` as if by [^completion_handler(forward<T[sub ['0]]>(t[sub 240['0]]), ..., forward<T[sub ['N-1]]>(t[sub ['N-1]]))]. 241 242If an asynchonous operation completes immediately (that is, within the thread 243of execution calling the initiating function, and before the initiating 244function returns), the completion handler shall be submitted for execution as 245if by performing `ex2.post(std::move(f), alloc2)`. Otherwise, the completion 246handler shall be submitted for execution as if by performing 247`ex2.dispatch(std::move(f), alloc2)`. 248 249[heading Completion handlers and exceptions] 250 251Completion handlers are permitted to throw exceptions. The effect of any 252exception propagated from the execution of a completion handler is determined 253by the executor which is executing the completion handler. 254 255[heading Default completion tokens] 256 257Every I/O executor type has an associated default completion token type. This is 258specified via the `default_completion_token` trait. This trait may be used in 259asynchronous operation declarations as follows: 260 261 template < 262 typename IoObject, 263 typename CompletionToken = 264 typename default_completion_token< 265 typename IoObject::executor_type 266 >::type 267 > 268 auto async_xyz( 269 IoObject& io_object, 270 CompletionToken&& token = 271 typename default_completion_token< 272 typename IoObject::executor_type 273 >::type{} 274 ); 275 276If not specialised, this trait type is `void`, meaning no default completion 277token type is available for the given I/O executor. 278 279\[['Example:] The `default_completion_token` trait is specialised for the 280`use_awaitable` completion token so that it may be used as shown in the 281following example: 282 283 auto socket = use_awaitable.as_default_on(tcp::socket(my_context)); 284 // ... 285 co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable. 286 287In this example, the type of the `socket` object is transformed from 288`tcp::socket` to have an I/O executor with the default completion token set to 289`use_awaitable`. 290 291Alternatively, the socket type may be computed directly: 292 293 using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>; 294 tcp_socket socket(my_context); 295 // ... 296 co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable. 297 298'''—'''['end example]\] 299 300[endsect] 301