[Orxonox-commit 1156] r5877 - in code/branches/core5/src: libraries/core libraries/core/input libraries/util modules/questsystem modules/questsystem/notifications orxonox orxonox/overlays orxonox/sound

rgrieder at orxonox.net rgrieder at orxonox.net
Mon Oct 5 01:34:10 CEST 2009


Author: rgrieder
Date: 2009-10-05 01:34:10 +0200 (Mon, 05 Oct 2009)
New Revision: 5877

Modified:
   code/branches/core5/src/libraries/core/Core.cc
   code/branches/core5/src/libraries/core/ScopedSingletonManager.h
   code/branches/core5/src/libraries/core/input/KeyBinderManager.cc
   code/branches/core5/src/libraries/core/input/KeyDetector.cc
   code/branches/core5/src/libraries/util/Scope.h
   code/branches/core5/src/modules/questsystem/QuestManager.cc
   code/branches/core5/src/modules/questsystem/notifications/NotificationManager.cc
   code/branches/core5/src/orxonox/CameraManager.cc
   code/branches/core5/src/orxonox/LevelManager.cc
   code/branches/core5/src/orxonox/PlayerManager.cc
   code/branches/core5/src/orxonox/overlays/InGameConsole.cc
   code/branches/core5/src/orxonox/sound/SoundManager.cc
Log:
Added new an option for the ScopedSingletonManager that can allow the Singleton to fail (throw an exception).
Also improved exception-safety in Scope so that when for a Singleton fails, the Scope will deactivate all activated listeners and properly destroy itself.

Modified: code/branches/core5/src/libraries/core/Core.cc
===================================================================
--- code/branches/core5/src/libraries/core/Core.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/libraries/core/Core.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -433,7 +433,7 @@
     void Core::preUpdate(const Clock& time)
     {
         // singletons from other libraries
-        ScopedSingletonManager::update(time, ScopeID::Root);
+        ScopedSingletonManager::update<ScopeID::Root>(time);
         if (this->bGraphicsLoaded_)
         {
             // process input events
@@ -441,7 +441,7 @@
             // process gui events
             this->guiManager_->update(time);
             // graphics singletons from other libraries
-            ScopedSingletonManager::update(time, ScopeID::Graphics);
+            ScopedSingletonManager::update<ScopeID::Graphics>(time);
         }
         // process thread commands
         this->tclThreadManager_->update(time);

Modified: code/branches/core5/src/libraries/core/ScopedSingletonManager.h
===================================================================
--- code/branches/core5/src/libraries/core/ScopedSingletonManager.h	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/libraries/core/ScopedSingletonManager.h	2009-10-04 23:34:10 UTC (rev 5877)
@@ -33,11 +33,12 @@
 
 #include <cassert>
 #include <map>
+#include "util/Exception.h"
 #include "util/Scope.h"
 #include "util/Singleton.h"
 
-#define ManageScopedSingleton(className, scope) \
-    static ClassScopedSingletonManager<className, scope> className##ScopedSingletonManager(#className)
+#define ManageScopedSingleton(className, scope, allowedToFail) \
+    static ClassScopedSingletonManager<className, scope, allowedToFail> className##ScopedSingletonManager(#className)
 
 namespace orxonox
 {
@@ -52,8 +53,10 @@
             static void addManager(ScopedSingletonManager* manager);
             static void removeManager(ScopedSingletonManager* manager);
 
-            static void update(const Clock& time, ScopeID::Value scope)
+            template<ScopeID::Value scope>
+            static void update(const Clock& time)
             {
+                assert(Scope<scope>::isActive());
                 for (ManagerMultiMap::iterator it = getManagersByScope().lower_bound(scope); it != getManagersByScope().upper_bound(scope); ++it)
                     it->second->update(time);
             }
@@ -68,7 +71,7 @@
             const ScopeID::Value scope_;
     };
 
-    template <class T, ScopeID::Value scope>
+    template <class T, ScopeID::Value scope, bool allowedToFail>
     class ClassScopedSingletonManager : public ScopedSingletonManager, public ScopeListener
     {
     public:
@@ -82,6 +85,7 @@
 
         ~ClassScopedSingletonManager()
         {
+            assert(singletonPtr_ == NULL);
             ScopedSingletonManager::removeManager(this);
         }
 
@@ -100,6 +104,65 @@
             singletonPtr_ = NULL;
         }
 
+        void destroy(OrxonoxClass*)
+        {
+            singletonPtr_->destroy();
+        }
+        void destroy(void*)
+        {
+            delete singletonPtr_;
+        }
+
+        //! Called every frame by the ScopedSingletonManager
+        void update(const Clock& time)
+        {
+            assert(Scope<scope>::isActive());
+            // assuming T inherits Singleton<T>
+            singletonPtr_->updateSingleton(time);
+        }
+
+    private:
+        T* singletonPtr_;
+    };
+
+    template <class T, ScopeID::Value scope>
+    class ClassScopedSingletonManager<T, scope, true> : public ScopedSingletonManager, public ScopeListener
+    {
+    public:
+        ClassScopedSingletonManager(const std::string& className)
+            : ScopedSingletonManager(className, scope)
+            , ScopeListener(scope)
+            , singletonPtr_(NULL)
+        {
+            ScopedSingletonManager::addManager(this);
+        }
+
+        ~ClassScopedSingletonManager()
+        {
+            assert(singletonPtr_ == NULL);
+            ScopedSingletonManager::removeManager(this);
+        }
+
+        //! Called if the Scope of the Singleton gets active (creates the instance)
+        void activated()
+        {
+            assert(singletonPtr_ == NULL);
+            try
+                { singletonPtr_ = new T(); }
+            catch (...)
+                { COUT(1) << "Singleton creation failed: " << Exception::handleMessage() << std::endl; }
+        }
+
+        //! Called if the Scope of this Singleton gets deactivated (destroys the instance)
+        void deactivated()
+        {
+            if (singletonPtr_ != NULL)
+            {
+                this->destroy(singletonPtr_);
+                singletonPtr_ = NULL;
+            }
+        }
+
         void destroy(OrxonoxClass* ptr)
         {
             singletonPtr_->destroy();
@@ -112,8 +175,10 @@
         //! Called every frame by the ScopedSingletonManager
         void update(const Clock& time)
         {
+            assert(Scope<scope>::isActive());
             // assuming T inherits Singleton<T>
-            singletonPtr_->updateSingleton(time);
+            if (singletonPtr_ != NULL)
+                singletonPtr_->updateSingleton(time);
         }
 
     private:

Modified: code/branches/core5/src/libraries/core/input/KeyBinderManager.cc
===================================================================
--- code/branches/core5/src/libraries/core/input/KeyBinderManager.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/libraries/core/input/KeyBinderManager.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -40,7 +40,7 @@
 namespace orxonox
 {
     KeyBinderManager* KeyBinderManager::singletonPtr_s = 0;
-    ManageScopedSingleton(KeyBinderManager, ScopeID::Graphics);
+    ManageScopedSingleton(KeyBinderManager, ScopeID::Graphics, false);
 
     KeyBinderManager::KeyBinderManager()
         : currentBinder_(NULL)

Modified: code/branches/core5/src/libraries/core/input/KeyDetector.cc
===================================================================
--- code/branches/core5/src/libraries/core/input/KeyDetector.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/libraries/core/input/KeyDetector.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -39,7 +39,7 @@
 {
     std::string KeyDetector::callbackCommand_s = "KeyDetectorKeyPressed";
     KeyDetector* KeyDetector::singletonPtr_s = 0;
-    ManageScopedSingleton(KeyDetector, ScopeID::Graphics);
+    ManageScopedSingleton(KeyDetector, ScopeID::Graphics, false);
 
     KeyDetector::KeyDetector()
         : KeyBinder("")

Modified: code/branches/core5/src/libraries/util/Scope.h
===================================================================
--- code/branches/core5/src/libraries/util/Scope.h	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/libraries/util/Scope.h	2009-10-04 23:34:10 UTC (rev 5877)
@@ -34,7 +34,9 @@
 #include <cassert>
 #include <map>
 #include <set>
+
 #include "Debug.h"
+#include "ScopeGuard.h"
 
 namespace orxonox
 {
@@ -62,7 +64,7 @@
 
         protected:
             //! Constructor: Registers the instance.
-            ScopeListener(ScopeID::Value scope) : scope_(scope)
+            ScopeListener(ScopeID::Value scope) : scope_(scope), bActivated_(false)
                 { ScopeManager::listeners_s[this->scope_].insert(this); }
             //! Destructor: Unregisters the instance.
             virtual ~ScopeListener()
@@ -75,6 +77,7 @@
 
         private:
             ScopeID::Value scope_; //!< Store the scope to unregister on destruction
+            bool bActivated_;
     };
 
     /**
@@ -90,13 +93,26 @@
             //! Constructor: Increases the instance counter and activates the scope if the count went from 0 to 1. Counts >1 don't change anything.
             Scope()
             {
-                ScopeManager::instanceCounts_s[scope]++;
-                assert(ScopeManager::instanceCounts_s[scope] > 0);
-                if (ScopeManager::instanceCounts_s[scope] == 1)
+                try
                 {
-                    for (typename std::set<ScopeListener*>::iterator it = ScopeManager::listeners_s[scope].begin(); it != ScopeManager::listeners_s[scope].end(); )
-                        (*(it++))->activated();
+                    ScopeManager::instanceCounts_s[scope]++;
+                    assert(ScopeManager::instanceCounts_s[scope] > 0);
+                    if (ScopeManager::instanceCounts_s[scope] == 1)
+                    {
+                        Loki::ScopeGuard deactivator = Loki::MakeObjGuard(*this, &Scope::deactivateListeners);
+                        for (typename std::set<ScopeListener*>::iterator it = ScopeManager::listeners_s[scope].begin(); it != ScopeManager::listeners_s[scope].end(); )
+                        {
+                            (*it)->activated();
+                            (*(it++))->bActivated_ = true;
+                        }
+                        deactivator.Dismiss();
+                    }
                 }
+                catch (...)
+                {
+                    ScopeManager::instanceCounts_s[scope]--;
+                    throw;
+                }
             }
 
             //! Destructor: Decreases the instance counter and deactivates the scope if the count went from 1 to 0. Counts >0 don't change anything.
@@ -110,9 +126,23 @@
                     ScopeManager::instanceCounts_s[scope] = 0;
 
                 if (ScopeManager::instanceCounts_s[scope] == 0)
+                    this->deactivateListeners();
+            }
+
+            void deactivateListeners()
+            {
+                for (typename std::set<ScopeListener*>::iterator it = ScopeManager::listeners_s[scope].begin(); it != ScopeManager::listeners_s[scope].end(); )
                 {
-                    for (typename std::set<ScopeListener*>::iterator it = ScopeManager::listeners_s[scope].begin(); it != ScopeManager::listeners_s[scope].end(); )
-                        (*(it++))->deactivated();
+                    if ((*it)->bActivated_)
+                    {
+                        try
+                            { (*it)->deactivated(); }
+                        catch (...)
+                            { COUT(0) << "ScopeListener::deactivated() failed! This MUST NOT happen, fix it!" << std::endl; }
+                        (*(it++))->bActivated_ = false;
+                    }
+                    else
+                        ++it;
                 }
             }
 

Modified: code/branches/core5/src/modules/questsystem/QuestManager.cc
===================================================================
--- code/branches/core5/src/modules/questsystem/QuestManager.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/modules/questsystem/QuestManager.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -56,7 +56,7 @@
 
     //! Pointer to the current (and single) instance of this class.
     /*static*/ QuestManager* QuestManager::singletonPtr_s = NULL;
-    ManageScopedSingleton(QuestManager, ScopeID::Root);
+    ManageScopedSingleton(QuestManager, ScopeID::Root, false);
 
     /**
     @brief

Modified: code/branches/core5/src/modules/questsystem/notifications/NotificationManager.cc
===================================================================
--- code/branches/core5/src/modules/questsystem/notifications/NotificationManager.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/modules/questsystem/notifications/NotificationManager.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -47,7 +47,7 @@
     const std::string NotificationManager::NONE = "none";
 
     NotificationManager* NotificationManager::singletonPtr_s = NULL;
-    ManageScopedSingleton(NotificationManager, ScopeID::Root);
+    ManageScopedSingleton(NotificationManager, ScopeID::Root, false);
 
     /**
     @brief

Modified: code/branches/core5/src/orxonox/CameraManager.cc
===================================================================
--- code/branches/core5/src/orxonox/CameraManager.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/orxonox/CameraManager.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -44,8 +44,8 @@
 
 namespace orxonox
 {
-    ManageScopedSingleton(CameraManager, ScopeID::Graphics);
     CameraManager* CameraManager::singletonPtr_s = 0;
+    ManageScopedSingleton(CameraManager, ScopeID::Graphics, false);
 
     CameraManager::CameraManager()
         : viewport_(GraphicsManager::getInstance().getViewport())

Modified: code/branches/core5/src/orxonox/LevelManager.cc
===================================================================
--- code/branches/core5/src/orxonox/LevelManager.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/orxonox/LevelManager.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -43,8 +43,8 @@
 {
     SetCommandLineArgument(level, "").shortcut("l").information("Default level file (overrides LevelManager::defaultLevelName_ configValue)");
 
-    ManageScopedSingleton(LevelManager, ScopeID::Root);
     LevelManager* LevelManager::singletonPtr_s = 0;
+    ManageScopedSingleton(LevelManager, ScopeID::Root, false);
 
     LevelManager::LevelManager()
     {

Modified: code/branches/core5/src/orxonox/PlayerManager.cc
===================================================================
--- code/branches/core5/src/orxonox/PlayerManager.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/orxonox/PlayerManager.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -38,7 +38,7 @@
 namespace orxonox
 {
     PlayerManager* PlayerManager::singletonPtr_s = 0;
-    ManageScopedSingleton(PlayerManager, ScopeID::Root);
+    ManageScopedSingleton(PlayerManager, ScopeID::Root, false);
 
     PlayerManager::PlayerManager()
     {

Modified: code/branches/core5/src/orxonox/overlays/InGameConsole.cc
===================================================================
--- code/branches/core5/src/orxonox/overlays/InGameConsole.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/orxonox/overlays/InGameConsole.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -61,7 +61,7 @@
     SetConsoleCommand(InGameConsole, closeConsole, true);
 
     InGameConsole* InGameConsole::singletonPtr_s = 0;
-    ManageScopedSingleton(InGameConsole, ScopeID::Graphics);
+    ManageScopedSingleton(InGameConsole, ScopeID::Graphics, false);
 
     /**
         @brief Constructor: Creates and initializes the InGameConsole.

Modified: code/branches/core5/src/orxonox/sound/SoundManager.cc
===================================================================
--- code/branches/core5/src/orxonox/sound/SoundManager.cc	2009-10-04 21:08:14 UTC (rev 5876)
+++ code/branches/core5/src/orxonox/sound/SoundManager.cc	2009-10-04 23:34:10 UTC (rev 5877)
@@ -39,7 +39,7 @@
 namespace orxonox
 {
     SoundManager* SoundManager::singletonPtr_s = NULL;
-    ManageScopedSingleton(SoundManager, ScopeID::Graphics);
+    ManageScopedSingleton(SoundManager, ScopeID::Graphics, true);
 
     /**
      * Default constructor




More information about the Orxonox-commit mailing list