[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

@@ -120,7 +120,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
m_watchdogs.remove(this);
m_expirationTime = m_startTime + m_timeout;
m_watchdogs.add(this);
updateAlarm();
updateAlarm(false);
} finally {
m_queueMutex.unlock();
}
@@ -194,7 +194,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
m_watchdogs.remove(this);
m_expirationTime = m_startTime + m_timeout;
m_watchdogs.add(this);
updateAlarm();
updateAlarm(false);
} finally {
m_queueMutex.unlock();
}
@@ -205,7 +205,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
m_queueMutex.lock();
try {
m_watchdogs.remove(this);
updateAlarm();
updateAlarm(false);
} finally {
m_queueMutex.unlock();
}
@@ -223,9 +223,12 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
}
@SuppressWarnings("resource")
private static void updateAlarm() {
private static void updateAlarm(boolean acknowledge) {
if (m_watchdogs.isEmpty()) {
NotifierJNI.cancelNotifierAlarm(m_notifier);
} else if (acknowledge) {
NotifierJNI.acknowledgeNotifierAlarm(
m_notifier, true, (long) (m_watchdogs.peek().m_expirationTime * 1e6), 0, true);
} else {
NotifierJNI.setNotifierAlarm(
m_notifier, (long) (m_watchdogs.peek().m_expirationTime * 1e6), 0, true);
@@ -277,9 +280,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
watchdog.m_callback.run();
m_queueMutex.lock();
updateAlarm();
NotifierJNI.acknowledgeNotifierAlarm(m_notifier);
updateAlarm(true);
} finally {
m_queueMutex.unlock();
}