123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- /*
- * ComponentManager.cpp
- * --------------------
- * Purpose: Manages loading of optional components.
- * Notes : (currently none)
- * Authors: Joern Heusipp
- * OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #include "stdafx.h"
- #include "ComponentManager.h"
- #include "mpt/mutex/mutex.hpp"
- #include "Logging.h"
- OPENMPT_NAMESPACE_BEGIN
- ComponentBase::ComponentBase(ComponentType type)
- : m_Type(type)
- , m_Initialized(false)
- , m_Available(false)
- {
- return;
- }
- ComponentBase::~ComponentBase()
- {
- return;
- }
- void ComponentBase::SetInitialized()
- {
- m_Initialized = true;
- }
- void ComponentBase::SetAvailable()
- {
- m_Available = true;
- }
- ComponentType ComponentBase::GetType() const
- {
- return m_Type;
- }
- bool ComponentBase::IsInitialized() const
- {
- return m_Initialized;
- }
- bool ComponentBase::IsAvailable() const
- {
- return m_Initialized && m_Available;
- }
- mpt::ustring ComponentBase::GetVersion() const
- {
- return mpt::ustring();
- }
- void ComponentBase::Initialize()
- {
- if(IsInitialized())
- {
- return;
- }
- if(DoInitialize())
- {
- SetAvailable();
- }
- SetInitialized();
- }
- #if defined(MODPLUG_TRACKER)
- ComponentLibrary::ComponentLibrary(ComponentType type)
- : ComponentBase(type)
- , m_BindFailed(false)
- {
- return;
- }
- ComponentLibrary::~ComponentLibrary()
- {
- return;
- }
- bool ComponentLibrary::AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath)
- {
- if(m_Libraries[libName].IsValid())
- {
- // prefer previous
- return true;
- }
- mpt::Library lib(libPath);
- if(!lib.IsValid())
- {
- return false;
- }
- m_Libraries[libName] = lib;
- return true;
- }
- void ComponentLibrary::ClearLibraries()
- {
- m_Libraries.clear();
- }
- void ComponentLibrary::SetBindFailed()
- {
- m_BindFailed = true;
- }
- void ComponentLibrary::ClearBindFailed()
- {
- m_BindFailed = false;
- }
- bool ComponentLibrary::HasBindFailed() const
- {
- return m_BindFailed;
- }
- mpt::Library ComponentLibrary::GetLibrary(const std::string &libName) const
- {
- const auto it = m_Libraries.find(libName);
- if(it == m_Libraries.end())
- {
- return mpt::Library();
- }
- return it->second;
- }
- #endif // MODPLUG_TRACKER
- #if MPT_COMPONENT_MANAGER
- ComponentFactoryBase::ComponentFactoryBase(const std::string &id, const std::string &settingsKey)
- : m_ID(id)
- , m_SettingsKey(settingsKey)
- {
- return;
- }
- ComponentFactoryBase::~ComponentFactoryBase()
- {
- return;
- }
- std::string ComponentFactoryBase::GetID() const
- {
- return m_ID;
- }
- std::string ComponentFactoryBase::GetSettingsKey() const
- {
- return m_SettingsKey;
- }
- void ComponentFactoryBase::PreConstruct() const
- {
- MPT_LOG_GLOBAL(LogInformation, "Components",
- MPT_UFORMAT("Constructing Component {}")
- ( mpt::ToUnicode(mpt::Charset::ASCII, m_ID)
- )
- );
- }
- void ComponentFactoryBase::Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const
- {
- if(componentManager.IsComponentBlocked(GetSettingsKey()))
- {
- return;
- }
- componentManager.InitializeComponent(component);
- }
- // Global list of component register functions.
- // We do not use a global scope static list head because the corresponding
- // mutex would be no POD type and would thus not be safe to be usable in
- // zero-initialized state.
- // Function scope static initialization is guaranteed to be thread safe
- // in C++11.
- // We use this implementation to be future-proof.
- // MSVC currently does not exploit the possibility of using multiple threads
- // for global lifetime object's initialization.
- // An implementation with a simple global list head and no mutex at all would
- // thus work fine for MSVC (currently).
- static mpt::mutex & ComponentListMutex()
- {
- static mpt::mutex g_ComponentListMutex;
- return g_ComponentListMutex;
- }
- static ComponentListEntry * & ComponentListHead()
- {
- static ComponentListEntry g_ComponentListHeadEmpty = {nullptr, nullptr};
- static ComponentListEntry *g_ComponentListHead = &g_ComponentListHeadEmpty;
- return g_ComponentListHead;
- }
- bool ComponentListPush(ComponentListEntry *entry)
- {
- mpt::lock_guard<mpt::mutex> guard(ComponentListMutex());
- #if MPT_MSVC_BEFORE(2019,0)
- // Guard against VS2017 compiler bug causing repeated initialization of inline variables.
- // See <https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876>.
- if(entry->next)
- {
- return false;
- }
- #endif
- entry->next = ComponentListHead();
- ComponentListHead() = entry;
- return true;
- }
- static std::shared_ptr<ComponentManager> g_ComponentManager;
- void ComponentManager::Init(const IComponentManagerSettings &settings)
- {
- MPT_LOG_GLOBAL(LogInformation, "Components", U_("Init"));
- // cannot use make_shared because the constructor is private
- g_ComponentManager = std::shared_ptr<ComponentManager>(new ComponentManager(settings));
- }
- void ComponentManager::Release()
- {
- MPT_LOG_GLOBAL(LogInformation, "Components", U_("Release"));
- g_ComponentManager = nullptr;
- }
- std::shared_ptr<ComponentManager> ComponentManager::Instance()
- {
- return g_ComponentManager;
- }
- ComponentManager::ComponentManager(const IComponentManagerSettings &settings)
- : m_Settings(settings)
- {
- mpt::lock_guard<mpt::mutex> guard(ComponentListMutex());
- for(ComponentListEntry *entry = ComponentListHead(); entry; entry = entry->next)
- {
- if(entry->reg)
- {
- entry->reg(*this);
- }
- }
- }
- void ComponentManager::Register(const IComponentFactory &componentFactory)
- {
- if(m_Components.find(componentFactory.GetID()) != m_Components.end())
- {
- return;
- }
- RegisteredComponent registeredComponent;
- registeredComponent.settingsKey = componentFactory.GetSettingsKey();
- registeredComponent.factoryMethod = componentFactory.GetStaticConstructor();
- registeredComponent.instance = nullptr;
- registeredComponent.weakInstance = std::weak_ptr<IComponent>();
- m_Components.insert(std::make_pair(componentFactory.GetID(), registeredComponent));
- }
- void ComponentManager::Startup()
- {
- MPT_LOG_GLOBAL(LogDebug, "Components", U_("Startup"));
- if(m_Settings.LoadOnStartup())
- {
- for(auto &it : m_Components)
- {
- it.second.instance = it.second.factoryMethod(*this);
- it.second.weakInstance = it.second.instance;
- }
- }
- if(!m_Settings.KeepLoaded())
- {
- for(auto &it : m_Components)
- {
- it.second.instance = nullptr;
- }
- }
- }
- bool ComponentManager::IsComponentBlocked(const std::string &settingsKey) const
- {
- if(settingsKey.empty())
- {
- return false;
- }
- return m_Settings.IsBlocked(settingsKey);
- }
- void ComponentManager::InitializeComponent(std::shared_ptr<IComponent> component) const
- {
- if(!component)
- {
- return;
- }
- if(component->IsInitialized())
- {
- return;
- }
- component->Initialize();
- }
- std::shared_ptr<const IComponent> ComponentManager::GetComponent(const IComponentFactory &componentFactory)
- {
- std::shared_ptr<IComponent> component = nullptr;
- auto it = m_Components.find(componentFactory.GetID());
- if(it != m_Components.end())
- { // registered component
- if((*it).second.instance)
- { // loaded
- component = (*it).second.instance;
- } else
- { // not loaded
- component = (*it).second.weakInstance.lock();
- if(!component)
- {
- component = (*it).second.factoryMethod(*this);
- }
- if(m_Settings.KeepLoaded())
- { // keep the component loaded
- (*it).second.instance = component;
- }
- (*it).second.weakInstance = component;
- }
- } else
- { // unregistered component
- component = componentFactory.Construct(*this);
- }
- MPT_ASSERT(component);
- return component;
- }
- std::shared_ptr<const IComponent> ComponentManager::ReloadComponent(const IComponentFactory &componentFactory)
- {
- std::shared_ptr<IComponent> component = nullptr;
- auto it = m_Components.find(componentFactory.GetID());
- if(it != m_Components.end())
- { // registered component
- if((*it).second.instance)
- { // loaded
- (*it).second.instance = nullptr;
- if(!(*it).second.weakInstance.expired())
- {
- throw std::runtime_error("Component not completely unloaded. Cannot reload.");
- }
- (*it).second.weakInstance = std::weak_ptr<IComponent>();
- }
- // not loaded
- component = (*it).second.factoryMethod(*this);
- if(m_Settings.KeepLoaded())
- { // keep the component loaded
- (*it).second.instance = component;
- }
- (*it).second.weakInstance = component;
- } else
- { // unregistered component
- component = componentFactory.Construct(*this);
- }
- MPT_ASSERT(component);
- return component;
- }
- std::vector<std::string> ComponentManager::GetRegisteredComponents() const
- {
- std::vector<std::string> result;
- result.reserve(m_Components.size());
- for(const auto &it : m_Components)
- {
- result.push_back(it.first);
- }
- return result;
- }
- ComponentInfo ComponentManager::GetComponentInfo(std::string name) const
- {
- ComponentInfo result;
- result.name = name;
- result.state = ComponentStateUnregistered;
- result.settingsKey = "";
- result.type = ComponentTypeUnknown;
- const auto it = m_Components.find(name);
- if(it == m_Components.end())
- {
- result.state = ComponentStateUnregistered;
- return result;
- }
- result.settingsKey = it->second.settingsKey;
- if(IsComponentBlocked(it->second.settingsKey))
- {
- result.state = ComponentStateBlocked;
- return result;
- }
- std::shared_ptr<IComponent> component = it->second.instance;
- if(!component)
- {
- component = it->second.weakInstance.lock();
- }
- if(!component)
- {
- result.state = ComponentStateUnintialized;
- return result;
- }
- result.type = component->GetType();
- if(!component->IsInitialized())
- {
- result.state = ComponentStateUnintialized;
- return result;
- }
- if(!component->IsAvailable())
- {
- result.state = ComponentStateUnavailable;
- return result;
- }
- result.state = ComponentStateAvailable;
- return result;
- }
- mpt::PathString ComponentManager::GetComponentPath() const
- {
- return m_Settings.Path();
- }
- #endif // MPT_COMPONENT_MANAGER
- OPENMPT_NAMESPACE_END
|