[hal,wpilib] Fix TimedRobot notifier race (#8445)

It was possible for the alarm to fire between the set alarm and ack,
resulting in a hang on next wait. It's not possible to ack before set
alarm due to a race in sim step timing, so the fix is to provide an
atomic ack and set alarm; the easiest way to implement this in the API
was to change ack to optionally also set the alarm again.
This commit is contained in:
Peter Johnson
2025-12-04 09:59:59 -07:00
committed by GitHub
parent d1b1703c86
commit 934f8d9c15
12 changed files with 147 additions and 78 deletions

View File

@@ -35,16 +35,14 @@ void TimedRobot::StartCompetition() {
auto callback = m_callbacks.pop();
int32_t status = 0;
HAL_SetNotifierAlarm(m_notifier, callback.expirationTime.count(), 0, true,
&status);
WPILIB_CheckErrorStatus(status, "UpdateNotifierAlarm");
// Acknowledge previous alarm after setting the next one to avoid a race
// against getting the next notifier timeout in HALSIM StepTiming.
if (first) {
first = false;
HAL_SetNotifierAlarm(m_notifier, callback.expirationTime.count(), 0, true,
&status);
WPILIB_CheckErrorStatus(status, "SetNotifierAlarm");
} else {
HAL_AcknowledgeNotifierAlarm(m_notifier, &status);
HAL_AcknowledgeNotifierAlarm(
m_notifier, true, callback.expirationTime.count(), 0, true, &status);
WPILIB_CheckErrorStatus(status, "AcknowledgeNotifierAlarm");
}

View File

@@ -46,7 +46,7 @@ Notifier::Notifier(std::function<void()> callback) {
}
// Ack notifier
HAL_AcknowledgeNotifierAlarm(notifier, &status);
HAL_AcknowledgeNotifierAlarm(notifier, false, 0, 0, false, &status);
WPILIB_CheckErrorStatus(status, "AcknowledgeNotifier");
}
});
@@ -99,7 +99,7 @@ Notifier::Notifier(int priority, std::function<void()> callback) {
}
// Ack notifier
HAL_AcknowledgeNotifierAlarm(notifier, &status);
HAL_AcknowledgeNotifierAlarm(notifier, false, 0, 0, false, &status);
WPILIB_CheckErrorStatus(status, "AcknowledgeNotifier");
}
});

View File

@@ -39,7 +39,7 @@ class Watchdog::Impl {
DerefGreater<Watchdog*>>
m_watchdogs;
void UpdateAlarm();
void UpdateAlarm(bool acknowledge = false);
private:
void Main();
@@ -67,7 +67,7 @@ Watchdog::Impl::~Impl() {
}
}
void Watchdog::Impl::UpdateAlarm() {
void Watchdog::Impl::UpdateAlarm(bool acknowledge) {
int32_t status = 0;
// Return if we are being destructed, or were not created successfully
auto notifier = m_notifier.load();
@@ -76,6 +76,12 @@ void Watchdog::Impl::UpdateAlarm() {
}
if (m_watchdogs.empty()) {
HAL_CancelNotifierAlarm(notifier, &status);
} else if (acknowledge) {
HAL_AcknowledgeNotifierAlarm(
notifier, true,
static_cast<uint64_t>(m_watchdogs.top()->m_expirationTime.value() *
1e6),
0, true, &status);
} else {
HAL_SetNotifierAlarm(notifier,
static_cast<uint64_t>(
@@ -125,9 +131,7 @@ void Watchdog::Impl::Main() {
watchdog->m_callback();
lock.lock();
UpdateAlarm();
HAL_AcknowledgeNotifierAlarm(notifier, &status);
UpdateAlarm(true);
}
}