Repository navigation
refactor(timers): unify the duplicated ClockConditionalVariable implementations - #3401
skyegalaxy wants to merge 9 commits into
Conversation
Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
…alVariable Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
ABI Compliance Check✅ Verdict: compatible (additions only)
✅
|
|
Pulls: #3401 |
| const rclcpp::Time & abs_time, const std::function<bool ()> & pred) | ||
| { | ||
| switch(clock_->get_clock_type()) { | ||
| if (abs_time.get_clock_type() != clock->get_clock_type()) { |
There was a problem hiding this comment.
With a RCL_ROS_TIME clock and sim time off (and with a RCL_SYSTEM_TIME clock), the old code never compared abs_time to the clock, so wait_until(lk, rclcpp::Time(sec, nsec), pred) worked. rclcpp::Time defaults to system time, so that call now throws. Only the steady path and the active-ROS path threw before, through Time::operator- and operator>=.
Could we keep the old behavior for those paths, or call this out as a breaking change?
| * the clocks involved may be destroyed between waits. | ||
| */ | ||
| RCLCPP_PUBLIC | ||
| explicit ClockConditionalVariable(const rclcpp::Context::SharedPtr & context); |
There was a problem hiding this comment.
This overload makes ClockConditionalVariable cv(nullptr); and std::make_unique<ClockConditionalVariable>(nullptr) ambiguous, because nullptr converts to both shared_ptr types.
| rclcpp::Clock::SharedPtr used_clock_for_timers; | ||
|
|
||
| ClockConditionalVariable clock_waiter; | ||
| rclcpp::ClockConditionalVariable clock_waiter; |
There was a problem hiding this comment.
Switching to rclcpp::ClockConditionalVariable means wait_until can now throw for reasons other than the shutdown race: a clock type mismatch, or a null clock. The existing catch (const std::runtime_error &) in the timer thread (around L392) sets running = false without logging, so either of these would stop every timer in the queue without a message. Worth narrowing that catch, or at least logging.
…system time waits Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
… constructor Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
| * to wait on, for example because the clocks involved may be destroyed | ||
| * between waits. |
There was a problem hiding this comment.
add one space for alignment?
| * to wait on, for example because the clocks involved may be destroyed | |
| * between waits. | |
| * to wait on, for example because the clocks involved may be destroyed | |
| * between waits. |
| } catch (const std::runtime_error & e) { | ||
| // there is a race on shutdown, were the context may | ||
| // become invalid, while we call sleep_until | ||
| if (rclcpp::ok()) { |
There was a problem hiding this comment.
this means this must be always with default context? imo it shoule be more like the following with using the stored context in TimerQueue? otherwise, using explicit context in the application will fail here.
| if (rclcpp::ok()) { | |
| if (rclcpp::ok(context)) { |
Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
…timer wait failure Signed-off-by: Skyler Medeiros <skye@polymathrobotics.com>
Description
The timer manager in #3097 introduced a variant of
ClockWaiterandClockConditionalVariablewhich could accept a clock on itswait_untilcalls instead of at construction. This PR unifies bothClockWaiterandClockConditionalVariableunder one set which can do both, and removes the duplicates intimer_manager.ClockWaiterandClockConditionalVariablecan now accept a null clock at construction, and both gain await_until(lock, clock, until, pred)overload. The existing overloads without a clock are unchanged.ClockConditionalVariablekeeps oneClockWaiterfor its whole lifetime, sonotify_one()takes no lock and a wait performs no allocation.TimerQueueusesrclcpp::ClockConditionalVariabledirectly, now constructed with a null clock.std::runtime_error. Before, waiting without a clock dereferenced a null pointer.Is this user-facing behavior change?
rclcpp::ClockConditionalVariable::wait_until()used to returntrueunconditionally. It now returnsfalseif the context was shut down before the call. Callers that ignored the return value need no change.A wait whose
untildoesn't match the clock's type now throws before it starts, on every clock type.Did you use Generative AI?
Yes, Claude Opus 5.5
Additional Information