ComponentManager.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * ComponentManager.cpp
  3. * --------------------
  4. * Purpose: Manages loading of optional components.
  5. * Notes : (currently none)
  6. * Authors: Joern Heusipp
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include "ComponentManager.h"
  12. #include "mpt/mutex/mutex.hpp"
  13. #include "Logging.h"
  14. OPENMPT_NAMESPACE_BEGIN
  15. ComponentBase::ComponentBase(ComponentType type)
  16. : m_Type(type)
  17. , m_Initialized(false)
  18. , m_Available(false)
  19. {
  20. return;
  21. }
  22. ComponentBase::~ComponentBase()
  23. {
  24. return;
  25. }
  26. void ComponentBase::SetInitialized()
  27. {
  28. m_Initialized = true;
  29. }
  30. void ComponentBase::SetAvailable()
  31. {
  32. m_Available = true;
  33. }
  34. ComponentType ComponentBase::GetType() const
  35. {
  36. return m_Type;
  37. }
  38. bool ComponentBase::IsInitialized() const
  39. {
  40. return m_Initialized;
  41. }
  42. bool ComponentBase::IsAvailable() const
  43. {
  44. return m_Initialized && m_Available;
  45. }
  46. mpt::ustring ComponentBase::GetVersion() const
  47. {
  48. return mpt::ustring();
  49. }
  50. void ComponentBase::Initialize()
  51. {
  52. if(IsInitialized())
  53. {
  54. return;
  55. }
  56. if(DoInitialize())
  57. {
  58. SetAvailable();
  59. }
  60. SetInitialized();
  61. }
  62. #if defined(MODPLUG_TRACKER)
  63. ComponentLibrary::ComponentLibrary(ComponentType type)
  64. : ComponentBase(type)
  65. , m_BindFailed(false)
  66. {
  67. return;
  68. }
  69. ComponentLibrary::~ComponentLibrary()
  70. {
  71. return;
  72. }
  73. bool ComponentLibrary::AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath)
  74. {
  75. if(m_Libraries[libName].IsValid())
  76. {
  77. // prefer previous
  78. return true;
  79. }
  80. mpt::Library lib(libPath);
  81. if(!lib.IsValid())
  82. {
  83. return false;
  84. }
  85. m_Libraries[libName] = lib;
  86. return true;
  87. }
  88. void ComponentLibrary::ClearLibraries()
  89. {
  90. m_Libraries.clear();
  91. }
  92. void ComponentLibrary::SetBindFailed()
  93. {
  94. m_BindFailed = true;
  95. }
  96. void ComponentLibrary::ClearBindFailed()
  97. {
  98. m_BindFailed = false;
  99. }
  100. bool ComponentLibrary::HasBindFailed() const
  101. {
  102. return m_BindFailed;
  103. }
  104. mpt::Library ComponentLibrary::GetLibrary(const std::string &libName) const
  105. {
  106. const auto it = m_Libraries.find(libName);
  107. if(it == m_Libraries.end())
  108. {
  109. return mpt::Library();
  110. }
  111. return it->second;
  112. }
  113. #endif // MODPLUG_TRACKER
  114. #if MPT_COMPONENT_MANAGER
  115. ComponentFactoryBase::ComponentFactoryBase(const std::string &id, const std::string &settingsKey)
  116. : m_ID(id)
  117. , m_SettingsKey(settingsKey)
  118. {
  119. return;
  120. }
  121. ComponentFactoryBase::~ComponentFactoryBase()
  122. {
  123. return;
  124. }
  125. std::string ComponentFactoryBase::GetID() const
  126. {
  127. return m_ID;
  128. }
  129. std::string ComponentFactoryBase::GetSettingsKey() const
  130. {
  131. return m_SettingsKey;
  132. }
  133. void ComponentFactoryBase::PreConstruct() const
  134. {
  135. MPT_LOG_GLOBAL(LogInformation, "Components",
  136. MPT_UFORMAT("Constructing Component {}")
  137. ( mpt::ToUnicode(mpt::Charset::ASCII, m_ID)
  138. )
  139. );
  140. }
  141. void ComponentFactoryBase::Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const
  142. {
  143. if(componentManager.IsComponentBlocked(GetSettingsKey()))
  144. {
  145. return;
  146. }
  147. componentManager.InitializeComponent(component);
  148. }
  149. // Global list of component register functions.
  150. // We do not use a global scope static list head because the corresponding
  151. // mutex would be no POD type and would thus not be safe to be usable in
  152. // zero-initialized state.
  153. // Function scope static initialization is guaranteed to be thread safe
  154. // in C++11.
  155. // We use this implementation to be future-proof.
  156. // MSVC currently does not exploit the possibility of using multiple threads
  157. // for global lifetime object's initialization.
  158. // An implementation with a simple global list head and no mutex at all would
  159. // thus work fine for MSVC (currently).
  160. static mpt::mutex & ComponentListMutex()
  161. {
  162. static mpt::mutex g_ComponentListMutex;
  163. return g_ComponentListMutex;
  164. }
  165. static ComponentListEntry * & ComponentListHead()
  166. {
  167. static ComponentListEntry g_ComponentListHeadEmpty = {nullptr, nullptr};
  168. static ComponentListEntry *g_ComponentListHead = &g_ComponentListHeadEmpty;
  169. return g_ComponentListHead;
  170. }
  171. bool ComponentListPush(ComponentListEntry *entry)
  172. {
  173. mpt::lock_guard<mpt::mutex> guard(ComponentListMutex());
  174. #if MPT_MSVC_BEFORE(2019,0)
  175. // Guard against VS2017 compiler bug causing repeated initialization of inline variables.
  176. // See <https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876>.
  177. if(entry->next)
  178. {
  179. return false;
  180. }
  181. #endif
  182. entry->next = ComponentListHead();
  183. ComponentListHead() = entry;
  184. return true;
  185. }
  186. static std::shared_ptr<ComponentManager> g_ComponentManager;
  187. void ComponentManager::Init(const IComponentManagerSettings &settings)
  188. {
  189. MPT_LOG_GLOBAL(LogInformation, "Components", U_("Init"));
  190. // cannot use make_shared because the constructor is private
  191. g_ComponentManager = std::shared_ptr<ComponentManager>(new ComponentManager(settings));
  192. }
  193. void ComponentManager::Release()
  194. {
  195. MPT_LOG_GLOBAL(LogInformation, "Components", U_("Release"));
  196. g_ComponentManager = nullptr;
  197. }
  198. std::shared_ptr<ComponentManager> ComponentManager::Instance()
  199. {
  200. return g_ComponentManager;
  201. }
  202. ComponentManager::ComponentManager(const IComponentManagerSettings &settings)
  203. : m_Settings(settings)
  204. {
  205. mpt::lock_guard<mpt::mutex> guard(ComponentListMutex());
  206. for(ComponentListEntry *entry = ComponentListHead(); entry; entry = entry->next)
  207. {
  208. if(entry->reg)
  209. {
  210. entry->reg(*this);
  211. }
  212. }
  213. }
  214. void ComponentManager::Register(const IComponentFactory &componentFactory)
  215. {
  216. if(m_Components.find(componentFactory.GetID()) != m_Components.end())
  217. {
  218. return;
  219. }
  220. RegisteredComponent registeredComponent;
  221. registeredComponent.settingsKey = componentFactory.GetSettingsKey();
  222. registeredComponent.factoryMethod = componentFactory.GetStaticConstructor();
  223. registeredComponent.instance = nullptr;
  224. registeredComponent.weakInstance = std::weak_ptr<IComponent>();
  225. m_Components.insert(std::make_pair(componentFactory.GetID(), registeredComponent));
  226. }
  227. void ComponentManager::Startup()
  228. {
  229. MPT_LOG_GLOBAL(LogDebug, "Components", U_("Startup"));
  230. if(m_Settings.LoadOnStartup())
  231. {
  232. for(auto &it : m_Components)
  233. {
  234. it.second.instance = it.second.factoryMethod(*this);
  235. it.second.weakInstance = it.second.instance;
  236. }
  237. }
  238. if(!m_Settings.KeepLoaded())
  239. {
  240. for(auto &it : m_Components)
  241. {
  242. it.second.instance = nullptr;
  243. }
  244. }
  245. }
  246. bool ComponentManager::IsComponentBlocked(const std::string &settingsKey) const
  247. {
  248. if(settingsKey.empty())
  249. {
  250. return false;
  251. }
  252. return m_Settings.IsBlocked(settingsKey);
  253. }
  254. void ComponentManager::InitializeComponent(std::shared_ptr<IComponent> component) const
  255. {
  256. if(!component)
  257. {
  258. return;
  259. }
  260. if(component->IsInitialized())
  261. {
  262. return;
  263. }
  264. component->Initialize();
  265. }
  266. std::shared_ptr<const IComponent> ComponentManager::GetComponent(const IComponentFactory &componentFactory)
  267. {
  268. std::shared_ptr<IComponent> component = nullptr;
  269. auto it = m_Components.find(componentFactory.GetID());
  270. if(it != m_Components.end())
  271. { // registered component
  272. if((*it).second.instance)
  273. { // loaded
  274. component = (*it).second.instance;
  275. } else
  276. { // not loaded
  277. component = (*it).second.weakInstance.lock();
  278. if(!component)
  279. {
  280. component = (*it).second.factoryMethod(*this);
  281. }
  282. if(m_Settings.KeepLoaded())
  283. { // keep the component loaded
  284. (*it).second.instance = component;
  285. }
  286. (*it).second.weakInstance = component;
  287. }
  288. } else
  289. { // unregistered component
  290. component = componentFactory.Construct(*this);
  291. }
  292. MPT_ASSERT(component);
  293. return component;
  294. }
  295. std::shared_ptr<const IComponent> ComponentManager::ReloadComponent(const IComponentFactory &componentFactory)
  296. {
  297. std::shared_ptr<IComponent> component = nullptr;
  298. auto it = m_Components.find(componentFactory.GetID());
  299. if(it != m_Components.end())
  300. { // registered component
  301. if((*it).second.instance)
  302. { // loaded
  303. (*it).second.instance = nullptr;
  304. if(!(*it).second.weakInstance.expired())
  305. {
  306. throw std::runtime_error("Component not completely unloaded. Cannot reload.");
  307. }
  308. (*it).second.weakInstance = std::weak_ptr<IComponent>();
  309. }
  310. // not loaded
  311. component = (*it).second.factoryMethod(*this);
  312. if(m_Settings.KeepLoaded())
  313. { // keep the component loaded
  314. (*it).second.instance = component;
  315. }
  316. (*it).second.weakInstance = component;
  317. } else
  318. { // unregistered component
  319. component = componentFactory.Construct(*this);
  320. }
  321. MPT_ASSERT(component);
  322. return component;
  323. }
  324. std::vector<std::string> ComponentManager::GetRegisteredComponents() const
  325. {
  326. std::vector<std::string> result;
  327. result.reserve(m_Components.size());
  328. for(const auto &it : m_Components)
  329. {
  330. result.push_back(it.first);
  331. }
  332. return result;
  333. }
  334. ComponentInfo ComponentManager::GetComponentInfo(std::string name) const
  335. {
  336. ComponentInfo result;
  337. result.name = name;
  338. result.state = ComponentStateUnregistered;
  339. result.settingsKey = "";
  340. result.type = ComponentTypeUnknown;
  341. const auto it = m_Components.find(name);
  342. if(it == m_Components.end())
  343. {
  344. result.state = ComponentStateUnregistered;
  345. return result;
  346. }
  347. result.settingsKey = it->second.settingsKey;
  348. if(IsComponentBlocked(it->second.settingsKey))
  349. {
  350. result.state = ComponentStateBlocked;
  351. return result;
  352. }
  353. std::shared_ptr<IComponent> component = it->second.instance;
  354. if(!component)
  355. {
  356. component = it->second.weakInstance.lock();
  357. }
  358. if(!component)
  359. {
  360. result.state = ComponentStateUnintialized;
  361. return result;
  362. }
  363. result.type = component->GetType();
  364. if(!component->IsInitialized())
  365. {
  366. result.state = ComponentStateUnintialized;
  367. return result;
  368. }
  369. if(!component->IsAvailable())
  370. {
  371. result.state = ComponentStateUnavailable;
  372. return result;
  373. }
  374. result.state = ComponentStateAvailable;
  375. return result;
  376. }
  377. mpt::PathString ComponentManager::GetComponentPath() const
  378. {
  379. return m_Settings.Path();
  380. }
  381. #endif // MPT_COMPONENT_MANAGER
  382. OPENMPT_NAMESPACE_END