Skip to content

Commit 7a64f24

Browse files
16bit-ykikoclaude
andcommitted
fix(async): address review feedback on current-node tracking
- resume_and_drain now takes an explicit restore_to parameter so the correct previous node is restored even after handle_subtask_result / deliver_deferred overwrite the thread-local - async_node::current() returns const async_node* to prevent mutation of the live runtime node through the diagnostic API Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bc046c6 commit 7a64f24

File tree

3 files changed

+19
-10
lines changed

3 files changed

+19
-10
lines changed

include/eventide/async/runtime/frame.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@
1616

1717
namespace eventide {
1818

19+
class async_node;
1920
class sync_primitive;
2021

2122
namespace detail {
2223

2324
/// Resume a coroutine and immediately drain any deferred root-frame destruction.
24-
void resume_and_drain(std::coroutine_handle<> handle);
25+
/// @param restore_to The async_node* to write back into the thread-local
26+
/// current-node slot after the resumed chain returns.
27+
/// Callers must capture this **before** any call to
28+
/// handle_subtask_result / deliver_deferred, which
29+
/// overwrite the slot as part of symmetric-transfer setup.
30+
void resume_and_drain(async_node* restore_to, std::coroutine_handle<> handle);
2531

2632
} // namespace detail
2733

@@ -124,7 +130,7 @@ class async_node {
124130

125131
/// Returns the async_node whose coroutine body is currently executing on
126132
/// this thread, or nullptr if no coroutine is active.
127-
static async_node* current() noexcept;
133+
const static async_node* current() noexcept;
128134

129135
/// Convenience: calls dump_dot() on the current node. Returns an empty
130136
/// string if no coroutine is active.

src/async/runtime/frame.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async_node* detail::current_node() noexcept {
2020
return current_running_node;
2121
}
2222

23-
async_node* async_node::current() noexcept {
23+
const async_node* async_node::current() noexcept {
2424
return current_running_node;
2525
}
2626

@@ -63,11 +63,10 @@ void drain_pending_destroys() {
6363

6464
} // namespace
6565

66-
void detail::resume_and_drain(std::coroutine_handle<> handle) {
66+
void detail::resume_and_drain(async_node* restore_to, std::coroutine_handle<> handle) {
6767
if(handle) {
68-
auto* prev = current_running_node;
6968
handle.resume();
70-
current_running_node = prev;
69+
current_running_node = restore_to;
7170
}
7271
#if ETD_WORKAROUND_MSVC_COROUTINE_ASAN_UAF
7372
drain_pending_destroys();
@@ -137,8 +136,9 @@ void async_node::cancel() {
137136
return;
138137
}
139138

139+
auto* prev = current_running_node;
140140
auto next = awaiter->handle_subtask_result(link);
141-
detail::resume_and_drain(next);
141+
detail::resume_and_drain(prev, next);
142142
};
143143

144144
switch(kind) {
@@ -177,8 +177,9 @@ void async_node::cancel() {
177177
break;
178178
}
179179

180+
auto* prev = current_running_node;
180181
auto next = self->deliver_deferred();
181-
detail::resume_and_drain(next);
182+
detail::resume_and_drain(prev, next);
182183
break;
183184
}
184185

@@ -217,8 +218,9 @@ void system_op::complete() noexcept {
217218
if(!parent) {
218219
return;
219220
}
221+
auto* prev = current_running_node;
220222
auto next = parent->handle_subtask_result(this);
221-
detail::resume_and_drain(next);
223+
detail::resume_and_drain(prev, next);
222224
}
223225

224226
/// Wires this node as a child of `awaiter`. For Task nodes, sets state

src/async/runtime/sync.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ bool sync_primitive::cancel_waiter(waiter_link* link) noexcept {
6363
// than first stashing raw waiter pointers into a temporary container.
6464
link->state = async_node::Cancelled;
6565
link->policy = static_cast<async_node::Policy>(link->policy | async_node::InterceptCancel);
66+
auto* prev = detail::current_node();
6667
auto next = awaiting->handle_subtask_result(link);
67-
detail::resume_and_drain(next);
68+
detail::resume_and_drain(prev, next);
6869
return true;
6970
}
7071

0 commit comments

Comments
 (0)