diff --git a/Source/Foundation/bsfUtility/Utility/BsModule.h b/Source/Foundation/bsfUtility/Utility/BsModule.h index 99f7ad01c..1e1b20c0d 100644 --- a/Source/Foundation/bsfUtility/Utility/BsModule.h +++ b/Source/Foundation/bsfUtility/Utility/BsModule.h @@ -68,7 +68,12 @@ namespace bs if (isStartedUp()) BS_EXCEPT(InternalErrorException, "Trying to start an already started module."); - _instance() = bs_new(std::forward(args)...); + T * test = nullptr; + bool const success = _instance().compare_exchange_strong(test, bs_new(std::forward(args)...)); + + if (!success) + BS_EXCEPT(InternalErrorException, "Race condition when starting module."); + isStartedUp() = true; ((Module*)_instance())->onStartUp(); @@ -86,7 +91,12 @@ namespace bs if (isStartedUp()) BS_EXCEPT(InternalErrorException, "Trying to start an already started module."); - _instance() = bs_new(std::forward(args)...); + T * test = nullptr; + bool const success = _instance().compare_exchange_strong(test, bs_new(std::forward(args)...)); + + if (!success) + BS_EXCEPT(InternalErrorException, "Race condition when starting module."); + isStartedUp() = true; ((Module*)_instance())->onStartUp(); @@ -95,6 +105,18 @@ namespace bs /** Shuts down this module and frees any resources it is using. */ static void shutDown() { + struct ScopeGuard + { + ScopeGuard(Module* inst) + : m_inst(inst) + { } + ~ScopeGuard() + { + bs_delete(inst); + } + Module* m_inst; + }; + if (isDestroyed()) { BS_EXCEPT(InternalErrorException, @@ -107,9 +129,15 @@ namespace bs "Trying to shut down a module which was never started."); } - ((Module*)_instance())->onShutDown(); + Module* const inst = _instance().exchange(nullptr); + + if (nullptr == inst) + BS_EXCEPT(InternalErrorException, "Race condition when starting module."); + + ScopeGuard guard(inst); + + inst->onShutDown(); - bs_delete(_instance()); isDestroyed() = true; } @@ -122,7 +150,7 @@ namespace bs protected: Module() = default; - virtual ~Module() = default; + ~Module() = default; /* * The notion of copying or moving a singleton is rather nonsensical. @@ -149,9 +177,9 @@ namespace bs virtual void onShutDown() {} /** Returns a singleton instance of this module. */ - static T*& _instance() + static std::atomic& _instance() { - static T* inst = nullptr; + static std::atomic inst{nullptr}; return inst; } @@ -160,16 +188,16 @@ namespace bs * * @note If module was never even started, this will return false. */ - static bool& isDestroyed() + static std::atomic& isDestroyed() { - static bool inst = false; + static std::atomic inst{false}; return inst; } /** Checks has the Module been started up. */ - static bool& isStartedUp() + static std::atomic& isStartedUp() { - static bool inst = false; + static std::atomic inst{false}; return inst; } };