diff --git a/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp b/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp index 0cfe58ac7a..a8c82bfa91 100644 --- a/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp +++ b/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp @@ -30,6 +30,22 @@ static wpi::mutex* getManagedStaticMutex() { return ManagedStaticMutex; } +void ManagedStaticBase::RegisterManagedStatic(void* created, + void (*Deleter)(void*)) const { + std::scoped_lock Lock(*getManagedStaticMutex()); + + if (!Ptr.load(std::memory_order_relaxed)) { + void *Tmp = created; + + Ptr.store(Tmp, std::memory_order_release); + DeleterFn = Deleter; + + // Add to list of managed statics. + Next = StaticList; + StaticList = this; + } +} + void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(), void (*Deleter)(void*)) const { assert(Creator); diff --git a/wpiutil/src/main/native/include/wpi/ManagedStatic.h b/wpiutil/src/main/native/include/wpi/ManagedStatic.h index b99ad66547..28c11fa152 100644 --- a/wpiutil/src/main/native/include/wpi/ManagedStatic.h +++ b/wpiutil/src/main/native/include/wpi/ManagedStatic.h @@ -43,6 +43,7 @@ protected: mutable const ManagedStaticBase *Next; void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const; + void RegisterManagedStatic(void *created, void (*deleter)(void*)) const; public: /// isConstructed - Return true if this object has not been created yet. @@ -60,6 +61,12 @@ template , class Deleter = object_deleter> class ManagedStatic : public ManagedStaticBase { public: + ManagedStatic() = default; + + ManagedStatic(C* created, void(*deleter)(void*)) { + RegisterManagedStatic(created, deleter); + } + // Accessors. C &operator*() { void *Tmp = Ptr.load(std::memory_order_acquire); diff --git a/wpiutil/src/test/native/ManagedStaticTest.cpp b/wpiutil/src/test/native/ManagedStaticTest.cpp new file mode 100644 index 0000000000..81a4b9ce1a --- /dev/null +++ b/wpiutil/src/test/native/ManagedStaticTest.cpp @@ -0,0 +1,60 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2019 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "wpi/ManagedStatic.h" // NOLINT(build/include_order) + +#include "gtest/gtest.h" + +static int refCount = 0; + +struct StaticTestClass { + StaticTestClass() { refCount++; } + ~StaticTestClass() { refCount--; } + + void Func() {} +}; + +namespace wpi { +TEST(ManagedStaticTest, LazyDoesNotInitialize) { + { + refCount = 0; + wpi::ManagedStatic managedStatic; + ASSERT_EQ(refCount, 0); + } + ASSERT_EQ(refCount, 0); + wpi_shutdown(); +} + +TEST(ManagedStaticTest, LazyInitDoesntDestruct) { + { + refCount = 0; + wpi::ManagedStatic managedStatic; + ASSERT_EQ(refCount, 0); + managedStatic->Func(); + ASSERT_EQ(refCount, 1); + } + ASSERT_EQ(refCount, 1); + wpi_shutdown(); + ASSERT_EQ(refCount, 0); +} + +TEST(ManagedStaticTest, EagerInit) { + { + refCount = 0; + StaticTestClass* test = new StaticTestClass{}; + ASSERT_EQ(refCount, 1); + wpi::ManagedStatic managedStatic( + test, [](void* val) { delete static_cast(val); }); + ASSERT_EQ(refCount, 1); + managedStatic->Func(); + ASSERT_EQ(refCount, 1); + } + ASSERT_EQ(refCount, 1); + wpi_shutdown(); + ASSERT_EQ(refCount, 0); +} +} // namespace wpi