[wpiutil] Add synchronization primitives

These enable more consistent use of synchronization across the
native libraries.  Users can create Event and Semaphore primitives, but
in addition, libraries can set up any handle as an Event-type signal.
This commit is contained in:
Peter Johnson
2021-08-03 00:05:47 -07:00
parent e32499c546
commit 87e34967ef
7 changed files with 1424 additions and 1 deletions

View File

@@ -6,6 +6,7 @@
#include "edu_wpi_first_util_WPIUtilJNI.h"
#include "wpi/PortForwarder.h"
#include "wpi/Synchronization.h"
#include "wpi/jni_util.h"
#include "wpi/timestamp.h"
@@ -14,6 +15,8 @@ using namespace wpi::java;
static bool mockTimeEnabled = false;
static uint64_t mockNow = 0;
static JException interruptedEx;
extern "C" {
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
@@ -22,10 +25,21 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_ERR;
}
interruptedEx = JException(env, "java/lang/InterruptedException");
if (!interruptedEx) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return;
}
interruptedEx.free(env);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
@@ -94,4 +108,169 @@ Java_edu_wpi_first_util_WPIUtilJNI_removePortForwarder
wpi::PortForwarder::GetInstance().Remove(port);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: createEvent
* Signature: (ZZ)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_createEvent
(JNIEnv*, jclass, jboolean manualReset, jboolean initialState)
{
return wpi::CreateEvent(manualReset, initialState);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: destroyEvent
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_destroyEvent
(JNIEnv*, jclass, jint eventHandle)
{
wpi::DestroyEvent(eventHandle);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: setEvent
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_setEvent
(JNIEnv*, jclass, jint eventHandle)
{
wpi::SetEvent(eventHandle);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: resetEvent
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_resetEvent
(JNIEnv*, jclass, jint eventHandle)
{
wpi::ResetEvent(eventHandle);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: createSemaphore
* Signature: (II)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_createSemaphore
(JNIEnv*, jclass, jint initialCount, jint maximumCount)
{
return wpi::CreateSemaphore(initialCount, maximumCount);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: destroySemaphore
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_destroySemaphore
(JNIEnv*, jclass, jint semHandle)
{
wpi::DestroySemaphore(semHandle);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: releaseSemaphore
* Signature: (II)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_releaseSemaphore
(JNIEnv*, jclass, jint semHandle, jint releaseCount)
{
return wpi::ReleaseSemaphore(semHandle, releaseCount);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: waitForObject
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_waitForObject
(JNIEnv* env, jclass, jint handle)
{
if (!wpi::WaitForObject(handle)) {
interruptedEx.Throw(env, "WaitForObject interrupted");
}
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: waitForObjectTimeout
* Signature: (ID)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_waitForObjectTimeout
(JNIEnv* env, jclass, jint handle, jdouble timeout)
{
bool timedOut;
if (!wpi::WaitForObject(handle, timeout, &timedOut) && !timedOut) {
interruptedEx.Throw(env, "WaitForObject interrupted");
return false;
}
return timedOut;
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: waitForObjects
* Signature: ([I)[I
*/
JNIEXPORT jintArray JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_waitForObjects
(JNIEnv* env, jclass, jintArray handles)
{
JIntArrayRef handlesArr{env, handles};
wpi::SmallVector<WPI_Handle, 8> signaledBuf;
signaledBuf.resize(handlesArr.size());
wpi::span<const WPI_Handle> handlesArr2{
reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
handlesArr.size()};
auto signaled = wpi::WaitForObjects(handlesArr2, signaledBuf);
if (signaled.empty()) {
interruptedEx.Throw(env, "WaitForObjects interrupted");
return nullptr;
}
return MakeJIntArray(env, signaled);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: waitForObjectsTimeout
* Signature: ([ID)[I
*/
JNIEXPORT jintArray JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_waitForObjectsTimeout
(JNIEnv* env, jclass, jintArray handles, jdouble timeout)
{
JIntArrayRef handlesArr{env, handles};
wpi::SmallVector<WPI_Handle, 8> signaledBuf;
signaledBuf.resize(handlesArr.size());
wpi::span<const WPI_Handle> handlesArr2{
reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
handlesArr.size()};
bool timedOut;
auto signaled =
wpi::WaitForObjects(handlesArr2, signaledBuf, timeout, &timedOut);
if (signaled.empty() && !timedOut) {
interruptedEx.Throw(env, "WaitForObjects interrupted");
return nullptr;
}
return MakeJIntArray(env, signaled);
}
} // extern "C"