]> git.mxchange.org Git - simgear.git/blobdiff - simgear/structure/subsystem_mgr.cxx
Fix rpmlint/Linux packager complaints
[simgear.git] / simgear / structure / subsystem_mgr.cxx
index 8b1d5ea456309e1b99134f88ae43c73016bbe420..df2c0ef38349bcc60f124a6b9869ae3da07e9574 100644 (file)
@@ -1,15 +1,44 @@
+// Written by David Megginson, started 2000-12
+//
+// Copyright (C) 2000  David Megginson, david@megginson.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
 
 #include <simgear/debug/logstream.hxx>
+#include <simgear/timing/timestamp.hxx>
 
 #include "exception.hxx"
 #include "subsystem_mgr.hxx"
 
+#include <simgear/math/SGMath.hxx>
+#include "SGSmplstat.hxx"
+
+const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
 
-\f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of SGSubsystem
 ////////////////////////////////////////////////////////////////////////
 
+SGSubsystemTimingCb SGSubsystem::reportTimingCb = NULL;
+void* SGSubsystem::reportTimingUserData = NULL;
 
 SGSubsystem::SGSubsystem ()
   : _suspended(false)
@@ -25,11 +54,21 @@ SGSubsystem::init ()
 {
 }
 
+void
+SGSubsystem::postinit ()
+{
+}
+
 void
 SGSubsystem::reinit ()
 {
 }
 
+void
+SGSubsystem::shutdown ()
+{
+}
+
 void
 SGSubsystem::bind ()
 {
@@ -64,20 +103,53 @@ SGSubsystem::is_suspended () const
   return _suspended;
 }
 
+void SGSubsystem::stamp(const string& name)
+{
+    timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
+}
 
 \f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of SGSubsystemGroup.
 ////////////////////////////////////////////////////////////////////////
 
-SGSubsystemGroup::SGSubsystemGroup ()
+class SGSubsystemGroup::Member
+{    
+private:
+    Member (const Member &member);
+public:
+    Member ();
+    virtual ~Member ();
+    
+    virtual void update (double delta_time_sec);
+
+    void reportTiming(void) { if (reportTimingCb) reportTimingCb(reportTimingUserData, name, &timeStat); }
+    void updateExecutionTime(double time) { timeStat += time;}
+
+    SampleStatistic timeStat;
+    std::string name;
+    SGSubsystem * subsystem;
+    double min_step_sec;
+    double elapsed_sec;
+    bool collectTimeStats;
+    int exceptionCount;
+};
+
+
+
+SGSubsystemGroup::SGSubsystemGroup () :
+  _fixedUpdateTime(-1.0),
+  _updateTimeRemainder(0.0)
 {
 }
 
 SGSubsystemGroup::~SGSubsystemGroup ()
 {
-    for (unsigned int i = 0; i < _members.size(); i++)
-        delete _members[i];
+    // reverse order to prevent order dependency problems
+    for (unsigned int i = _members.size(); i > 0; i--)
+    {
+        delete _members[i-1];
+    }
 }
 
 void
@@ -87,6 +159,13 @@ SGSubsystemGroup::init ()
         _members[i]->subsystem->init();
 }
 
+void
+SGSubsystemGroup::postinit ()
+{
+    for (unsigned int i = 0; i < _members.size(); i++)
+        _members[i]->subsystem->postinit();
+}
+
 void
 SGSubsystemGroup::reinit ()
 {
@@ -94,6 +173,14 @@ SGSubsystemGroup::reinit ()
         _members[i]->subsystem->reinit();
 }
 
+void
+SGSubsystemGroup::shutdown ()
+{
+    // reverse order to prevent order dependency problems
+    for (unsigned int i = _members.size(); i > 0; i--)
+        _members[i-1]->subsystem->shutdown();
+}
+
 void
 SGSubsystemGroup::bind ()
 {
@@ -104,15 +191,51 @@ SGSubsystemGroup::bind ()
 void
 SGSubsystemGroup::unbind ()
 {
-    for (unsigned int i = 0; i < _members.size(); i++)
-        _members[i]->subsystem->unbind();
+    // reverse order to prevent order dependency problems
+    for (unsigned int i = _members.size(); i > 0; i--)
+       _members[i-1]->subsystem->unbind();
 }
 
 void
 SGSubsystemGroup::update (double delta_time_sec)
 {
-    for (unsigned int i = 0; i < _members.size(); i++)
-        _members[i]->update(delta_time_sec); // indirect call
+    int loopCount = 1;
+    // if dt == 0.0, we are paused, so we need to run one iteration
+    // of our members; if we have a fixed update time, we compute a
+    // loop count, and locally adjust dt
+    if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
+      double localDelta = delta_time_sec + _updateTimeRemainder;
+      loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
+      _updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
+      delta_time_sec = _fixedUpdateTime;
+    }
+
+    bool recordTime = (reportTimingCb != NULL);
+    SGTimeStamp timeStamp;
+    while (loopCount-- > 0) {
+      for (unsigned int i = 0; i < _members.size(); i++)
+      {
+          if (recordTime)
+              timeStamp = SGTimeStamp::now();
+
+          _members[i]->update(delta_time_sec); // indirect call
+
+          if ((recordTime)&&(reportTimingCb))
+          {
+              timeStamp = SGTimeStamp::now() - timeStamp;
+              _members[i]->updateExecutionTime(timeStamp.toUSecs());
+          }
+      }
+    } // of multiple update loop
+}
+
+void
+SGSubsystemGroup::reportTiming(void)
+{
+    for (unsigned int i = _members.size(); i > 0; i--)
+    {
+        _members[i-1]->reportTiming();
+    }
 }
 
 void
@@ -168,6 +291,12 @@ SGSubsystemGroup::remove_subsystem (const string &name)
     }
 }
 
+void
+SGSubsystemGroup::set_fixed_update_time(double dt)
+{
+  _fixedUpdateTime = dt;
+}
+
 bool
 SGSubsystemGroup::has_subsystem (const string &name) const
 {
@@ -201,35 +330,49 @@ SGSubsystemGroup::Member::Member ()
     : name(""),
       subsystem(0),
       min_step_sec(0),
-      elapsed_sec(0)
+      elapsed_sec(0),
+      exceptionCount(0)
 {
 }
 
+// This shouldn't be called due to subsystem pointer ownership issues.
 SGSubsystemGroup::Member::Member (const Member &)
 {
-    Member();
 }
 
 SGSubsystemGroup::Member::~Member ()
 {
-                                // FIXME: causes a crash
-//     delete subsystem;
+    delete subsystem;
 }
 
 void
 SGSubsystemGroup::Member::update (double delta_time_sec)
 {
     elapsed_sec += delta_time_sec;
-    if (elapsed_sec >= min_step_sec) {
-        if (!subsystem->is_suspended()) {
-            subsystem->update(elapsed_sec);
-            elapsed_sec = 0;
-        }
+    if (elapsed_sec < min_step_sec) {
+        return;
+    }
+    
+    if (subsystem->is_suspended()) {
+        return;
+    }
+    
+    try {
+      subsystem->update(elapsed_sec);
+      elapsed_sec = 0;
+    } catch (sg_exception& e) {
+      SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
+        << "\nmessage:" << e.getMessage());
+      
+      if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
+        SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
+          ", suspending)");
+        subsystem->suspend();
+      }
     }
 }
 
 
-\f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of SGSubsystemMgr.
 ////////////////////////////////////////////////////////////////////////
@@ -237,45 +380,72 @@ SGSubsystemGroup::Member::update (double delta_time_sec)
 
 SGSubsystemMgr::SGSubsystemMgr ()
 {
+  for (int i = 0; i < MAX_GROUPS; i++) {
+    _groups[i] = new SGSubsystemGroup;
+  }
 }
 
 SGSubsystemMgr::~SGSubsystemMgr ()
 {
+  // ensure get_subsystem returns NULL from now onwards,
+  // before the SGSubsystemGroup destructors are run
+  _subsystem_map.clear();
+  
+  for (int i = 0; i < MAX_GROUPS; i++) {
+    delete _groups[i];
+  }
 }
 
 void
 SGSubsystemMgr::init ()
 {
     for (int i = 0; i < MAX_GROUPS; i++)
-            _groups[i].init();
+            _groups[i]->init();
+}
+
+void
+SGSubsystemMgr::postinit ()
+{
+    for (int i = 0; i < MAX_GROUPS; i++)
+            _groups[i]->postinit();
 }
 
 void
 SGSubsystemMgr::reinit ()
 {
     for (int i = 0; i < MAX_GROUPS; i++)
-            _groups[i].reinit();
+            _groups[i]->reinit();
+}
+
+void
+SGSubsystemMgr::shutdown ()
+{
+    // reverse order to prevent order dependency problems
+    for (int i = MAX_GROUPS-1; i >= 0; i--)
+        _groups[i]->shutdown();
 }
 
+
 void
 SGSubsystemMgr::bind ()
 {
     for (int i = 0; i < MAX_GROUPS; i++)
-        _groups[i].bind();
+        _groups[i]->bind();
 }
 
 void
 SGSubsystemMgr::unbind ()
 {
-    for (int i = 0; i < MAX_GROUPS; i++)
-        _groups[i].unbind();
+    // reverse order to prevent order dependency problems
+    for (int i = MAX_GROUPS-1; i >= 0; i--)
+        _groups[i]->unbind();
 }
 
 void
 SGSubsystemMgr::update (double delta_time_sec)
 {
     for (int i = 0; i < MAX_GROUPS; i++) {
-        _groups[i].update(delta_time_sec);
+        _groups[i]->update(delta_time_sec);
     }
 }
 
@@ -283,14 +453,14 @@ void
 SGSubsystemMgr::suspend ()
 {
     for (int i = 0; i < MAX_GROUPS; i++)
-        _groups[i].suspend();
+        _groups[i]->suspend();
 }
 
 void
 SGSubsystemMgr::resume ()
 {
     for (int i = 0; i < MAX_GROUPS; i++)
-        _groups[i].resume();
+        _groups[i]->resume();
 }
 
 bool
@@ -313,16 +483,39 @@ SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
     _subsystem_map[name] = subsystem;
 }
 
+SGSubsystem* 
+SGSubsystemMgr::remove(const char* name)
+{
+  SubsystemDict::iterator s =_subsystem_map.find(name);
+  if (s == _subsystem_map.end()) {
+    return NULL;
+  }
+  
+  SGSubsystem* sub = s->second;
+  _subsystem_map.erase(s);
+  
+// tedious part - we don't know which group the subsystem belongs too
+  for (int i = 0; i < MAX_GROUPS; i++) {
+    if (_groups[i]->get_subsystem(name) == sub) {
+      _groups[i]->remove_subsystem(name);
+      break;
+    }
+  } // of groups iteration
+  
+  return sub;
+}
+
+
 SGSubsystemGroup *
 SGSubsystemMgr::get_group (GroupType group)
 {
-    return &(_groups[group]);
+    return _groups[group];
 }
 
 SGSubsystem *
-SGSubsystemMgr::get_subsystem (const string &name)
+SGSubsystemMgr::get_subsystem (const string &name) const
 {
-    map<string,SGSubsystem *>::iterator s =_subsystem_map.find(name);
+    SubsystemDict::const_iterator s =_subsystem_map.find(name);
 
     if (s == _subsystem_map.end())
         return 0;
@@ -330,4 +523,13 @@ SGSubsystemMgr::get_subsystem (const string &name)
         return s->second;
 }
 
-// end of fgfs.cxx
+/** Trigger the timing callback to report data for all subsystems. */
+void
+SGSubsystemMgr::reportTiming()
+{
+    for (int i = 0; i < MAX_GROUPS; i++) {
+        _groups[i]->reportTiming();
+    } // of groups iteration
+}
+
+// end of subsystem_mgr.cxx