feat: support actions on the Tokio executor (Tokio Executor 3/3)#655
Draft
azerupi wants to merge 3 commits into
Draft
feat: support actions on the Tokio executor (Tokio Executor 3/3)#655azerupi wants to merge 3 commits into
azerupi wants to merge 3 commits into
Conversation
Add an opt-in way for primitives to report readiness via rcl's push callbacks (rcl_*_set_on_new_*_callback) instead of being polled in a wait set, as the foundation for an event-driven executor. `RclPrimitive::register_on_ready` installs a callback that the middleware invokes when the entity becomes ready and returns an `OnReadyHandle` (RAII) that deregisters on drop. `OnReadyRegistration` wraps the unsafe rcl setter: it boxes the callback context for a stable address and, on drop, clears the callback before freeing the context (finalizing the rcl entity first) so the middleware can never invoke a freed context during teardown. Implemented for subscriptions, services, and clients. No executor consumes this yet, so the basic executor is unchanged.
Add a Tokio-based executor (opt-in via the `tokio-executor` feature, enabled by default) that learns entity readiness from the rcl push callbacks added in the previous commit instead of polling rcl_wait. Each Worker drains its own mailbox on a dedicated Tokio task, so one Worker's callbacks are serialized and ordered while independent Workers run concurrently across Tokio's thread pool — multi-core concurrency with no per-event task spawn. Subscriptions, services, and clients are driven by push callbacks; timers by tokio::time. Worker tasks are gated by spinning (callbacks only run while spinning, and spin() waits for in-flight callbacks before returning); spin() honors only_next_available_work (spin_once) and reports a timeout as a Timeout error, matching the basic executor. Notifications coalesce per entity to bound the mailbox, a panicking callback is contained rather than wedging the worker, and push-callback registrations finalize the rcl entity before freeing their context to avoid a teardown use-after-free. Opt out with `default-features = false` to drop the Tokio multi-threaded runtime and macros for a lighter build. Action support follows in a separate commit.
0dd9e5b to
dfccf93
Compare
This was referenced Jun 21, 2026
e11770b to
c77caf9
Compare
Drive action servers and clients with rcl's action push callbacks (rcl_action_*_set_*_callback) on the event-driven executor. An action is a composite primitive: each internal source (the server's goal/cancel/result services; the client's feedback/status subscriptions and goal/cancel/result clients) registers its own push callback tagged with the ReadyKind flag it satisfies. Because the notifications for one action coalesce into a single mailbox wakeup, the executor accumulates a merged ReadyKind per entity and runs the primitive with it. Goal expiration has no push callback, so the server polls it on a coarse interval. Adds end-to-end tests for a goal round-trip (feedback + result) and for cancellation on the Tokio executor. Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Note: This is based on #654 , I was hoping I could target that PR as base branch but that seems to only work if the branches are in the ros2_rust repo and not in my fork.
This is part of a set of PRs that attempt to add an event-driven Tokio executor to rclrs. The goal is to have something that:
I tried to split the work up into multiple PRs that build on top of each other to make the reviewing easier.
support actions on the Tokio executor
This extends the event-driven Tokio executor to action servers and clients via the
rcl_actionpush callbacks. It rounds out primitive coverage so the Tokio executor handles the same entity kinds as the basic executor.An action is a composite primitive. A server bundles three services (goal, cancel, result). A client bundles two subscriptions (feedback, status) and three service clients (goal, cancel, result). Each internal source gets its own push callback, tagged with the readiness flag it satisfies, so the executor knows which part of the action became ready.
Because notifications for one entity coalesce, the executor cannot assume each mailbox message maps to a single source. It accumulates merged readiness per action entity: each notification ORs its flag in, and the worker takes the merged value when it runs the primitive. Single-path primitives (everything except actions) keep the cheaper path.
Goal expiration has no push callback. rcl drives it from an internal timer. The server polls it on a coarse interval. That is acceptable because expiration only bounds how promptly a completed goal is cleaned up, well after its result
timeout.