diff --git a/hal/src/main/java/edu/wpi/first/hal/HAL.java b/hal/src/main/java/edu/wpi/first/hal/HAL.java index c132a58e45..ca1e90c2d0 100644 --- a/hal/src/main/java/edu/wpi/first/hal/HAL.java +++ b/hal/src/main/java/edu/wpi/first/hal/HAL.java @@ -18,6 +18,8 @@ public final class HAL extends JNIWrapper { public static native boolean initialize(int timeout, int mode); + public static native void shutdown(); + public static native boolean hasMain(); public static native void runMain(); diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp index 7e41b3f751..17ef0b9cb2 100644 --- a/hal/src/main/native/athena/HAL.cpp +++ b/hal/src/main/native/athena/HAL.cpp @@ -420,6 +420,8 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) { return true; } +void HAL_Shutdown(void) {} + int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context, const char* feature) { if (feature == nullptr) { diff --git a/hal/src/main/native/cpp/jni/HAL.cpp b/hal/src/main/native/cpp/jni/HAL.cpp index 421dc38b59..3d736bfcbe 100644 --- a/hal/src/main/native/cpp/jni/HAL.cpp +++ b/hal/src/main/native/cpp/jni/HAL.cpp @@ -36,6 +36,18 @@ Java_edu_wpi_first_hal_HAL_initialize return HAL_Initialize(timeout, mode); } +/* + * Class: edu_wpi_first_hal_HAL + * Method: shutdown + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_HAL_shutdown + (JNIEnv*, jclass) +{ + return HAL_Shutdown(); +} + /* * Class: edu_wpi_first_hal_HAL * Method: hasMain diff --git a/hal/src/main/native/include/hal/Extensions.h b/hal/src/main/native/include/hal/Extensions.h index aa1b44cf51..13de7f87f3 100644 --- a/hal/src/main/native/include/hal/Extensions.h +++ b/hal/src/main/native/include/hal/Extensions.h @@ -25,7 +25,10 @@ */ typedef int halsim_extension_init_func_t(void); +#ifdef __cplusplus extern "C" { +#endif + /** * Loads a single extension from a direct path. * @@ -82,5 +85,17 @@ void HAL_RegisterExtensionListener(void* param, * @param showMessage true to show message, false to not. */ void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage); + +/** + * Registers a function to be called from HAL_Shutdown(). This is intended + * for use only by simulation extensions. + * + * @param param parameter data to pass to callback function + * @param func callback function + */ +void HAL_OnShutdown(void* param, void (*func)(void*)); + +#ifdef __cplusplus } // extern "C" +#endif /** @} */ diff --git a/hal/src/main/native/include/hal/HALBase.h b/hal/src/main/native/include/hal/HALBase.h index 308788e1cc..ee5b054788 100644 --- a/hal/src/main/native/include/hal/HALBase.h +++ b/hal/src/main/native/include/hal/HALBase.h @@ -149,6 +149,14 @@ uint64_t HAL_ExpandFPGATime(uint32_t unexpanded_lower, int32_t* status); */ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode); +/** + * Call this to shut down HAL. + * + * This must be called at termination of the robot program to avoid potential + * segmentation faults with simulation extensions at exit. + */ +void HAL_Shutdown(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp index 92b19d3e81..64c4a1090d 100644 --- a/hal/src/main/native/sim/HAL.cpp +++ b/hal/src/main/native/sim/HAL.cpp @@ -7,8 +7,11 @@ #include "hal/HAL.h" +#include + #include #include +#include #ifdef _WIN32 #include @@ -28,6 +31,8 @@ using namespace hal; static HAL_RuntimeType runtimeType{HAL_Mock}; +static wpi::spinlock gOnShutdownMutex; +static std::vector> gOnShutdown; namespace hal { namespace init { @@ -312,6 +317,22 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) { return true; // Add initialization if we need to at a later point } +void HAL_Shutdown(void) { + std::vector> funcs; + { + std::scoped_lock lock(gOnShutdownMutex); + funcs.swap(gOnShutdown); + } + for (auto&& func : funcs) { + func.second(func.first); + } +} + +void HAL_OnShutdown(void* param, void (*func)(void*)) { + std::scoped_lock lock(gOnShutdownMutex); + gOnShutdown.emplace_back(param, func); +} + int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context, const char* feature) { return 0; // Do nothing for now diff --git a/wpilibc/src/main/native/include/frc/RobotBase.h b/wpilibc/src/main/native/include/frc/RobotBase.h index a005dd80ef..4139b03655 100644 --- a/wpilibc/src/main/native/include/frc/RobotBase.h +++ b/wpilibc/src/main/native/include/frc/RobotBase.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -89,6 +90,8 @@ int StartRobot() { impl::RunRobot(m, &robot); } + HAL_Shutdown(); + return 0; } diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java index 922377dc8c..9c3e45f3e2 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java @@ -419,6 +419,8 @@ public abstract class RobotBase implements AutoCloseable { runRobot(robotSupplier); } + HAL.shutdown(); + System.exit(0); } }