[wpilib] Remove InterruptableSensorBase and replace with interrupt classes (#2410)

This commit is contained in:
Thad House
2021-06-05 11:25:21 -07:00
committed by GitHub
parent 15c521a7fe
commit 5c817082a0
28 changed files with 982 additions and 1497 deletions

View File

@@ -21,65 +21,14 @@
using namespace hal;
namespace {
// Safe thread to allow callbacks to run on their own thread
class InterruptThread : public wpi::SafeThread {
public:
void Main() override {
std::unique_lock lock(m_mutex);
while (m_active) {
m_cond.wait(lock, [&] { return !m_active || m_notify; });
if (!m_active) {
break;
}
m_notify = false;
HAL_InterruptHandlerFunction handler = m_handler;
uint32_t mask = m_mask;
void* param = m_param;
lock.unlock(); // don't hold mutex during callback execution
handler(mask, param);
lock.lock();
}
}
bool m_notify = false;
HAL_InterruptHandlerFunction m_handler;
void* m_param;
uint32_t m_mask;
};
class InterruptThreadOwner : public wpi::SafeThreadOwner<InterruptThread> {
public:
void SetFunc(HAL_InterruptHandlerFunction handler, void* param) {
auto thr = GetThread();
if (!thr)
return;
thr->m_handler = handler;
thr->m_param = param;
}
void Notify(uint32_t mask) {
auto thr = GetThread();
if (!thr)
return;
thr->m_mask = mask;
thr->m_notify = true;
thr->m_cond.notify_one();
}
};
struct Interrupt {
std::unique_ptr<tInterrupt> anInterrupt;
std::unique_ptr<tInterruptManager> manager;
std::unique_ptr<InterruptThreadOwner> threadOwner = nullptr;
void* param = nullptr;
};
} // namespace
static void threadedInterruptHandler(uint32_t mask, void* param) {
static_cast<InterruptThreadOwner*>(param)->Notify(mask);
}
static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
HAL_HandleEnum::Interrupt>* interruptHandles;
@@ -94,8 +43,7 @@ void InitializeInterrupts() {
extern "C" {
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
int32_t* status) {
HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) {
hal::init::CheckInit();
HAL_InterruptHandle handle = interruptHandles->Allocate();
if (handle == HAL_kInvalidHandle) {
@@ -108,24 +56,16 @@ HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
anInterrupt->anInterrupt.reset(tInterrupt::create(interruptIndex, status));
anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
anInterrupt->manager = std::make_unique<tInterruptManager>(
(1u << interruptIndex) | (1u << (interruptIndex + 8u)), watcher, status);
(1u << interruptIndex) | (1u << (interruptIndex + 8u)), true, status);
return handle;
}
void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
int32_t* status) {
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
auto anInterrupt = interruptHandles->Get(interruptHandle);
interruptHandles->Free(interruptHandle);
if (anInterrupt == nullptr) {
return nullptr;
return;
}
if (anInterrupt->manager->isEnabled(status)) {
anInterrupt->manager->disable(status);
}
void* param = anInterrupt->param;
return param;
}
int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
@@ -150,31 +90,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
return result;
}
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
int32_t* status) {
auto anInterrupt = interruptHandles->Get(interruptHandle);
if (anInterrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (!anInterrupt->manager->isEnabled(status)) {
anInterrupt->manager->enable(status);
}
}
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
int32_t* status) {
auto anInterrupt = interruptHandles->Get(interruptHandle);
if (anInterrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (anInterrupt->manager->isEnabled(status)) {
anInterrupt->manager->disable(status);
}
}
int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
int32_t* status) {
auto anInterrupt = interruptHandles->Get(interruptHandle);
@@ -223,40 +138,6 @@ void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
anInterrupt->anInterrupt->writeConfig_Source_Module(routingModule, status);
}
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
HAL_InterruptHandlerFunction handler,
void* param, int32_t* status) {
auto anInterrupt = interruptHandles->Get(interruptHandle);
if (anInterrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
anInterrupt->manager->registerHandler(handler, param, status);
anInterrupt->param = param;
}
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interrupt_handle,
HAL_InterruptHandlerFunction handler,
void* param, int32_t* status) {
auto anInterrupt = interruptHandles->Get(interrupt_handle);
if (anInterrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
anInterrupt->threadOwner = std::make_unique<InterruptThreadOwner>();
anInterrupt->threadOwner->Start();
anInterrupt->threadOwner->SetFunc(handler, param);
HAL_AttachInterruptHandler(interrupt_handle, threadedInterruptHandler,
anInterrupt->threadOwner.get(), status);
if (*status != 0) {
anInterrupt->threadOwner = nullptr;
}
anInterrupt->param = param;
}
void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
HAL_Bool risingEdge, HAL_Bool fallingEdge,
int32_t* status) {

View File

@@ -17,126 +17,19 @@
using namespace hal;
// Thread where callbacks are actually performed.
//
// JNI's AttachCurrentThread() creates a Java Thread object on every
// invocation, which is both time inefficient and causes issues with Eclipse
// (which tries to keep a thread list up-to-date and thus gets swamped).
//
// Instead, this class attaches just once. When a hardware notification
// occurs, a condition variable wakes up this thread and this thread actually
// makes the call into Java.
//
// We don't want to use a FIFO here. If the user code takes too long to
// process, we will just ignore the redundant wakeup.
class InterruptThreadJNI : public wpi::SafeThread {
public:
void Main() override;
bool m_notify = false;
uint32_t m_mask = 0;
jobject m_func = nullptr;
jmethodID m_mid;
jobject m_param = nullptr;
};
class InterruptJNI : public wpi::SafeThreadOwner<InterruptThreadJNI> {
public:
void SetFunc(JNIEnv* env, jobject func, jmethodID mid, jobject param);
void Notify(uint32_t mask) {
auto thr = GetThread();
if (!thr) {
return;
}
thr->m_notify = true;
thr->m_mask = mask;
thr->m_cond.notify_one();
}
};
void InterruptJNI::SetFunc(JNIEnv* env, jobject func, jmethodID mid,
jobject param) {
auto thr = GetThread();
if (!thr) {
return;
}
// free global references
if (thr->m_func) {
env->DeleteGlobalRef(thr->m_func);
}
if (thr->m_param) {
env->DeleteGlobalRef(thr->m_param);
}
// create global references
thr->m_func = env->NewGlobalRef(func);
thr->m_param = param ? env->NewGlobalRef(param) : nullptr;
thr->m_mid = mid;
}
void InterruptThreadJNI::Main() {
JNIEnv* env;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_2;
args.name = const_cast<char*>("Interrupt");
args.group = nullptr;
jint rs = GetJVM()->AttachCurrentThreadAsDaemon(
reinterpret_cast<void**>(&env), &args);
if (rs != JNI_OK) {
return;
}
std::unique_lock lock(m_mutex);
while (m_active) {
m_cond.wait(lock, [&] { return !m_active || m_notify; });
if (!m_active) {
break;
}
m_notify = false;
if (!m_func) {
continue;
}
jobject func = m_func;
jmethodID mid = m_mid;
uint32_t mask = m_mask;
jobject param = m_param;
lock.unlock(); // don't hold mutex during callback execution
env->CallVoidMethod(func, mid, static_cast<jint>(mask), param);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
lock.lock();
}
// free global references
if (m_func) {
env->DeleteGlobalRef(m_func);
}
if (m_param) {
env->DeleteGlobalRef(m_param);
}
GetJVM()->DetachCurrentThread();
}
void interruptHandler(uint32_t mask, void* param) {
static_cast<InterruptJNI*>(param)->Notify(mask);
}
extern "C" {
/*
* Class: edu_wpi_first_hal_InterruptJNI
* Method: initializeInterrupts
* Signature: (Z)I
* Signature: ()I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_InterruptJNI_initializeInterrupts
(JNIEnv* env, jclass, jboolean watcher)
(JNIEnv* env, jclass)
{
int32_t status = 0;
HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(watcher, &status);
HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(&status);
CheckStatusForceThrow(env, status);
return (jint)interrupt;
@@ -151,14 +44,7 @@ JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_InterruptJNI_cleanInterrupts
(JNIEnv* env, jclass, jint interruptHandle)
{
int32_t status = 0;
auto param =
HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle, &status);
if (param) {
delete static_cast<InterruptJNI*>(param);
}
// ignore status, as an invalid handle just needs to be ignored.
HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle);
}
/*
@@ -179,36 +65,6 @@ Java_edu_wpi_first_hal_InterruptJNI_waitForInterrupt
return result;
}
/*
* Class: edu_wpi_first_hal_InterruptJNI
* Method: enableInterrupts
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_InterruptJNI_enableInterrupts
(JNIEnv* env, jclass, jint interruptHandle)
{
int32_t status = 0;
HAL_EnableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_InterruptJNI
* Method: disableInterrupts
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_InterruptJNI_disableInterrupts
(JNIEnv* env, jclass, jint interruptHandle)
{
int32_t status = 0;
HAL_DisableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_InterruptJNI
* Method: readInterruptRisingTimestamp
@@ -261,37 +117,6 @@ Java_edu_wpi_first_hal_InterruptJNI_requestInterrupts
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_InterruptJNI
* Method: attachInterruptHandler
* Signature: (ILjava/lang/Object;Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_InterruptJNI_attachInterruptHandler
(JNIEnv* env, jclass, jint interruptHandle, jobject handler, jobject param)
{
jclass cls = env->GetObjectClass(handler);
if (cls == nullptr) {
assert(false);
return;
}
jmethodID mid = env->GetMethodID(cls, "apply", "(ILjava/lang/Object;)V");
if (mid == nullptr) {
assert(false);
return;
}
InterruptJNI* intr = new InterruptJNI;
intr->Start();
intr->SetFunc(env, handler, mid, param);
int32_t status = 0;
HAL_AttachInterruptHandler((HAL_InterruptHandle)interruptHandle,
interruptHandler, intr, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_InterruptJNI
* Method: setInterruptUpSourceEdge

View File

@@ -19,25 +19,20 @@
extern "C" {
#endif
typedef void (*HAL_InterruptHandlerFunction)(uint32_t interruptAssertedMask,
void* param);
/**
* Initializes an interrupt.
*
* @param watcher true for synchronous interrupts, false for asynchronous
* @return the created interrupt handle
*/
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher, int32_t* status);
HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status);
/**
* Frees an interrupt.
*
* @param interruptHandle the interrupt handle
* @return the param passed to the interrupt, or nullptr if one
* wasn't passed.
*/
void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle);
/**
* In synchronous mode, waits for the defined interrupt to occur.
@@ -52,25 +47,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
double timeout, HAL_Bool ignorePrevious,
int32_t* status);
/**
* Enables interrupts to occur on this input.
*
* Interrupts are disabled when the RequestInterrupt call is made. This gives
* time to do the setup of the other options before starting to field
* interrupts.
*
* @param interruptHandle the interrupt handle
*/
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
/**
* Disables interrupts without without deallocating structures.
*
* @param interruptHandle the interrupt handle
*/
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
int32_t* status);
/**
* Returns the timestamp for the rising interrupt that occurred most recently.
*
@@ -110,34 +86,6 @@ void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
HAL_AnalogTriggerType analogTriggerType,
int32_t* status);
/**
* Attaches an asynchronous interrupt handler to the interrupt.
*
* This interrupt gets called directly on the FPGA interrupt thread, so will
* block other interrupts while running.
*
* @param interruptHandle the interrupt handle
* @param handler the handler function for the interrupt to call
* @param param a parameter to be passed to the handler
*/
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
HAL_InterruptHandlerFunction handler,
void* param, int32_t* status);
/**
* Attaches an asynchronous interrupt handler to the interrupt.
*
* This interrupt gets called on a thread specific to the interrupt, so will not
* block other interrupts.
*
* @param interruptHandle the interrupt handle
* @param handler the handler function for the interrupt to call
* @param param a parameter to be passed to the handler
*/
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
HAL_InterruptHandlerFunction handler,
void* param, int32_t* status);
/**
* Sets the edges to trigger the interrupt on.
*

View File

@@ -42,16 +42,12 @@ struct Interrupt {
HAL_Handle portHandle;
uint8_t index;
HAL_AnalogTriggerType trigType;
bool watcher;
int64_t risingTimestamp;
int64_t fallingTimestamp;
bool previousState;
bool fireOnUp;
bool fireOnDown;
int32_t callbackId;
void* callbackParam;
HAL_InterruptHandlerFunction callbackFunction;
};
struct SynchronousWaitData {
@@ -83,8 +79,7 @@ void InitializeInterrupts() {
} // namespace hal::init
extern "C" {
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
int32_t* status) {
HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) {
hal::init::CheckInit();
HAL_InterruptHandle handle = interruptHandles->Allocate();
if (handle == HAL_kInvalidHandle) {
@@ -100,19 +95,10 @@ HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
anInterrupt->index = getHandleIndex(handle);
anInterrupt->callbackId = -1;
anInterrupt->watcher = watcher;
return handle;
}
void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
int32_t* status) {
HAL_DisableInterrupts(interruptHandle, status);
auto anInterrupt = interruptHandles->Get(interruptHandle);
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
interruptHandles->Free(interruptHandle);
if (anInterrupt == nullptr) {
return nullptr;
}
return anInterrupt->callbackParam;
}
static void ProcessInterruptDigitalSynchronous(const char* name, void* param,
@@ -352,12 +338,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
return WaitResult::Timeout;
}
// Check to make sure we are actually an interrupt in synchronous mode
if (!interrupt->watcher) {
*status = NiFpga_Status_InvalidParameter;
return WaitResult::Timeout;
}
if (interrupt->isAnalog) {
return WaitForInterruptAnalog(interruptHandle, interrupt.get(), timeout,
ignorePrevious);
@@ -367,196 +347,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
}
}
static void ProcessInterruptDigitalAsynchronous(const char* name, void* param,
const struct HAL_Value* value) {
// void* is a HAL handle
// convert to uintptr_t first, then to handle
uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
auto interrupt = interruptHandles->Get(handle);
if (interrupt == nullptr) {
return;
}
// Have a valid interrupt
if (value->type != HAL_Type::HAL_BOOLEAN) {
return;
}
bool retVal = value->data.v_boolean;
// If no change in interrupt, return;
if (retVal == interrupt->previousState) {
return;
}
int32_t mask = 0;
if (interrupt->previousState) {
interrupt->previousState = retVal;
interrupt->fallingTimestamp = hal::GetFPGATime();
mask = 1 << (8 + interrupt->index);
if (!interrupt->fireOnDown) {
return;
}
} else {
interrupt->previousState = retVal;
interrupt->risingTimestamp = hal::GetFPGATime();
mask = 1 << (interrupt->index);
if (!interrupt->fireOnUp) {
return;
}
}
// run callback
auto callback = interrupt->callbackFunction;
if (callback == nullptr) {
return;
}
callback(mask, interrupt->callbackParam);
}
static void ProcessInterruptAnalogAsynchronous(const char* name, void* param,
const struct HAL_Value* value) {
// void* is a HAL handle
// convert to intptr_t first, then to handle
uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
auto interrupt = interruptHandles->Get(handle);
if (interrupt == nullptr) {
return;
}
// Have a valid interrupt
if (value->type != HAL_Type::HAL_DOUBLE) {
return;
}
int32_t status = 0;
bool retVal = GetAnalogTriggerValue(interrupt->portHandle,
interrupt->trigType, &status);
if (status != 0) {
return;
}
// If no change in interrupt, return;
if (retVal == interrupt->previousState) {
return;
}
int mask = 0;
if (interrupt->previousState) {
interrupt->previousState = retVal;
interrupt->fallingTimestamp = hal::GetFPGATime();
if (!interrupt->fireOnDown) {
return;
}
mask = 1 << (8 + interrupt->index);
} else {
interrupt->previousState = retVal;
interrupt->risingTimestamp = hal::GetFPGATime();
if (!interrupt->fireOnUp) {
return;
}
mask = 1 << (interrupt->index);
}
// run callback
auto callback = interrupt->callbackFunction;
if (callback == nullptr) {
return;
}
callback(mask, interrupt->callbackParam);
}
static void EnableInterruptsDigital(HAL_InterruptHandle handle,
Interrupt* interrupt) {
int32_t status = 0;
int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
if (status != 0) {
return;
}
interrupt->previousState = SimDIOData[digitalIndex].value;
int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
&ProcessInterruptDigitalAsynchronous,
reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
interrupt->callbackId = uid;
}
static void EnableInterruptsAnalog(HAL_InterruptHandle handle,
Interrupt* interrupt) {
int32_t status = 0;
int32_t analogIndex =
GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
if (status != 0) {
return;
}
status = 0;
interrupt->previousState = GetAnalogTriggerValue(
interrupt->portHandle, interrupt->trigType, &status);
if (status != 0) {
return;
}
int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
&ProcessInterruptAnalogAsynchronous,
reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
interrupt->callbackId = uid;
}
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
int32_t* status) {
auto interrupt = interruptHandles->Get(interruptHandle);
if (interrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
// If we have not had a callback set, error out
if (interrupt->callbackFunction == nullptr) {
*status = INCOMPATIBLE_STATE;
return;
}
// EnableInterrupts has already been called
if (interrupt->callbackId >= 0) {
// We can double enable safely.
return;
}
if (interrupt->isAnalog) {
EnableInterruptsAnalog(interruptHandle, interrupt.get());
} else {
EnableInterruptsDigital(interruptHandle, interrupt.get());
}
}
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
int32_t* status) {
auto interrupt = interruptHandles->Get(interruptHandle);
if (interrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
// No need to disable if we are already disabled
if (interrupt->callbackId < 0) {
return;
}
if (interrupt->isAnalog) {
// Do analog
int32_t status = 0;
int32_t analogIndex =
GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
if (status != 0) {
return;
}
SimAnalogInData[analogIndex].voltage.CancelCallback(interrupt->callbackId);
} else {
int32_t status = 0;
int32_t digitalIndex =
GetDigitalInputChannel(interrupt->portHandle, &status);
if (status != 0) {
return;
}
SimDIOData[digitalIndex].value.CancelCallback(interrupt->callbackId);
}
interrupt->callbackId = -1;
}
int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
int32_t* status) {
auto interrupt = interruptHandles->Get(interruptHandle);
@@ -602,24 +392,6 @@ void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
interrupt->trigType = analogTriggerType;
interrupt->portHandle = digitalSourceHandle;
}
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
HAL_InterruptHandlerFunction handler,
void* param, int32_t* status) {
auto interrupt = interruptHandles->Get(interruptHandle);
if (interrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
interrupt->callbackFunction = handler;
interrupt->callbackParam = param;
}
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
HAL_InterruptHandlerFunction handler,
void* param, int32_t* status) {
HAL_AttachInterruptHandler(interruptHandle, handler, param, status);
}
void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
HAL_Bool risingEdge, HAL_Bool fallingEdge,
@@ -636,6 +408,19 @@ void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
int32_t* status) {
// Requires a fairly large rewrite to get working
auto interrupt = interruptHandles->Get(interruptHandle);
if (interrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
synchronousInterruptHandles->ForEach(
[interruptHandle](SynchronousWaitDataHandle handle,
SynchronousWaitData* data) {
if (data->interruptHandle == interruptHandle) {
data->waitPredicate = true;
data->waitCond.notify_all();
}
});
}
} // extern "C"