[wpilib] Clean up Notifier (#5630)

The user-facing docs were simplified, SetHandler() was renamed to
SetCallback(), and the internal documentation was synchronized.
This commit is contained in:
Tyler Veness
2023-09-15 19:59:03 -07:00
committed by GitHub
parent 4bac4dd0f4
commit 12e2043b77
3 changed files with 148 additions and 112 deletions

View File

@@ -11,7 +11,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
* Notifiers run a callback function on a separate thread at a specified period.
* Notifiers run a user-provided callback function on a separate thread.
*
* <p>If startSingle() is used, the callback will run once. If startPeriodic() is used, the callback
* will run repeatedly with the given period until stop() is called.
@@ -19,23 +19,27 @@ import java.util.concurrent.locks.ReentrantLock;
public class Notifier implements AutoCloseable {
// The thread waiting on the HAL alarm.
private Thread m_thread;
// The lock for the process information.
// The lock held while updating process information.
private final ReentrantLock m_processLock = new ReentrantLock();
// The C pointer to the notifier object. We don't use it directly, it is
// just passed to the JNI bindings.
// HAL handle passed to the JNI bindings (atomic for proper destruction).
private final AtomicInteger m_notifier = new AtomicInteger();
// The time, in seconds, at which the corresponding handler should be
// called. Has the same zero as RobotController.getFPGATime().
// The user-provided callback.
private Runnable m_callback;
// The time, in seconds, at which the callback should be called. Has the same
// zero as RobotController.getFPGATime().
private double m_expirationTimeSeconds;
// The handler passed in by the user which should be called at the
// appropriate interval.
private Runnable m_handler;
// Whether we are calling the handler just once or periodically.
private boolean m_periodic;
// If periodic, the period of the calling; if just once, stores how long it
// is until we call the handler.
// If periodic, stores the callback period; if single, stores the time until
// the callback call.
private double m_periodSeconds;
// True if the callback is periodic
private boolean m_periodic;
@Override
public void close() {
int handle = m_notifier.getAndSet(0);
@@ -43,7 +47,7 @@ public class Notifier implements AutoCloseable {
return;
}
NotifierJNI.stopNotifier(handle);
// Join the thread to ensure the handler has exited.
// Join the thread to ensure the callback has exited.
if (m_thread.isAlive()) {
try {
m_thread.interrupt();
@@ -75,15 +79,16 @@ public class Notifier implements AutoCloseable {
}
/**
* Create a Notifier for timer event notification.
* Create a Notifier with the given callback.
*
* @param run The handler that is called at the notification time which is set using StartSingle
* or StartPeriodic.
* <p>Configure when the callback runs with startSingle() or startPeriodic().
*
* @param callback The callback to run.
*/
public Notifier(Runnable run) {
requireNonNullParam(run, "run", "Notifier");
public Notifier(Runnable callback) {
requireNonNullParam(callback, "callback", "Notifier");
m_handler = run;
m_callback = callback;
m_notifier.set(NotifierJNI.initializeNotifier());
m_thread =
@@ -99,23 +104,24 @@ public class Notifier implements AutoCloseable {
break;
}
Runnable handler;
Runnable threadHandler;
m_processLock.lock();
try {
handler = m_handler;
threadHandler = m_callback;
if (m_periodic) {
m_expirationTimeSeconds += m_periodSeconds;
updateAlarm();
} else {
// need to update the alarm to cause it to wait again
// Need to update the alarm to cause it to wait again
updateAlarm((long) -1);
}
} finally {
m_processLock.unlock();
}
if (handler != null) {
handler.run();
// Call callback
if (threadHandler != null) {
threadHandler.run();
}
}
});
@@ -150,24 +156,39 @@ public class Notifier implements AutoCloseable {
}
/**
* Change the handler function.
* Change the callback function.
*
* @param handler Handler
* @param callback The callback function.
* @deprecated Use setCallback() instead.
*/
public void setHandler(Runnable handler) {
@Deprecated(forRemoval = true, since = "2024")
public void setHandler(Runnable callback) {
m_processLock.lock();
try {
m_handler = handler;
m_callback = callback;
} finally {
m_processLock.unlock();
}
}
/**
* Register for single event notification. A timer event is queued for a single event after the
* specified delay.
* Change the callback function.
*
* @param delaySeconds Seconds to wait before the handler is called.
* @param callback The callback function.
*/
public void setCallback(Runnable callback) {
m_processLock.lock();
try {
m_callback = callback;
} finally {
m_processLock.unlock();
}
}
/**
* Run the callback once after the given delay.
*
* @param delaySeconds Time in seconds to wait before the callback is called.
*/
public void startSingle(double delaySeconds) {
m_processLock.lock();
@@ -182,15 +203,13 @@ public class Notifier implements AutoCloseable {
}
/**
* Register for periodic event notification. A timer event is queued for periodic event
* notification. Each time the interrupt occurs, the event will be immediately requeued for the
* same time interval.
* Run the callback periodically with the given period.
*
* <p>The user-provided callback should be written in a nonblocking manner so the callback can be
* recalled at the next periodic event notification.
* <p>The user-provided callback should be written so that it completes before the next time it's
* scheduled to run.
*
* @param periodSeconds Period in seconds to call the handler starting one period after the call
* to this method.
* @param periodSeconds Period in seconds after which to to call the callback starting one period
* after the call to this method.
*/
public void startPeriodic(double periodSeconds) {
m_processLock.lock();
@@ -205,9 +224,13 @@ public class Notifier implements AutoCloseable {
}
/**
* Stop timer events from occurring. Stop any repeating timer events from occurring. This will
* also remove any single notification events from the queue. If a timer-based call to the
* registered handler is in progress, this function will block until the handler call is complete.
* Stop further callback invocations.
*
* <p>No further periodic callbacks will occur. Single invocations will also be cancelled if they
* haven't yet occurred.
*
* <p>If a callback invocation is in progress, this function will block until the callback is
* complete.
*/
public void stop() {
m_processLock.lock();