Skip to content

feat(async): track current running coroutine for graph export#80

Closed
16bit-ykiko wants to merge 2 commits intomainfrom
feat/current-node-tracking
Closed

feat(async): track current running coroutine for graph export#80
16bit-ykiko wants to merge 2 commits intomainfrom
feat/current-node-tracking

Conversation

@16bit-ykiko
Copy link
Copy Markdown
Member

@16bit-ykiko 16bit-ykiko commented Mar 29, 2026

Summary

  • Add a thread_local async_node* that tracks which coroutine is currently executing on each thread
  • Expose async_node::current() and async_node::dump_current_dot() public API so user code inside any coroutine can export the async graph on demand
  • Set the thread-local via initial_tracking_suspend (first entry), save/restore in resume() / resume_and_drain() (entry points), and direct assignment in handle_subtask_result() / deliver_deferred() / propagate_fail() (symmetric transfer)

Test plan

  • All 643 existing unit tests pass
  • CI passes on all platforms

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added public APIs for introspection of currently executing async nodes: async_node::current() to retrieve the active coroutine node and async_node::dump_current_dot() for state visualization.
  • Tests

    • Expanded callable type tests with new tracked callable variants and comprehensive destructor correctness verification across move operations and storage types.

16bit-ykiko and others added 2 commits March 23, 2026 16:00
…d edge cases

Add 18 new test cases for function/function_ref:
- Destructor tracking: verify no double-free or leak for SBO and heap
  storage across construct, move-construct, move-assign, and move chains
- Cross-storage move assignment: SBO↔heap, fnptr↔SBO transitions
  with leak detection via TrackedCallable/LargeTrackedCallable
- Self-move assignment: SBO and heap paths
- function_ref: mutable lambda, reassign, bind_ref mutation visibility
- Complex types: string return, multiple arguments, bind const mem_fn

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ph export

Add a thread-local async_node* that always points to the coroutine
currently executing on this thread. This allows calling
async_node::current() or async_node::dump_current_dot() from anywhere
inside a coroutine body to export the async graph on demand.

Tracking points:
- initial_tracking_suspend sets the node on first coroutine entry
- async_node::resume() and resume_and_drain() save/restore around resumes
- handle_subtask_result(), deliver_deferred(), propagate_fail() set the
  node before returning a handle for symmetric transfer

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

coderabbitai bot commented Mar 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e76372c0-46af-484e-a337-177819a0e7ad

📥 Commits

Reviewing files that changed from the base of the PR and between 37dc1ed and 0a88804.

📒 Files selected for processing (4)
  • include/eventide/async/runtime/frame.h
  • include/eventide/async/runtime/task.h
  • src/async/runtime/frame.cpp
  • tests/unit/common/functional_tests.cpp

📝 Walkthrough

Walkthrough

This PR introduces thread-local tracking of the currently executing async_node across the coroutine runtime. It adds public APIs (async_node::current(), async_node::dump_current_dot()) and internal detail functions (set_current_node(), current_node()) to track active coroutine nodes. Task coroutine initialization is modified to establish node context, and resume/drain operations now preserve and restore the prior node state through save/restore pairs.

Changes

Cohort / File(s) Summary
Async Node API Declarations
include/eventide/async/runtime/frame.h
Added static methods async_node::current() and async_node::dump_current_dot() to query the active node on the current thread, plus detail-level set_current_node() and current_node() functions for internal tracking management.
Task Coroutine Initialization
include/eventide/async/runtime/task.h
Replaced std::suspend_always in task_promise_object::initial_suspend() with initial_tracking_suspend awaitable that establishes the current async_node on first coroutine activation. Updated detail::propagate_fail() to set current node context before returning parent coroutine handle during exception propagation.
Thread-Local Tracking Implementation
src/async/runtime/frame.cpp
Implemented thread-local storage (current_running_node) and four new APIs. Enhanced detail::resume_and_drain() and async_node::resume() to save/restore prior node state. Set current node in aggregation delivery paths (aggregate_op::deliver_deferred()) and parent notification paths (async_node::handle_subtask_result()).
Functional Tests
tests/unit/common/functional_tests.cpp
Added tracker-based callable structs and comprehensive test cases verifying destructor correctness across SBO/heap storage, move semantics, cross-storage moves, self-assignment, and function_ref/function behavior with various callable types.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant TaskCoro as Task<br/>Coroutine
    participant AsyncNode as async_node
    participant ThreadLocal as Thread-Local<br/>Storage
    
    Caller->>TaskCoro: co_await task
    TaskCoro->>TaskCoro: initial_suspend()
    TaskCoro->>ThreadLocal: set_current_node(this_node)
    ThreadLocal-->>TaskCoro: ✓
    TaskCoro-->>Caller: suspend, return handle
    
    Caller->>AsyncNode: resume()
    AsyncNode->>ThreadLocal: save prior current_node
    ThreadLocal-->>AsyncNode: prior_node
    AsyncNode->>TaskCoro: handle().resume()
    TaskCoro->>TaskCoro: coroutine body executes
    TaskCoro-->>AsyncNode: returns
    AsyncNode->>ThreadLocal: restore prior_node
    ThreadLocal-->>AsyncNode: ✓
    AsyncNode-->>Caller: ✓
    
    Note over TaskCoro,ThreadLocal: Exception path:<br/>propagate_fail() also<br/>sets current_node before<br/>resuming parent
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • fogsong233

Poem

🐰 A thread remembers which node hops along,
Save before resume, restore when done—strong!
No node left behind, context preserved tight,
Coroutines dance in their thread-local light.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 directly and clearly summarizes the main change: adding thread-local tracking of the current executing coroutine node to enable graph export via public APIs.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/current-node-tracking

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.

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.

1 participant