Repository navigation
Track every waiting coroutine with Waiting - #65
Merged
Merged
Conversation
Each awaiter guarded its handed-out handle in its own way: Event and Mutex an active flag, send_request and send_goal a shared State with a done flag and a destructor, the streams a destructor clearing waiter_, Sleep a done flag, and register_cancel an is_done predicate plus a weak_ptr to the stop callback. All of them now hold a Waiting, and whoever resumes them a weak_ptr to it. Waiting's handle is taken once, which decides between completion and cancellation, and the weak_ptr expiring with the awaiter keeps a destroyed one from being resumed. resume_now, post_resume and register_cancel(waiting, action) are the three ways to resume it. The per-awaiter flags, State structs, is_done predicates and destructors go away, except GoalStream::NextAwaiter's, which still cancels the goal. TfBuffer drops a destroyed awaiter's request on the next check instead of in the destructor. No behavior change otherwise.
register_cancel deferred withdrawing it to the executor, so a send that arrived in between won and returned a value despite the stop request.
otamachan
force-pushed
the
unify-waiting
branch
from
October 18, 2026 06:17
2190345 to
9852436
Compare
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.
Follows #63 and #64. Refactor only; no behavior change intended.
Each awaiter guarded the handle it hands out in its own way:
EventandMutexanactiveflag,send_request/send_goala sharedStatewith adoneflag plus a destructor,TopicStream/GoalStreama destructor clearingwaiter_,Sleepadoneflag, andregister_cancelanis_donepredicate plus aweak_ptrto the stop callback. #63 and #64 addedWaitingfor the cases that had no guard.Now every awaiter owns a
Waiting, and whoever resumes it holds aweak_ptrto it:Waiting::take()hands the handle out once (atomic exchange). Whichever of completion and cancellation takes it first resumes the coroutine; this replaces theactive/doneflags and theis_donepredicates.weak_ptrexpires with the awaiter, so a destroyed awaiter is never resumed; this replaces the destructors.executor.hpp:resume_now(ctx, w): take and resume on the spot (Event::set,Mutex::unlock, stream messages, timer ticks, service responses).post_resume(ctx, w[, claimed]): take now, resume on the executor if the awaiter is still alive (TF, goal response,Channel::send/close, and the synchronous stop callbacks ofSleep,TimerStreamandChannel, which withdraw the waiter on the spot as before). Unlike Resume a posted waiter only while its awaiter is alive #63's version it takes at call time, as the replaceddoneflags were set at call time.register_cancel(out, token, ctx, waiting, action): on a stop request, post; if the handle is still there, runactionand resume.Removed: the
activeflags andWaiterstructs inEvent/Mutex, theStatestructs ofSendRequestAwaiter/SendGoalAwaiter(callbacks write into the awaiter only while itsWaitingis alive),PendingRequest::activeand~LookupTransformAwaiter(a destroyed awaiter's request is dropped on the nextcheck_pending),SleepAwaiter::done, and the destructors ofEvent,Mutex,SendRequest,SendGoal,TopicStreamandTfBufferawaiters.GoalStream::NextAwaiterkeeps its destructor, which still cancels the goal.Mutex::LockAwaiter::await_resumecheckedtoken.stop_requested() && !(active && *active).*activewas always false by the time the awaiter resumed (bothunlockand the cancellation cleared it), so this istoken.stop_requested(), which is what it checks now.colcon testpasses (354 tests, ASan build, LeakSanitizer off), including the tests added in #63 and #64.