Repository navigation
feat!: move quitter out of the library into an example - #481
Conversation
|
An automated preview of the documentation is available at https://481.capy.prtest3.cppalliance.org/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-11-03 21:31:28 UTC |
|
GCOVR code coverage report https://481.capy.prtest3.cppalliance.org/gcovr/index.html Build time: 2026-11-03 21:59:30 UTC |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #481 +/- ##
===========================================
- Coverage 98.51% 98.46% -0.05%
===========================================
Files 137 135 -2
Lines 7484 7250 -234
===========================================
- Hits 7373 7139 -234
Misses 111 111
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 5 files with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
e88d1df to
2b1945c
Compare
The example quitter ends at the co_await it is suspended in when a stop is requested, without resuming its body and without throwing. The quitter that sees the stop stores canceled as the result of the topmost quitter in its run and resumes whatever awaited it, which then destroys the suspended frames from the top. Operations resume a gate frame, which applies the operation-decides rule before the body runs. It needs no hooks in the library: a launched or task-awaited quitter must have T = results<...> or std::error_code, enforced by the quitter itself. Includes the shutdown and deep call chain demos and a self-checking program for the stop, race and teardown cases.
quitter now lives in example/early-quitter, which needs nothing from the library beyond the public coroutine protocol. Removing it also removes stop_requested_exception, so the default error handler no longer catches a cancellation exception, and await_ready_then_suspend loses the out-parameter only quitter used. The quitter-shutdown example moves to example/early-quitter.
2b1945c to
a0dea4e
Compare
This PR removes
quitterfrom the library and keeps it as an example built only on capy's public coroutine protocol. It answers the design question in #431 (quitter's place in the library) with the "remove" option, while keeping the pattern available as example code.Supersedes #478: with quitter out of the library, the library hooks that #478 adds for it are no longer needed.
Why
quitterneeds special support from the library, and nothing else uses that support:stop_requested_exception), which the default error handler catches, so cancellation is reported through exception control flow;chain_owner, and stop handling inrunandrun_async.The review questioned whether it belongs in the library, and no in-org library (corosio, http, beast2) uses it. Removing it shrinks the library. Keeping it as an example shows that the pattern can be built outside the library.
The example quitter (
example/early-quitter)A stop ends the quitter at the
co_awaitit is suspended in, without resuming its body and without throwing:canceledas that quitter's result, and resumes whatever awaited it (run_async,run, a task, orwhen_all). To that awaiter the quitter simply completed. Destroying the top quitter then destroys the suspended frames below it, so RAII runs at every level.resultsorerror_codeends the quitter, and any other result is delivered, with the stop landing at the nextco_await.T=results<...>orstd::error_code. The quitter's ownset_continuationandawait_suspendenforce this with astatic_assert, so the launchers need no changes.Contents:
quitter.hpp: the typeshutdown.cpp: the formerquitter-shutdownexample, portedmain.cpp: a deep call chain (worker, item, fetch/store, wait)checks.cpp: a self-checking program, registered withadd_testso CI runs it, for these cases:co_awaitthat never starts the operation;await_resume;when_all.Locally, the checks pass under clang ASan/UBSan and TSan and under GCC
-O2 -Werror. I also broke the header on purpose in three ways to confirm the checks catch each one.Library changes
quitter.hpp,detail/stop_requested_exception.hpp,test/unit/quitter.cpp,example/quitter-shutdownanddoc/quitter.md.default_handlernow just rethrows a non-nullexception_ptr, since there is no cancellation exception left to filter.await_ready_then_suspendloses thecompletedout-parameter, which only quitter used.mrdocs.ymland the doc-lint baseline.This is a breaking change:
boost::capy::quitterno longer exists.Performance
A ready
co_awaitin a tight loop (clang -O3, pinned to one core, no function alignment, so expect about ±15% layout noise):taskKnown gaps compared with #478
run_asyncthat is after the handler returns, whereas a task's locals are gone before its handler runs. Code that signals completion from the handler must wait for the executor's work (for examplethread_pool::join) before touching state the quitter's destructors use. The shutdown demo does this.co_await, which then stops. feat!: stop a quitter by abandoning its frames #478 stops before the body starts.results<Ts...>needs default-constructibleTs.run(ex)across executors,when_any, strand and mutex handoff.CI
On the fork, every Linux and MSVC job passes. Of the macOS jobs, tsan passes. The other three macOS jobs never started on any attempt, because GitHub had no hosted macOS runner capacity, so they still need a run.