Repository navigation
Conversation
ABI Compliance Check✅ Verdict: compatible
✅
|
|
thanks for catching the issue and for the PR @Yadunund . @jmachowinski and I both looked into this during the client library working group today. My intuition is that this PR is perhaps putting in additional complexity in rclcpp's handling of timers for something that ought to be fixed in the rcl layer. I think the preference to not invoke |
|
@skyegalaxy thanks for the quick feedback! I agree a fix upstream in I had my agent iterate with the Deadlock with `on_reset`Calling on_reset from both reschedule sites in `_rcl_timer_time_jump()` with the current `TimerQueue`. It fixes the stall, but it deadlocks the executor's timer thread against the time source. `TimeSource::set_clock()` holds the clock mutex while rcl runs the jump callbacks, so the on_reset handler now runs under it and takes the queue mutex and then the wait mutex in `wakeup_timer_thread()`, while the timer thread takes the wait mutex and then the clock mutex every time `ClockWaiterImpl::wait_until_ros_time()` installs or removes its jump handler. TSAN (`detect_deadlocks=1`) reports the inversion within seconds of backward jumps, and a stress with 64 ROS time timers and a 1 s backward `/clock` jump every 25 samples hangs within a minute when pinned to one CPU (`taskset -c 0`):Also updated this PR to adopt the new callback. |
7bbb95f to
aabbea0
Compare
rcl moves next_call_time of a ROS time timer when the clock jumps back by more than one period and when ROS time is activated or deactivated, without calling the on reset callback. TimerQueue keyed its running timers by a copy of next_call_time taken when the timer was added, fired or reset, so after such a jump the timer thread slept until the stale deadline: a /clock jump from 1000 s back to 900 s silenced a 100 ms timer for 100 s of simulated time, and a timer that was created before use_sim_time was enabled never fired again. Register rcl's schedule change callback on every ROS time timer. It runs inside the clock jump callback with the clock mutex held, which the timer thread takes while holding its wait mutex, so it only flags the timer; the timer thread re-keys flagged timers before it computes its next wakeup, and the flag is part of its wait predicate. Signed-off-by: Yadunund Vijay <yadunund@gmail.com>
aabbea0 to
3637cae
Compare
Description
Fixes #3342
EventsCBGExecutortimers can stall after backward ROS time jumps or whenuse_sim_timeis enabled at runtime becauseTimerQueueretains stale deadlines.This PR uses the new schedule change callback from ros2/rcl#1352 to update timer deadlines. The callback only flags timers for rescheduling to avoid deadlocks.
test_executors_time_jumpverifies both scenarios. It fails on Rolling and passes with both fixes.Depends-On: ros2/rcl#1352
Is this user-facing behavior change?
Yes. Timers continue working after backward
/clockjumps (e.g.,ros2 bag play --loop --clock) and whenuse_sim_timeis enabled at runtime.Did you use Generative AI?
Yes. Claude Code (Claude Fable 5.1) assisted with investigation, implementation, and tests. Changes were reviewed and tested manually.
Additional Information
Reusing the on-reset callback causes a deadlock with
TimeSource::set_clock().