Skip to content

Add quitter<T> stop-aware task type#237

Merged
mvandeberg merged 1 commit intocppalliance:developfrom
mvandeberg:pr/quitter
Mar 19, 2026
Merged

Add quitter<T> stop-aware task type#237
mvandeberg merged 1 commit intocppalliance:developfrom
mvandeberg:pr/quitter

Conversation

@mvandeberg
Copy link
Contributor

@mvandeberg mvandeberg commented Mar 19, 2026

quitter is a coroutine task type identical to task except it provides transparent cancellation. When the stop token is triggered, transform_awaiter::await_resume intercepts the stop before the coroutine body sees the result, throwing a sentinel exception that unwinds through RAII destructors to final_suspend. The coroutine author writes zero cancellation-handling code.

New files:

  • quitter.hpp: quitter class template
  • detail/stop_requested_exception.hpp: sentinel exception type
  • test/unit/quitter.cpp: 17 tests covering normal completion, exception propagation, stop interception at initial_suspend and during I/O, chain propagation, RAII verification, when_all/when_any integration with quitter children, timer cancellation, echo server shutdown, task/quitter mixing, and move semantics
  • example/quitter-shutdown: 4 concurrent workers doing simulated I/O, Ctrl+C stops all workers, RAII cleanup runs, shutdown latency printed (~100us)

Modified:

  • run_async.hpp: fix task frame leak in make_trampoline by moving destroy before invoke (prevents leak when invoke throws)
  • capy.hpp: add quitter.hpp include

Summary by CodeRabbit

  • New Features

    • Introduced quitter coroutine task type enabling responsive shutdown with automatic stop-token awareness, allowing coroutines to cleanly terminate when stop is requested
    • Added example program demonstrating graceful shutdown with signal handling, worker coroutines, and automatic resource cleanup on termination
  • Bug Fixes

    • Fixed coroutine frame memory management to properly handle cleanup during exception handling

quitter<T> is a coroutine task type identical to task<T> except it
provides transparent cancellation. When the stop token is triggered,
transform_awaiter::await_resume intercepts the stop before the
coroutine body sees the result, throwing a sentinel exception that
unwinds through RAII destructors to final_suspend. The coroutine
author writes zero cancellation-handling code.

New files:
- quitter.hpp: quitter<T> class template
- detail/stop_requested_exception.hpp: sentinel exception type
- test/unit/quitter.cpp: 17 tests covering normal completion,
  exception propagation, stop interception at initial_suspend
  and during I/O, chain propagation, RAII verification,
  when_all/when_any integration with quitter children,
  timer cancellation, echo server shutdown, task/quitter
  mixing, and move semantics
- example/quitter-shutdown: 4 concurrent workers doing simulated
  I/O, Ctrl+C stops all workers, RAII cleanup runs, shutdown
  latency printed (~100us)

Modified:
- run_async.hpp: fix task frame leak in make_trampoline by
  moving destroy before invoke (prevents leak when invoke
  throws)
- capy.hpp: add quitter.hpp include

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

📝 Walkthrough

Walkthrough

The changes introduce boost::capy::quitter<>, a new stop-aware lazy coroutine task type that checks stop tokens before execution and at suspension points. Supporting infrastructure includes a sentinel exception type for stop signaling and exception handling via RAII guards. A complete example demonstrates responsive shutdown with worker coroutines and resource cleanup.

Changes

Cohort / File(s) Summary
Quitter Core Type
include/boost/capy/quitter.hpp
New public coroutine promise type implementing stop-token awareness via initial_suspend and transform_awaitable checks. Throws stop_requested_exception on stop and provides exception() and stopped() accessors for state inspection.
Stop Sentinel Infrastructure
include/boost/capy/detail/stop_requested_exception.hpp
New lightweight sentinel struct to represent stop request events, used for control flow in quitter promise exception handling.
Exception Handling Enhancement
include/boost/capy/ex/run_async.hpp
Replaced explicit frame destruction with RAII frame_guard to ensure coroutine cleanup on exception paths, including handler rethrows.
Master Header Integration
include/boost/capy.hpp
Added inclusion of boost/capy/quitter.hpp to expose quitter functionality via the umbrella header.
Example Build Configuration
example/CMakeLists.txt
Added add_subdirectory(quitter-shutdown) to incorporate new example into build system.
Quitter Example Setup
example/quitter-shutdown/CMakeLists.txt
New CMake configuration defining capy_example_quitter_shutdown executable target, collecting sources and linking against Boost::capy.
Responsive Shutdown Example
example/quitter-shutdown/quitter_shutdown.cpp
Complete example demonstrating signal handling, worker coroutines with stop-token integration, RAII resource guards, and shutdown latency reporting via atomic counters and latches.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/Signal
    participant SigHandler as Signal Handler
    participant StopSrc as stop_source
    participant Workers as Worker Coroutines
    participant StopToken as stop_token
    participant Resources as resource_guard
    participant Main as main()

    User ->> SigHandler: SIGINT/SIGTERM
    SigHandler ->> StopSrc: request_stop()
    StopSrc ->> StopToken: marks stop requested
    
    Workers ->> StopToken: check stop_requested() at suspension
    alt Stop Requested
        Workers ->> Workers: throw stop_requested_exception
        Workers ->> Resources: destructor (cleanup)
        Resources ->> Main: increment cleanup_count
        Workers ->> Main: coroutine completes
    else Continue
        Workers ->> Workers: co_await delay(...)
        Workers ->> Workers: process work
    end
    
    Main ->> Main: latch.wait() for all workers
    Main ->> Main: print results & latency
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Whiskers twitch with delight:
A quitter that knows when to stop,
Signals dance, resources hop,
RAII guards hold cleanup tight—
Shutdown's never been more right! ✨

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add quitter stop-aware task type' directly and specifically describes the main change—introducing a new coroutine task type with stop-token awareness, which is the primary focus of the entire pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can make CodeRabbit's review stricter and more nitpicky using the `assertive` profile, if that's what you prefer.

Change the reviews.profile setting to assertive to make CodeRabbit's nitpick more issues in your PRs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
include/boost/capy/quitter.hpp (1)

71-84: Consider adding a usage example to the class javadoc.

Per coding guidelines, type documentation should include @par Example with a code block showing typical usage. A brief snippet would help users understand the stop-token integration pattern.

📝 Suggested addition
    `@par` Example
    `@code`
    capy::quitter<int> fetch_data()
    {
        auto [ec, data] = co_await async_read(...);
        // If stop_token triggered, we never reach here — RAII runs.
        co_return process(data);
    }

    // Launch with stop token
    std::stop_source src;
    run_async(ex, src.get_token())(fetch_data());
    // Later: src.request_stop();
    `@endcode`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/capy/quitter.hpp` around lines 71 - 84, Add a short usage
example to the quitter<T> class javadoc by appending an "@par Example" section
that demonstrates typical stop-token integration: show a minimal coroutine
function returning capy::quitter<int> (or quitter<> for void) that uses co_await
(e.g., awaiting async_read) and co_return, and show launching it with a
std::stop_source and passing src.get_token() to the runner; reference the class
name quitter and its promise_type/stop-token behavior in the prose so readers
can correlate the example with the documented stopped behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@include/boost/capy/quitter.hpp`:
- Around line 71-84: Add a short usage example to the quitter<T> class javadoc
by appending an "@par Example" section that demonstrates typical stop-token
integration: show a minimal coroutine function returning capy::quitter<int> (or
quitter<> for void) that uses co_await (e.g., awaiting async_read) and
co_return, and show launching it with a std::stop_source and passing
src.get_token() to the runner; reference the class name quitter and its
promise_type/stop-token behavior in the prose so readers can correlate the
example with the documented stopped behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d42c9dba-185f-42ea-9f09-eb754c590100

📥 Commits

Reviewing files that changed from the base of the PR and between 721b47e and 5326ab3.

⛔ Files ignored due to path filters (1)
  • test/unit/quitter.cpp is excluded by !**/test/**
📒 Files selected for processing (7)
  • example/CMakeLists.txt
  • example/quitter-shutdown/CMakeLists.txt
  • example/quitter-shutdown/quitter_shutdown.cpp
  • include/boost/capy.hpp
  • include/boost/capy/detail/stop_requested_exception.hpp
  • include/boost/capy/ex/run_async.hpp
  • include/boost/capy/quitter.hpp

@cppalliance-bot
Copy link

An automated preview of the documentation is available at https://237.capy.prtest3.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-03-19 22:41:52 UTC

@mvandeberg mvandeberg merged commit 83e966c into cppalliance:develop Mar 19, 2026
36 of 37 checks passed
@codecov
Copy link

codecov bot commented Mar 19, 2026

Codecov Report

❌ Patch coverage is 93.87755% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.39%. Comparing base (2893a04) to head (5326ab3).
⚠️ Report is 2 commits behind head on develop.

Files with missing lines Patch % Lines
include/boost/capy/quitter.hpp 93.81% 6 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #237      +/-   ##
===========================================
+ Coverage    92.11%   92.39%   +0.28%     
===========================================
  Files          166      168       +2     
  Lines         9144     9327     +183     
===========================================
+ Hits          8423     8618     +195     
+ Misses         721      709      -12     
Flag Coverage Δ
linux 92.35% <ø> (+0.26%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
include/boost/capy/ex/run_async.hpp 87.39% <100.00%> (+1.80%) ⬆️
include/boost/capy/quitter.hpp 93.81% <93.81%> (ø)

... and 7 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2893a04...5326ab3. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants