Repository navigation
fix(coro): correctness v2, every co_await returns the caller, context and strand - #25
Merged
Merged
Conversation
- the rvalue overload extracted the handle into a non-owning awaiter, the frame leaked - an rvalue task binds to the const& overload, the temporary lives until the end of the full expression - the deleted copy assignment returns task_base&
- the scheduler lives in the promise, the payload is user data only (payload_base) - task awaiters read the caller's promise in await_suspend, no inject step - affine final awaiter: a task continues its parent on the parent's scheduler, also after an exception - one marker for awaiters that resume the caller themselves (this_coro_awaiter_base), await_transform passes them through - steal is dev::steal, it captures a foreign awaitable, the other overloads and executor::steal are removed - scheduled_task -> spawn_task with its own awaiter, the spawned task gets a fresh payload - tags receive the scheduler and the payload - native_handle_awaiter_base and osfence_awaiter_base are not templates - sync_executor_task is removed - a this_coro task awaited by a caller without this_coro is a compile error
- CTH_CRITICAL if called on a thread of its own scheduler, it would block a worker - the tests use it instead of their local helpers, the one in executor_test.cpp dropped exceptions of void tasks
- constexpr where a function can run at compile time, removed where it reads the clock or returns noop_coroutine() - payload copies (promise constructor, inherit, await_suspend of the task awaiter), raw_promise::return_value and data_awaiter::await_resume are noexcept if the copy is: a throwing copy reaches the caller instead of terminating
- abstract context: post, await (handle, time point), owns_thread - co::current_context(): the context whose job runs on the calling thread, exact for strand jobs - promise, awaiters, tags and executor work on context const&, this_coro::scheduler -> this_coro::context - the affine final awaiter and schedule() compare with current_context() - sync_wait has no CTH_CRITICAL, it documents the self wait
- strand is a context, its jobs run one at a time and in post order on the workers of its scheduler - strand jobs set current_context() to the strand while they run - shared asio helpers post_on and await_on, scheduler and strand implement their overrides with them
…ts value - dev::affine_promise<T> holds the affine final awaiter and parentContext together, they cannot be split anymore - the task awaiters set their own parts and call basic_promise_awaiter::await_suspend - raw_promise_base holds exception, continuation and unhandled_exception for both raw_promise versions - data_awaiter moves its value out in await_resume
…e caller - this_coro_promise_awaiter is the awaiter of executor, spawn and capture tasks - the per task part is the promise's attach(): affine default sets the parent context, executor also inherits, spawn falls back to its own context - dev::nothrow_attachable gives the noexcept of await_suspend - capture_promise_awaiter, spawn_promise_awaiter and the unused basic_final_promise_awaiter are removed
…ait pack, no lambda trick
- unpack_trait_t, first_pack_t and conditional_pack_t use partial specializations instead of consteval functions - about 2.6x faster on gcc and 15% on clang for 2000 instantiations - the consteval functions first_pack(), unpack_trait() and conditional_pack() are removed, the _t aliases stay - type_pack<T>: a pack that always unpacks to T
…ntext, cleanups - start() on an active scheduler deadlocked: the jthread assignment joined a running worker - affine_promise::parentContext -> callerContext, caller is the term in the docs - unused includes, forward declaration and namespace removed, wait_awaiter uses chrono::time_point_t
- context::await takes an await_func, the callback gets the error code of the wait - the wait handlers pass the error code instead of throwing on a worker, which terminated the program - timer_pool releases its timer before the callback, a failed wait leaked it - wait_awaiter_base keeps the error code until the caller resumes, its await_resume throws coro_exception - wait_awaiter -> time_point_awaiter, it and raw_native_handle_awaiter derive wait_awaiter_base - the awaiters of cth_net and cth_win call the base await_resume first
…HROW like the other modules
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #22 (reverted in the first commit) and #23.
Rule
Every
co_awaitreturns the caller to its context. Onlyschedule()moves the caller.Changes
task_basehas no rvalueoperator co_await: it leaked the framepayload_base)await_suspendthis_coro_awaiter_base)dev::stealonly captures foreign awaitables, the other steal overloads andexecutor::stealare removedscheduled_task->spawn_taskwith its own awaiter, the spawned task gets a fresh payloadthis_coro::scheduler->this_coro::contextexecutor::sync_wait(task, args...)sync_executor_taskis removednoexcept, new conceptsmta::nothrow_constructible,mta::nothrow_copy_constructiblemta::type_pack<T>; the consteval functions behind the_taliases are removedcontextinterface,co::current_context(),scheduler final : context,strand final : contextdev::affine_promise<T>holds the affine final awaiter andparentContexttogether, one awaiter for all tasks, the promise'sattach()does the per task part,raw_promise_baseholds the shared promise membersdata_awaitermoves its value outVerification (linux)