[Orxonox-commit 5879] r10539 - in code/branches/core7/src/libraries/core: . class module object

landauf at orxonox.net landauf at orxonox.net
Sun Jun 7 12:10:25 CEST 2015


Author: landauf
Date: 2015-06-07 12:10:24 +0200 (Sun, 07 Jun 2015)
New Revision: 10539

Modified:
   code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.cc
   code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.h
   code/branches/core7/src/libraries/core/class/Identifier.h
   code/branches/core7/src/libraries/core/module/ModuleInstance.h
   code/branches/core7/src/libraries/core/object/Context.cc
   code/branches/core7/src/libraries/core/object/Context.h
Log:
destroy objects before deleting identifiers (when unloading a module)

Modified: code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.cc
===================================================================
--- code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.cc	2015-06-07 09:57:31 UTC (rev 10538)
+++ code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.cc	2015-06-07 10:10:24 UTC (rev 10539)
@@ -28,8 +28,10 @@
 
 #include "CoreStaticInitializationHandler.h"
 
+#include "CoreIncludes.h"
 #include "module/ModuleInstance.h"
 #include "class/IdentifierManager.h"
+#include "object/Iterator.h"
 
 namespace orxonox
 {
@@ -52,7 +54,7 @@
 
     void CoreStaticInitializationHandler::loadInstances(ModuleInstance* module)
     {
-        // the order of initialization is important
+        // the order of initialization is important: handlers > identifiers > singletons > everything else
         module->loadAllStaticallyInitializedInstances(StaticInitialization::STATIC_INITIALIZATION_HANDLER);
         module->loadAllStaticallyInitializedInstances(StaticInitialization::IDENTIFIER);
         module->loadAllStaticallyInitializedInstances(StaticInitialization::SCOPED_SINGLETON_WRAPPER);
@@ -71,7 +73,54 @@
         module->unloadAllStaticallyInitializedInstances(StaticInitialization::CONSOLE_COMMAND);
         module->unloadAllStaticallyInitializedInstances(StaticInitialization::COMMAND_LINE_ARGUMENT);
         module->unloadAllStaticallyInitializedInstances(StaticInitialization::SCOPED_SINGLETON_WRAPPER);
+
+        // until now every object (including singletons) of the unloaded identifiers should have been destroyed in a controlled manner.
+        // every remaining object is now destroyed in random order.
+        this->destroyObjects(module);
+
+        // all objects are gone now and we can unload identifiers
         module->unloadAllStaticallyInitializedInstances(StaticInitialization::IDENTIFIER);
         module->unloadAllStaticallyInitializedInstances(StaticInitialization::STATIC_INITIALIZATION_HANDLER);
     }
+
+    void CoreStaticInitializationHandler::destroyObjects(ModuleInstance* module)
+    {
+        // collect all identifiers that are about to be unloaded
+        std::set<Identifier*> identifiers;
+        const std::set<StaticallyInitializedInstance*>& instances = module->getInstances(StaticInitialization::IDENTIFIER);
+        for (std::set<StaticallyInitializedInstance*>::const_iterator it = instances.begin(); it != instances.end(); ++it)
+            identifiers.insert(&static_cast<StaticallyInitializedIdentifier*>(*it)->getIdentifier());
+
+        // destroy objects. some objects may survive this at first because they still have smart pointers pointing at them. this is
+        // ok as long as those smart pointers are held by objects that are also about to be destroyed in the same loop. this means
+        // that objects within one module may reference each other by smart pointers. but it is not allowed that objects from another
+        // module (which is not unloaded) uses smart pointers to point at objects inside the unloaded module. this will lead to a crash.
+        for (std::set<Identifier*>::iterator it = identifiers.begin(); it != identifiers.end(); ++it)
+            (*it)->destroyObjects();
+
+        // check if all objects were really destroyed. this is not the case if an object is referenced by a smart pointer from another
+        // module (or if two objects inside this module reference each other). this will lead to a crash and must be fixed (e.g. by
+        // changing object dependencies; or by changing the logic that allows modules to be unloaded).
+        for (std::set<Identifier*>::iterator it = identifiers.begin(); it != identifiers.end(); ++it)
+        {
+            ObjectListBase* objectList = Context::getRootContext()->getObjectList(*it);
+            if (objectList->size() > 0)
+            {
+                orxout(internal_error) << "There are still " << objectList->size() << " objects of type " << (*it)->getName()
+                    << " after unloading the Identifier. This may lead to a crash" << endl;
+            }
+        }
+
+        // destroy object-lists in all contexts
+        for (std::set<Identifier*>::iterator it_identifier = identifiers.begin(); it_identifier != identifiers.end(); ++it_identifier)
+        {
+            // only do this if the Identifier is not a Context itself; otherwise we delete the list we're iterating over
+            if (!(*it_identifier)->isExactlyA(Class(Context)))
+            {
+                // iterate over all contexts
+                for (ObjectList<Context>::iterator it_context = ObjectList<Context>::begin(); it_context != ObjectList<Context>::end(); ++it_context)
+                    it_context->destroyObjectList((*it_identifier));
+            }
+        }
+    }
 }

Modified: code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.h
===================================================================
--- code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.h	2015-06-07 09:57:31 UTC (rev 10538)
+++ code/branches/core7/src/libraries/core/CoreStaticInitializationHandler.h	2015-06-07 10:10:24 UTC (rev 10539)
@@ -55,6 +55,8 @@
             void loadInstances(ModuleInstance* module);
             void initInstances(ModuleInstance* module);
 
+            void destroyObjects(ModuleInstance* module);
+
             bool bInitInstances_;
     };
 }

Modified: code/branches/core7/src/libraries/core/class/Identifier.h
===================================================================
--- code/branches/core7/src/libraries/core/class/Identifier.h	2015-06-07 09:57:31 UTC (rev 10538)
+++ code/branches/core7/src/libraries/core/class/Identifier.h	2015-06-07 10:10:24 UTC (rev 10539)
@@ -151,7 +151,13 @@
             /// Returns true if the Identifier was completely initialized.
             inline bool isInitialized() const { return this->bInitialized_; }
 
+            virtual void destroyObjects() = 0;
 
+            virtual bool canDynamicCastObjectToIdentifierClass(Identifiable* object) const = 0;
+
+            static bool initConfigValues_s; // TODO: this is a hack - remove it as soon as possible
+
+
             /////////////////////////////
             ////// Class Hierarchy //////
             /////////////////////////////
@@ -214,10 +220,6 @@
             void addXMLPortObjectContainer(const std::string& sectionname, XMLPortObjectContainer* container);
             XMLPortObjectContainer* getXMLPortObjectContainer(const std::string& sectionname);
 
-            virtual bool canDynamicCastObjectToIdentifierClass(Identifiable* object) const = 0;
-
-            static bool initConfigValues_s; // TODO: this is a hack - remove it as soon as possible
-
         protected:
             virtual void createSuperFunctionCaller() const = 0;
 
@@ -296,6 +298,8 @@
             virtual bool canDynamicCastObjectToIdentifierClass(Identifiable* object) const
                 { return dynamic_cast<T*>(object) != 0; }
 
+            virtual void destroyObjects();
+
             static ClassIdentifier<T>* getIdentifier();
 
         private:
@@ -307,6 +311,12 @@
             void addObjectToList(T* object, Listable*);
             void addObjectToList(T* object, Identifiable*);
 
+            void destroyObjects(Listable*);
+            void destroyObjects(void*);
+
+            void destroyObject(Destroyable* object);
+            void destroyObject(void* object);
+
             void updateConfigValues(bool updateChildren, Listable*) const;
             void updateConfigValues(bool updateChildren, Identifiable*) const;
 
@@ -391,6 +401,50 @@
     }
 
     /**
+     * @brief Destroy all objects of this class (must be Listable).
+     * Destroyables are destroyed with destroy(), all other classes with delete.
+     */
+    template <class T>
+    void ClassIdentifier<T>::destroyObjects()
+    {
+        this->destroyObjects((T*)0);
+    }
+
+    /**
+     * @brief Only searches and destroys objects if is a @ref Listable
+     */
+    template <class T>
+    void ClassIdentifier<T>::destroyObjects(Listable*)
+    {
+        ObjectListBase* objectList = Context::getRootContext()->getObjectList(this);
+        ObjectListElement<T>* begin = static_cast<ObjectListElement<T>*>(objectList->begin());
+        ObjectListElement<T>* end = static_cast<ObjectListElement<T>*>(objectList->end());
+        for (typename ObjectList<T>::iterator it = begin; it != end; )
+            this->destroyObject(*(it++));
+    }
+
+    template <class T>
+    void ClassIdentifier<T>::destroyObjects(void*)
+    {
+        // no action
+    }
+
+    /**
+     * @brief Call 'object->destroy()' for Destroyables and 'delete object' for all other types.
+     */
+    template <class T>
+    void ClassIdentifier<T>::destroyObject(Destroyable* object)
+    {
+        object->destroy();
+    }
+
+    template <class T>
+    void ClassIdentifier<T>::destroyObject(void* object)
+    {
+        delete static_cast<Identifiable*>(object);
+    }
+
+    /**
         @brief Updates the config-values of all existing objects of this class by calling their setConfigValues() function.
     */
     template <class T>

Modified: code/branches/core7/src/libraries/core/module/ModuleInstance.h
===================================================================
--- code/branches/core7/src/libraries/core/module/ModuleInstance.h	2015-06-07 09:57:31 UTC (rev 10538)
+++ code/branches/core7/src/libraries/core/module/ModuleInstance.h	2015-06-07 10:10:24 UTC (rev 10539)
@@ -51,6 +51,9 @@
             void loadAllStaticallyInitializedInstances(StaticInitialization::Type type);
             void unloadAllStaticallyInitializedInstances(StaticInitialization::Type type);
 
+            inline const std::set<StaticallyInitializedInstance*>& getInstances(StaticInitialization::Type type)
+                { return this->staticallyInitializedInstancesByType_[type]; }
+
             void deleteAllStaticallyInitializedInstances();
 
             inline const std::string& getName() const

Modified: code/branches/core7/src/libraries/core/object/Context.cc
===================================================================
--- code/branches/core7/src/libraries/core/object/Context.cc	2015-06-07 09:57:31 UTC (rev 10538)
+++ code/branches/core7/src/libraries/core/object/Context.cc	2015-06-07 10:10:24 UTC (rev 10539)
@@ -96,4 +96,11 @@
             this->objectLists_[classID] = new ObjectListBase();
         return this->objectLists_[classID];
     }
+
+    void Context::destroyObjectList(const Identifier* identifier)
+    {
+        ObjectListBase* objectList = this->getObjectList(identifier);
+        delete objectList;
+        this->objectLists_[identifier->getClassID()] = NULL;
+    }
 }

Modified: code/branches/core7/src/libraries/core/object/Context.h
===================================================================
--- code/branches/core7/src/libraries/core/object/Context.h	2015-06-07 09:57:31 UTC (rev 10538)
+++ code/branches/core7/src/libraries/core/object/Context.h	2015-06-07 10:10:24 UTC (rev 10539)
@@ -70,6 +70,8 @@
                     this->getParentContext()->addObject(object);
             }
 
+            void destroyObjectList(const Identifier* identifier);
+
         private:
             Context* parentContext_;
             std::vector<ObjectListBase*> objectLists_;




More information about the Orxonox-commit mailing list