mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[hal] Refactor threads API (#8701)
Since sched_setscheduler() requires non-RT priorities to be 0, we can use that as a sentinel value for disabling RT and condense the Java API to just two functions with fewer parameters. The thread priority setter is deprecated since only experts should use it. The HAL Notifier thread priority setter was replaced with setting the priority in the thread itself. The C++ Notifier non-RT and RT constructors were deduplicated. The real-time scheduler was changed from SCHED_FIFO to SCHED_RR, which is SCHED_FIFO with threads allowed to run for a maximum time quantum before yielding (100 ms by default).
This commit is contained in:
@@ -14,56 +14,20 @@
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
Notifier::Notifier(std::function<void()> callback) {
|
||||
if (!callback) {
|
||||
throw WPILIB_MakeError(err::NullParameter, "callback");
|
||||
}
|
||||
m_callback = callback;
|
||||
int32_t status = 0;
|
||||
m_notifier = HAL_CreateNotifier(&status);
|
||||
WPILIB_CheckErrorStatus(status, "CreateNotifier");
|
||||
|
||||
m_thread = std::thread([=, this] {
|
||||
for (;;) {
|
||||
int32_t status = 0;
|
||||
HAL_NotifierHandle notifier = m_notifier.load();
|
||||
if (notifier == 0) {
|
||||
break;
|
||||
}
|
||||
if (WPI_WaitForObject(notifier) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::function<void()> callback;
|
||||
{
|
||||
std::scoped_lock lock(m_processMutex);
|
||||
callback = m_callback;
|
||||
}
|
||||
|
||||
// Call callback
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
// Ack notifier
|
||||
HAL_AcknowledgeNotifierAlarm(notifier, &status);
|
||||
WPILIB_CheckErrorStatus(status, "AcknowledgeNotifier");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Notifier::Notifier(int priority, std::function<void()> callback) {
|
||||
if (!callback) {
|
||||
throw WPILIB_MakeError(err::NullParameter, "callback");
|
||||
}
|
||||
m_callback = callback;
|
||||
int32_t status = 0;
|
||||
HAL_Status status = 0;
|
||||
m_notifier = HAL_CreateNotifier(&status);
|
||||
WPILIB_CheckErrorStatus(status, "InitializeNotifier");
|
||||
|
||||
m_thread = std::thread([=, this] {
|
||||
int32_t status = 0;
|
||||
HAL_SetCurrentThreadPriority(true, priority, &status);
|
||||
if (priority > 0 && HAL_SetCurrentThreadPriority(priority) != 0) {
|
||||
WPILIB_ReportWarning("Setting Notifier priority to {} failed\n",
|
||||
priority);
|
||||
}
|
||||
for (;;) {
|
||||
HAL_NotifierHandle notifier = m_notifier.load();
|
||||
if (notifier == 0) {
|
||||
@@ -99,6 +63,7 @@ Notifier::Notifier(int priority, std::function<void()> callback) {
|
||||
}
|
||||
|
||||
// Ack notifier
|
||||
HAL_Status status = 0;
|
||||
HAL_AcknowledgeNotifierAlarm(notifier, &status);
|
||||
WPILIB_CheckErrorStatus(status, "AcknowledgeNotifier");
|
||||
}
|
||||
@@ -170,8 +135,3 @@ int32_t Notifier::GetOverrun() const {
|
||||
WPILIB_CheckErrorStatus(status, "GetNotifierOverrun");
|
||||
return overrun;
|
||||
}
|
||||
|
||||
bool Notifier::SetHALThreadPriority(bool realTime, int32_t priority) {
|
||||
int32_t status = 0;
|
||||
return HAL_SetNotifierThreadPriority(realTime, priority, &status);
|
||||
}
|
||||
|
||||
@@ -9,38 +9,32 @@
|
||||
|
||||
namespace wpi {
|
||||
|
||||
int GetThreadPriority(std::thread& thread, bool* isRealTime) {
|
||||
int32_t status = 0;
|
||||
HAL_Bool rt = false;
|
||||
int GetThreadPriority(std::thread& thread) {
|
||||
auto native = thread.native_handle();
|
||||
auto ret = HAL_GetThreadPriority(&native, &rt, &status);
|
||||
int32_t priority = 0;
|
||||
HAL_Status status = HAL_GetThreadPriority(&native, &priority);
|
||||
WPILIB_CheckErrorStatus(status, "GetThreadPriority");
|
||||
*isRealTime = rt;
|
||||
return ret;
|
||||
return priority;
|
||||
}
|
||||
|
||||
int GetCurrentThreadPriority(bool* isRealTime) {
|
||||
int32_t status = 0;
|
||||
HAL_Bool rt = false;
|
||||
auto ret = HAL_GetCurrentThreadPriority(&rt, &status);
|
||||
int GetCurrentThreadPriority() {
|
||||
int32_t priority = 0;
|
||||
HAL_Status status = HAL_GetCurrentThreadPriority(&priority);
|
||||
WPILIB_CheckErrorStatus(status, "GetCurrentThreadPriority");
|
||||
*isRealTime = rt;
|
||||
return ret;
|
||||
return priority;
|
||||
}
|
||||
|
||||
bool SetThreadPriority(std::thread& thread, bool realTime, int priority) {
|
||||
int32_t status = 0;
|
||||
bool SetThreadPriority(std::thread& thread, int priority) {
|
||||
auto native = thread.native_handle();
|
||||
auto ret = HAL_SetThreadPriority(&native, realTime, priority, &status);
|
||||
HAL_Status status = HAL_SetThreadPriority(&native, priority);
|
||||
WPILIB_CheckErrorStatus(status, "SetThreadPriority");
|
||||
return ret;
|
||||
return status != 0;
|
||||
}
|
||||
|
||||
bool SetCurrentThreadPriority(bool realTime, int priority) {
|
||||
int32_t status = 0;
|
||||
auto ret = HAL_SetCurrentThreadPriority(realTime, priority, &status);
|
||||
bool SetCurrentThreadPriority(int priority) {
|
||||
HAL_Status status = HAL_SetCurrentThreadPriority(priority);
|
||||
WPILIB_CheckErrorStatus(status, "SetCurrentThreadPriority");
|
||||
return ret;
|
||||
return status != 0;
|
||||
}
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "wpi/nt/NetworkTableInstance.hpp"
|
||||
#include "wpi/smartdashboard/SmartDashboard.hpp"
|
||||
#include "wpi/system/Errors.hpp"
|
||||
#include "wpi/system/Notifier.hpp"
|
||||
#include "wpi/system/WPILibVersion.hpp"
|
||||
#include "wpi/util/print.hpp"
|
||||
#include "wpi/util/timestamp.hpp"
|
||||
@@ -51,10 +50,6 @@ int wpi::RunHALInitialization() {
|
||||
HAL_ReportUsage("Language", "C++");
|
||||
HAL_ReportUsage("WPILibVersion", GetWPILibVersion());
|
||||
|
||||
if (!wpi::Notifier::SetHALThreadPriority(true, 40)) {
|
||||
WPILIB_ReportWarning("Setting HAL Notifier RT priority to 40 failed\n");
|
||||
}
|
||||
|
||||
std::puts("\n********** Robot program starting **********");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,8 @@ namespace wpi {
|
||||
* If the robot periodic functions and the controller periodic functions have a
|
||||
* lot of scheduling jitter that cause them to occasionally overlap with later
|
||||
* timeslices, consider giving the main robot thread a real-time priority using
|
||||
* wpi::SetCurrentThreadPriority(). An RT priority of 15 is a reasonable choice.
|
||||
* wpi::SetCurrentThreadPriority(int). An RT priority of 15 is a reasonable
|
||||
* choice.
|
||||
*
|
||||
* If you do enable RT though, <i>make sure your periodic functions do not
|
||||
* block</i>. If they do, the operating system will lock up, and you'll have to
|
||||
|
||||
@@ -36,7 +36,8 @@ class Notifier {
|
||||
*
|
||||
* @param callback The callback to run.
|
||||
*/
|
||||
explicit Notifier(std::function<void()> callback);
|
||||
explicit Notifier(std::function<void()> callback)
|
||||
: Notifier(0, std::move(callback)) {}
|
||||
|
||||
template <typename Arg, typename... Args>
|
||||
Notifier(std::invocable<Arg, Args...> auto&& callback, Arg&& arg,
|
||||
@@ -140,23 +141,6 @@ class Notifier {
|
||||
*/
|
||||
int32_t GetOverrun() const;
|
||||
|
||||
/**
|
||||
* Sets the HAL notifier thread priority.
|
||||
*
|
||||
* The HAL notifier thread is responsible for managing the FPGA's notifier
|
||||
* interrupt and waking up user's Notifiers when it's their time to run.
|
||||
* Giving the HAL notifier thread real-time priority helps ensure the user's
|
||||
* real-time Notifiers, if any, are notified to run in a timely manner.
|
||||
*
|
||||
* @param realTime Set to true to set a real-time priority, false for standard
|
||||
* priority.
|
||||
* @param priority Priority to set the thread to. For real-time, this is 1-99
|
||||
* with 99 being highest. For non-real-time, this is forced to
|
||||
* 0. See "man 7 sched" for more details.
|
||||
* @return True on success.
|
||||
*/
|
||||
static bool SetHALThreadPriority(bool realTime, int32_t priority);
|
||||
|
||||
private:
|
||||
// The thread waiting on the HAL alarm
|
||||
std::thread m_thread;
|
||||
|
||||
@@ -9,49 +9,59 @@
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* Get the thread priority for the specified thread.
|
||||
* Gets the specified thread's priority.
|
||||
*
|
||||
* @param thread Reference to the thread to get the priority for.
|
||||
* @param isRealTime Set to true if thread is real-time, otherwise false.
|
||||
* @return The current thread priority. For real-time, this is 1-99
|
||||
* with 99 being highest. For non-real-time, this is 0. See
|
||||
* "man 7 sched" for details.
|
||||
* Priorities range from 0 to 99 where 0 is non-real-time, 1-99 are real-time,
|
||||
* and 99 is highest priority. See "man 7 sched" for details.
|
||||
*
|
||||
* @param thread The thread.
|
||||
* @return The specified thread's priority.
|
||||
*/
|
||||
int GetThreadPriority(std::thread& thread, bool* isRealTime);
|
||||
int GetThreadPriority(std::thread& thread);
|
||||
|
||||
/**
|
||||
* Get the thread priority for the current thread.
|
||||
* Gets the current thread's priority.
|
||||
*
|
||||
* @param isRealTime Set to true if thread is real-time, otherwise false.
|
||||
* @return The current thread priority. For real-time, this is 1-99
|
||||
* with 99 being highest. For non-real-time, this is 0. See
|
||||
* "man 7 sched" for details.
|
||||
* Priorities range from 0 to 99 where 0 is non-real-time, 1-99 are real-time,
|
||||
* and 99 is highest priority. See "man 7 sched" for details.
|
||||
*
|
||||
* @return The current thread's priority.
|
||||
*/
|
||||
int GetCurrentThreadPriority(bool* isRealTime);
|
||||
int GetCurrentThreadPriority();
|
||||
|
||||
/**
|
||||
* Sets the thread priority for the specified thread.
|
||||
* Sets the specified thread's priority.
|
||||
*
|
||||
* @param thread Reference to the thread to set the priority of.
|
||||
* @param realTime Set to true to set a real-time priority, false for standard
|
||||
* priority.
|
||||
* @param priority Priority to set the thread to. For real-time, this is 1-99
|
||||
* with 99 being highest. For non-real-time, this is forced to
|
||||
* 0. See "man 7 sched" for more details.
|
||||
* @return True on success.
|
||||
* Priorities range from 0 to 99 where 0 is non-real-time, 1-99 are real-time,
|
||||
* and 99 is highest priority. See "man 7 sched" for details.
|
||||
*
|
||||
* @param thread The thread.
|
||||
* @param priority The priority.
|
||||
* @return True on success.
|
||||
* @deprecated Incorrect usage of real-time priority can lead to system lockups.
|
||||
* Only use this function if you are trained in real-time software
|
||||
* development.
|
||||
*/
|
||||
bool SetThreadPriority(std::thread& thread, bool realTime, int priority);
|
||||
[[deprecated(
|
||||
"Incorrect usage of real-time priority can lead to system lockups. Only "
|
||||
"use this function if you are trained in real-time software development.")]]
|
||||
bool SetThreadPriority(std::thread& thread, int priority);
|
||||
|
||||
/**
|
||||
* Sets the thread priority for the current thread.
|
||||
* Sets the current thread's priority.
|
||||
*
|
||||
* @param realTime Set to true to set a real-time priority, false for standard
|
||||
* priority.
|
||||
* @param priority Priority to set the thread to. For real-time, this is 1-99
|
||||
* with 99 being highest. For non-real-time, this is forced to
|
||||
* 0. See "man 7 sched" for more details.
|
||||
* @return True on success.
|
||||
* Priorities range from 0 to 99 where 0 is non-real-time, 1-99 are real-time,
|
||||
* and 99 is highest priority. See "man 7 sched" for details.
|
||||
*
|
||||
* @param priority The priority.
|
||||
* @return True on success.
|
||||
* @deprecated Incorrect usage of real-time priority can lead to system lockups.
|
||||
* Only use this function if you are trained in real-time software
|
||||
* development.
|
||||
*/
|
||||
bool SetCurrentThreadPriority(bool realTime, int priority);
|
||||
[[deprecated(
|
||||
"Incorrect usage of real-time priority can lead to system lockups. Only "
|
||||
"use this function if you are trained in real-time software development.")]]
|
||||
bool SetCurrentThreadPriority(int priority);
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
@@ -19,4 +19,3 @@ classes:
|
||||
wpi::units::second_t:
|
||||
Stop:
|
||||
GetOverrun:
|
||||
SetHALThreadPriority:
|
||||
|
||||
@@ -157,11 +157,6 @@ class RobotStarter:
|
||||
def _start(self, robot_cls: wpilib.RobotBase) -> bool:
|
||||
hal.reportUsage("Language", "Python")
|
||||
|
||||
if not wpilib.Notifier.setHALThreadPriority(True, 40):
|
||||
reportErrorInternal(
|
||||
"Setting HAL Notifier RT priority to 40 failed", isWarning=True
|
||||
)
|
||||
|
||||
isSimulation = wpilib.RobotBase.isSimulation()
|
||||
|
||||
# hack: initialize networktables before creating the robot
|
||||
|
||||
@@ -155,8 +155,3 @@ int32_t PyNotifier::GetOverrun() const {
|
||||
WPILIB_CheckErrorStatus(status, "GetNotifierOverrun");
|
||||
return overrun;
|
||||
}
|
||||
|
||||
bool PyNotifier::SetHALThreadPriority(bool realTime, int32_t priority) {
|
||||
int32_t status = 0;
|
||||
return HAL_SetNotifierThreadPriority(realTime, priority, &status);
|
||||
}
|
||||
|
||||
@@ -101,23 +101,6 @@ class PyNotifier {
|
||||
*/
|
||||
int32_t GetOverrun() const;
|
||||
|
||||
/**
|
||||
* Sets the HAL notifier thread priority.
|
||||
*
|
||||
* The HAL notifier thread is responsible for managing the FPGA's notifier
|
||||
* interrupt and waking up user's Notifiers when it's their time to run.
|
||||
* Giving the HAL notifier thread real-time priority helps ensure the user's
|
||||
* real-time Notifiers, if any, are notified to run in a timely manner.
|
||||
*
|
||||
* @param realTime Set to true to set a real-time priority, false for standard
|
||||
* priority.
|
||||
* @param priority Priority to set the thread to. For real-time, this is 1-99
|
||||
* with 99 being highest. For non-real-time, this is forced to
|
||||
* 0. See "man 7 sched" for more details.
|
||||
* @return True on success.
|
||||
*/
|
||||
static bool SetHALThreadPriority(bool realTime, int32_t priority);
|
||||
|
||||
private:
|
||||
// The thread waiting on the HAL alarm
|
||||
py::object m_thread;
|
||||
|
||||
Reference in New Issue
Block a user