Skip to content

add support for reentrant callback group to EventsCBGExecutor#3178

Merged
jmachowinski merged 3 commits into
ros2:rollingfrom
armaho:events_cbg_executor_reentrant
Jul 16, 2026
Merged

add support for reentrant callback group to EventsCBGExecutor#3178
jmachowinski merged 3 commits into
ros2:rollingfrom
armaho:events_cbg_executor_reentrant

Conversation

@armaho

@armaho armaho commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #3175

Is this user-facing behavior change?

Did you use Generative AI?

No

Additional Information

Signed-off-by: Arman Hosseini <armahosseini878787@gmail.com>
@skyegalaxy
skyegalaxy requested review from jmachowinski and skyegalaxy and removed request for jmachowinski June 18, 2026 16:00

@skyegalaxy skyegalaxy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm with green CI. will let @jmachowinski take a pass as well

{
ready_callback_groups.erase(it);
}
return CBGScheduler::ExecutableEntityWithInfo{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

note to self to remove C++20 initialization when backporting this to Jazzy and Kilted specifically

@skyegalaxy

Copy link
Copy Markdown
Member

actually @armaho can you add a test which exercises the reentrant path like we discussed at the client library WG meeting?

@armaho

armaho commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

@skyegalaxy

Sure let me see how to test it.

@mergify

mergify Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

…er EventCBGExecutor

Signed-off-by: Arman Hosseini <armahosseini878787@gmail.com>
@armaho
armaho force-pushed the events_cbg_executor_reentrant branch from 554512d to 855d1b2 Compare June 19, 2026 13:29
@armaho

armaho commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

@skyegalaxy

I just added a test covering the reentrant callback group behavior. Could you take another look when you have time?

@jmachowinski jmachowinski left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sorry for the late reply.
I wonder if it makes sense to introduce a second class of callback handle, providing a seperate logic.
In this case the ready queue would be something like
std::deque<std::variant<ReentrantCallbackGroupHandle *, MutalExclusiveCallbackGroupHandle *>

Even though this would lead to some code duplication, I think it would make the code easier and better understandable in the end. The current approach of selectively doing things made it hard to understand what is going on.

I also think the compiler might optimize the variant better.

Comment thread rclcpp/src/rclcpp/executors/events_cbg_executor/first_in_first_out_scheduler.cpp Outdated
Comment thread rclcpp/src/rclcpp/executors/events_cbg_executor/scheduler.hpp Outdated
Comment on lines +234 to +252

// Reentrant callback groups might not be removed from the queue when one of
// their entities starts executing.
if (handle->get_type() == CallbackGroupType::Reentrant) {
bool already_in_queue = false;

for (auto it = ready_callback_groups.begin(); it != ready_callback_groups.end(); it++) {
if (*it == handle) {
already_in_queue = true;
break;
}
}

if (!already_in_queue) {
ready_callback_groups.push_back(handle);
}
} else {
ready_callback_groups.push_back(handle);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is a big no go, you introduce O(n) characteristics by searching the ready list.
This code should actually not be needed as the callback group handle should hold the information
if it is in the queue or not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I wasn't able to find anything in the handle itself that indicates whether it's in the queue or not. There was an idle field, but I had trouble using it to determine that. I ended up adding an in_queue field to the handle instead, which is simple to understand and implement. What do you think about that?

@skyegalaxy

Copy link
Copy Markdown
Member

@armaho - do you have bandwidth to respond to the feedback / still want to work on this?

@armaho

armaho commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@skyegalaxy Yes. Sorry I’ve been busy I will address the problems of current code and check out that variant idea tomorrow and get back to you with the results.

Signed-off-by: Arman Hosseini <armahosseini878787@gmail.com>
@armaho
armaho force-pushed the events_cbg_executor_reentrant branch from cfebaef to 490c6b0 Compare July 3, 2026 13:20
@armaho
armaho requested a review from jmachowinski July 3, 2026 13:29
@armaho

armaho commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@jmachowinski

I also think that the current implementation of EventCBGExecutor is hard to understand. At least, it was for me.

But I don't think that creating a separate handle for reentrant cbgs would help that much. Right now, the only conditional piece of code within the CallbackGroupHandle itself is inside mark_as_executing:

void mark_as_executing()
{
  if (type != CallbackGroupType::Reentrant) {
    not_ready = true;
  }
}

Which is not hard to understand, and I don't think that creating a separate handle would fundamentally reduce the conditional logic elsewhere in the code. To me, it doesn’t seem worth the amount of code duplication it would introduce.

That said, you know this codebase much better than I do, so I'll go in whichever direction you think is best.

@jmachowinski

Copy link
Copy Markdown
Collaborator

The commit looks good so far. I started playing around with the API to see if splitting the handle base class makes it more readable. I'll report back next week. Have a nice weekend.

@jmachowinski jmachowinski self-assigned this Jul 9, 2026
@jmachowinski

Copy link
Copy Markdown
Collaborator

Pulls: #3178
Gist: https://gist.githubusercontent.com/jmachowinski/263c67751e131d384f43e888d5e1d7e8/raw/3baffe34b4da0f4ab0f1c5da02d1a636647bd8cb/ros2.repos
BUILD args:
TEST args:
ROS Distro: rolling
Job: ci_launcher
ci_launcher ran: https://ci.ros2.org/job/ci_launcher/19863

  • Linux Build Status
  • Linux-aarch64 Build Status
  • Linux-rhel Build Status
  • Windows Build Status

@jmachowinski

jmachowinski commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

I don't have the capacity right now to look into making the code prettier.
Therefore I am going to merge this fix as it fixes the issue (if we get green CI).

Perhaps I'll have time later to play around with the code...

@armaho

armaho commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@skyegalaxy
@jmachowinski

Thank you both for your reviews. I'm working on ROS2 executors right now and I might come back here and work on this a bit further in the future.

Is there anything else I should do for now? :)

@jmachowinski
jmachowinski merged commit 0f0b693 into ros2:rolling Jul 16, 2026
3 checks passed
@jmachowinski

Copy link
Copy Markdown
Collaborator

@Mergifyio backport lyrical

@mergify

mergify Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

backport lyrical

✅ Backports have been created

Details

@skyegalaxy

Copy link
Copy Markdown
Member

could we backport this to jazzy and kilted also?

@jmachowinski

jmachowinski commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

You wrote a note to yourself to adjust the code to c++17.... ;-P

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.

EventsCBGExecutor treats reentrant callback groups like they're mutually exclusive

3 participants