diff --git a/Core/Code/Service/mitkModule.cpp b/Core/Code/Service/mitkModule.cpp index b209b240a1..a0087a3407 100644 --- a/Core/Code/Service/mitkModule.cpp +++ b/Core/Code/Service/mitkModule.cpp @@ -1,225 +1,235 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkModule.h" #include "mitkModuleContext.h" #include "mitkModuleActivator.h" #include "mitkModulePrivate.h" #include "mitkCoreModuleContext_p.h" #include namespace mitk { const std::string& Module::PROP_ID() { static const std::string s("module.id"); return s; } const std::string& Module::PROP_NAME() { static const std::string s("module.name"); return s; } const std::string& Module::PROP_LOCATION() { static const std::string s("module.location"); return s; } const std::string& Module::PROP_MODULE_DEPENDS() { static const std::string s("module.module_depends"); return s; } const std::string& Module::PROP_LIB_DEPENDS() { static const std::string s("module.lib_depends"); return s; } const std::string& Module::PROP_PACKAGE_DEPENDS() { static const std::string s("module.package_depends"); return s; } const std::string& Module::PROP_VERSION() { static const std::string s("module.version"); return s; } const std::string& Module::PROP_QT() { static const std::string s("module.qt"); return s; } Module::Module() : d(0) { } Module::~Module() { delete d; } void Module::Init(CoreModuleContext* coreCtx, ModuleInfo* info) { ModulePrivate* mp = new ModulePrivate(this, coreCtx, info); std::swap(mp, d); delete mp; } +void Module::Uninit() +{ + if (d->moduleContext) + { + delete d->moduleContext; + d->moduleContext = 0; + } + d->moduleActivator = 0; +} + bool Module::IsLoaded() const { return d->moduleContext != 0; } void Module::Start() { if (d->moduleContext) { MITK_WARN << "Module " << d->info.name << " already started."; return; } d->moduleContext = new ModuleContext(this->d); // try // { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADING, this)); // try to get a ModuleActivator instance if (d->info.activatorHook) { try { d->moduleActivator = d->info.activatorHook(); } catch (...) { MITK_ERROR << "Creating the module activator of " << d->info.name << " failed"; throw; } d->moduleActivator->Load(d->moduleContext); } d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADED, this)); // } // catch (...) // { // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); // d->RemoveModuleResources(); // delete d->moduleContext; // d->moduleContext = 0; // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); // MITK_ERROR << "Calling the module activator Load() method of " << d->info.name << " failed!"; // throw; // } } void Module::Stop() { if (d->moduleContext == 0) { MITK_WARN << "Module " << d->info.name << " already stopped."; return; } try { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); if (d->moduleActivator) { d->moduleActivator->Unload(d->moduleContext); } } catch (...) { MITK_ERROR << "Calling the module activator Unload() method of " << d->info.name << " failed!"; try { d->RemoveModuleResources(); } catch (...) {} delete d->moduleContext; d->moduleContext = 0; d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); throw; } d->RemoveModuleResources(); delete d->moduleContext; d->moduleContext = 0; d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); } ModuleContext* Module::GetModuleContext() const { return d->moduleContext; } long Module::GetModuleId() const { return d->info.id; } std::string Module::GetLocation() const { return d->info.location; } std::string Module::GetName() const { return d->info.name; } ModuleVersion Module::GetVersion() const { return d->version; } std::string Module::GetProperty(const std::string& key) const { if (d->properties.count(key) == 0) return ""; return d->properties[key]; } } // end namespace mitk std::ostream& operator<<(std::ostream& os, const mitk::Module& module) { os << "Module[" << "id=" << module.GetModuleId() << ", loc=" << module.GetLocation() << ", name=" << module.GetName() << "]"; return os; } std::ostream& operator<<(std::ostream& os, mitk::Module const * module) { return operator<<(os, *module); } diff --git a/Core/Code/Service/mitkModule.h b/Core/Code/Service/mitkModule.h index a793299260..dbbe618451 100644 --- a/Core/Code/Service/mitkModule.h +++ b/Core/Code/Service/mitkModule.h @@ -1,241 +1,242 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKMODULE_H #define MITKMODULE_H #include "mitkModuleVersion.h" namespace mitk { class CoreModuleContext; class ModuleInfo; class ModuleContext; class ModulePrivate; /** * \ingroup MicroServices * * Represents a MITK module. * *

* A %Module object is the access point to a MITK module. * Each MITK module has an associated %Module object. * *

* A module has unique identity, a long, chosen by the * framework. This identity does not change during the lifecycle of a module. * *

* A module can be in one of two states: *

*

* You can determine the current state by using IsLoaded(). * *

* A module can only execute code when its state is LOADED. * An UNLOADED module is a * zombie and can only be reached because it was loaded before. However, * unloaded modules can be loaded again. * *

* The framework is the only entity that is allowed to create * %Module objects. * * @remarks This class is thread safe. */ class MITK_CORE_EXPORT Module { public: static const std::string& PROP_ID(); static const std::string& PROP_NAME(); static const std::string& PROP_LOCATION(); static const std::string& PROP_MODULE_DEPENDS(); static const std::string& PROP_PACKAGE_DEPENDS(); static const std::string& PROP_LIB_DEPENDS(); static const std::string& PROP_VERSION(); static const std::string& PROP_QT(); ~Module(); /** * Returns this module's current state. * *

* A module can be in only one state at any time. * * @return true if the module is LOADED * false if it is UNLOADED */ bool IsLoaded() const; /** * Returns this module's {@link ModuleContext}. The returned * ModuleContext can be used by the caller to act on behalf * of this module. * *

* If this module is not in the LOADED state, then this * module has no valid ModuleContext. This method will * return 0 if this module has no valid * ModuleContext. * * @return A ModuleContext for this module or * 0 if this module has no valid * ModuleContext. */ ModuleContext* GetModuleContext() const; /** * Returns this module's unique identifier. This module is assigned a unique * identifier by the framework when it was loaded. * *

* A module's unique identifier has the following attributes: *

* *

* This method continues to return this module's unique identifier while * this module is in the UNLOADED state. * * @return The unique identifier of this module. */ long GetModuleId() const; /** * Returns this module's location. * *

* The location is the full path to the module's shared library. * This method continues to return this module's location * while this module is in the UNLOADED state. * * @return The string representation of this module's location. */ std::string GetLocation() const; /** * Returns the name of this module as specified by the * MITK_CREATE_MODULE CMake macro. The module * name together with a version must identify a unique module. * *

* This method continues to return this module's name while * this module is in the UNLOADED state. * * @return The name of this module. */ std::string GetName() const; /** * Returns the version of this module as specified by the * MITK_CREATE_MODULE CMake macro. If this module does not have a * specified version then {@link ModuleVersion#EmptyVersion} is returned. * *

* This method continues to return this module's version while * this module is in the UNLOADED state. * * @return The version of this module. */ ModuleVersion GetVersion() const; /** * Returns the value of the specified property for this module. The * method returns an empty string if the property is not found. * * @param key The name of the requested property. * @return The value of the requested property, or an empty string * if the property is undefined. */ std::string GetProperty(const std::string& key) const; private: friend class ModuleRegistry; friend class ServiceReferencePrivate; ModulePrivate* d; Module(); Module(const Module&); void Init(CoreModuleContext* coreCtx, ModuleInfo* info); + void Uninit(); void Start(); void Stop(); }; } #ifdef MITK_HAS_UNORDERED_MAP_H namespace std { #elif defined(__GNUC__) namespace __gnu_cxx { #else namespace itk { #endif template class hash; template<> class hash { public: std::size_t operator()(const mitk::Module* module) const { #ifdef MITK_HAS_HASH_SIZE_T return hash()(reinterpret_cast(module)); #else std::size_t key = reinterpret_cast(module); return std::size_t(key & (~0U)); #endif } }; /** * \ingroup MicroServices */ namespace ModuleConstants { } } /** * \ingroup MicroServices */ MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, const mitk::Module& module); /** * \ingroup MicroServices */ MITK_CORE_EXPORT std::ostream& operator<<(std::ostream& os, mitk::Module const * module); #endif // MITKMODULE_H diff --git a/Core/Code/Service/mitkModulePrivate.cpp b/Core/Code/Service/mitkModulePrivate.cpp index edc5ccbd7b..672b9c660e 100644 --- a/Core/Code/Service/mitkModulePrivate.cpp +++ b/Core/Code/Service/mitkModulePrivate.cpp @@ -1,143 +1,144 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkModulePrivate.h" #include "mitkModule.h" #include "mitkCoreModuleContext_p.h" #include "mitkServiceRegistration.h" #include "mitkServiceReferencePrivate.h" namespace mitk { AtomicInt ModulePrivate::idCounter; ModulePrivate::ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info) : coreCtx(coreCtx), info(*info), moduleContext(0), moduleActivator(0), q(qq) { std::stringstream propId; propId << this->info.id; properties[Module::PROP_ID()] = propId.str(); std::stringstream propModuleDepends; std::stringstream propLibDepends; std::stringstream propPackageDepends; int counter = 0; int counter2 = 0; std::stringstream ss(this->info.moduleDeps); while (ss) { std::string moduleDep; ss >> moduleDep; if (!moduleDep.empty()) { Module* dep = ModuleRegistry::GetModule(moduleDep); if (dep) { requiresIds.push_back(dep->GetModuleId()); if (counter > 0) propModuleDepends << ", "; propModuleDepends << moduleDep; ++counter; } else { requiresLibs.push_back(moduleDep); if (counter2 > 0) propLibDepends << ", "; propLibDepends << moduleDep; ++counter2; } } } properties[Module::PROP_MODULE_DEPENDS()] = propModuleDepends.str(); properties[Module::PROP_LIB_DEPENDS()] = propLibDepends.str(); counter = 0; ss.clear(); ss.str(this->info.packageDeps); while (ss) { std::string packageDep; ss >> packageDep; if (!packageDep.empty()) { requiresPackages.push_back(packageDep); if (counter > 0) propPackageDepends << ", "; propPackageDepends << packageDep; ++counter; } } properties[Module::PROP_PACKAGE_DEPENDS()] = propPackageDepends.str(); if (!this->info.version.empty()) { try { version = mitk::ModuleVersion(this->info.version); properties[Module::PROP_VERSION()] = this->info.version; } catch (const std::exception& e) { throw std::invalid_argument(std::string("MITK module does not specify a valid version identifier. Got exception: ") + e.what()); } } properties[Module::PROP_LOCATION()] = this->info.location; properties[Module::PROP_NAME()] = this->info.name; properties[Module::PROP_QT()] = this->info.qtModule ? "true" : "false"; } ModulePrivate::~ModulePrivate() { + delete moduleContext; } void ModulePrivate::RemoveModuleResources() { coreCtx->listeners.RemoveAllListeners(moduleContext); std::list srs; coreCtx->services.GetRegisteredByModule(this, srs); for (std::list::iterator i = srs.begin(); i != srs.end(); ++i) { try { i->Unregister(); } catch (const std::logic_error& /*ignore*/) { // Someone has unregistered the service after stop completed. // This should not occur, but we don't want get stuck in // an illegal state so we catch it. } } srs.clear(); coreCtx->services.GetUsedByModule(q, srs); for (std::list::const_iterator i = srs.begin(); i != srs.end(); ++i) { i->GetReference().d->UngetService(q, false); } } } diff --git a/Core/Code/Service/mitkModuleRegistry.cpp b/Core/Code/Service/mitkModuleRegistry.cpp index 6d00646ed2..9e09d842cb 100644 --- a/Core/Code/Service/mitkModuleRegistry.cpp +++ b/Core/Code/Service/mitkModuleRegistry.cpp @@ -1,179 +1,195 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkModuleRegistry.h" #include "mitkModule.h" #include "mitkModuleInfo.h" #include "mitkModuleContext.h" #include "mitkCoreModuleContext_p.h" #include "mitkStaticInit.h" #include #include namespace mitk { #ifdef MITK_HAS_UNORDERED_MAP_H typedef std::unordered_map ModuleMap; #else typedef itk::hash_map ModuleMap; #endif MITK_GLOBAL_STATIC(CoreModuleContext, coreModuleContext) +template +struct ModuleDeleter +{ + void operator()(GlobalStatic& globalStatic) const + { + ModuleMap* moduleMap = globalStatic.pointer; + for (ModuleMap::const_iterator i = moduleMap->begin(); + i != moduleMap->end(); ++i) + { + delete i->second; + } + DefaultGlobalStaticDeleter defaultDeleter; + defaultDeleter(globalStatic); + } +}; + /** * Table of all installed modules in this framework. - * Key is the module location. + * Key is the module id. */ -MITK_GLOBAL_STATIC(ModuleMap, modules) +MITK_GLOBAL_STATIC_WITH_DELETER(ModuleMap, modules, ModuleDeleter) typedef itk::SimpleFastMutexLock MutexType; typedef itk::MutexLockHolder MutexLocker; /** * Lock for protecting the modules object */ MITK_GLOBAL_STATIC(MutexType, modulesLock) /** * Lock for protecting the register count */ MITK_GLOBAL_STATIC(MutexType, countLock) void ModuleRegistry::Register(ModuleInfo* info) { static long regCount = 0; if (info->id > 0) { // The module was already registered MutexLocker lock(*modulesLock()); Module* module = modules()->operator[](info->id); module->Start(); } else { Module* module = 0; // check if the module is reloaded { MutexLocker lock(*modulesLock()); ModuleMap* map = modules(); for (ModuleMap::const_iterator i = map->begin(); i != map->end(); ++i) { if (i->second->GetLocation() == info->location) { module = i->second; info->id = module->GetModuleId(); } } } if (!module) { module = new Module(); countLock()->Lock(); info->id = ++regCount; countLock()->Unlock(); module->Init(coreModuleContext(), info); MutexLocker lock(*modulesLock()); ModuleMap* map = modules(); map->insert(std::make_pair(info->id, module)); } else { module->Init(coreModuleContext(), info); } module->Start(); } } void ModuleRegistry::UnRegister(const ModuleInfo* info) { // If we are unregistering the mitkCore module, there is // nothing to do. if (info->id == 1) return; MutexLocker lock(*modulesLock()); Module* curr = modules()->operator[](info->id); curr->Stop(); - delete curr->GetModuleContext(); + curr->Uninit(); } Module* ModuleRegistry::GetModule(long id) { MutexLocker lock(*modulesLock()); ModuleMap::const_iterator iter = modules()->find(id); if (iter != modules()->end()) { return iter->second; } return 0; } Module* ModuleRegistry::GetModule(const std::string& name) { MutexLocker lock(*modulesLock()); ModuleMap::const_iterator iter = modules()->begin(); ModuleMap::const_iterator iterEnd = modules()->end(); for (; iter != iterEnd; ++iter) { if (iter->second->GetName() == name) { return iter->second; } } return 0; } void ModuleRegistry::GetModules(std::vector& m) { MutexLocker lock(*modulesLock()); ModuleMap* map = modules(); ModuleMap::const_iterator iter = map->begin(); ModuleMap::const_iterator iterEnd = map->end(); for (; iter != iterEnd; ++iter) { m.push_back(iter->second); } } void ModuleRegistry::GetLoadedModules(std::vector& m) { MutexLocker lock(*modulesLock()); ModuleMap::const_iterator iter = modules()->begin(); ModuleMap::const_iterator iterEnd = modules()->end(); for (; iter != iterEnd; ++iter) { if (iter->second->IsLoaded()) { m.push_back(iter->second); } } } } diff --git a/Core/Code/Service/mitkStaticInit.h b/Core/Code/Service/mitkStaticInit.h index 86b1634786..7c8e8cc989 100644 --- a/Core/Code/Service/mitkStaticInit.h +++ b/Core/Code/Service/mitkStaticInit.h @@ -1,123 +1,158 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. Extracted from qglobal.h from Qt 4.7.3 and adapted for MITK. Original copyright (c) Nokia Corporation. Usage covered by the GNU Lesser General Public License version 2.1 (http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) and the Nokia Qt LGPL Exception version 1.1 (file LGPL_EXCEPTION.txt in Qt 4.7.3 package). =========================================================================*/ #ifndef MITK_STATIC_INIT_H #define MITK_STATIC_INIT_H #include namespace mitk { // POD for MITK_GLOBAL_STATIC template class GlobalStatic { public: T* pointer; bool destroyed; // Guards acces to "pointer". If a "atomic pointer" class is available, // this should be used instead of an explicit mutex. itk::SimpleFastMutexLock mutex; }; +template +struct DefaultGlobalStaticDeleter +{ + void operator()(GlobalStatic& globalStatic) const + { + delete globalStatic.pointer; + globalStatic.pointer = 0; + globalStatic.destroyed = true; + } +}; + // Created as a function-local static to delete a GlobalStatic -template +template class Deleter = DefaultGlobalStaticDeleter> class GlobalStaticDeleter { public: GlobalStatic &globalStatic; GlobalStaticDeleter(GlobalStatic &_globalStatic) : globalStatic(_globalStatic) { } inline ~GlobalStaticDeleter() { - delete globalStatic.pointer; - globalStatic.pointer = 0; - globalStatic.destroyed = true; + Deleter deleter; + deleter(globalStatic); } }; } // namespace mitk #define MITK_GLOBAL_STATIC_INIT(TYPE, NAME) \ static ::mitk::GlobalStatic& this_##NAME() \ { \ static ::mitk::GlobalStatic l = \ { 0, false, itk::SimpleFastMutexLock() }; \ return l; \ } #define MITK_GLOBAL_STATIC(TYPE, NAME) \ MITK_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE; \ bool ok = false; \ { \ this_##NAME().mutex.Lock(); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ this_##NAME().mutex.Unlock(); \ } \ if (!ok) \ delete x; \ else \ static ::mitk::GlobalStaticDeleter cleanup(this_##NAME());\ } \ return this_##NAME().pointer; \ } +#define MITK_GLOBAL_STATIC_WITH_DELETER(TYPE, NAME, DELETER) \ + MITK_GLOBAL_STATIC_INIT(TYPE, NAME) \ + static TYPE *NAME() \ + { \ + if (!this_##NAME().pointer && !this_##NAME().destroyed) \ + { \ + TYPE *x = new TYPE; \ + bool ok = false; \ + { \ + this_##NAME().mutex.Lock(); \ + if (!this_##NAME().pointer) \ + { \ + this_##NAME().pointer = x; \ + ok = true; \ + } \ + this_##NAME().mutex.Unlock(); \ + } \ + if (!ok) \ + delete x; \ + else \ + static ::mitk::GlobalStaticDeleter cleanup(this_##NAME());\ + } \ + return this_##NAME().pointer; \ + } + #define MITK_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ MITK_GLOBAL_STATIC_INIT(TYPE, NAME) \ static TYPE *NAME() \ { \ if (!this_##NAME().pointer && !this_##NAME().destroyed) \ { \ TYPE *x = new TYPE ARGS; \ bool ok = false; \ { \ this_##NAME().mutex.Lock(); \ if (!this_##NAME().pointer) \ { \ this_##NAME().pointer = x; \ ok = true; \ } \ this_##NAME().mutex.Unlock(); \ } \ if (!ok) \ delete x; \ else \ static ::mitk::GlobalStaticDeleter cleanup(this_##NAME());\ } \ return this_##NAME().pointer; \ } #endif // MITK_STATIC_INIT_H