1 // Written by David Megginson, started 2000-12
3 // Copyright (C) 2000 David Megginson, david@megginson.com
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 # include <simgear_config.h>
25 #include <simgear/debug/logstream.hxx>
26 #include <simgear/timing/timestamp.hxx>
28 #include "exception.hxx"
29 #include "subsystem_mgr.hxx"
31 #include <simgear/math/SGMath.hxx>
32 #include "SGSmplstat.hxx"
34 const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
38 ////////////////////////////////////////////////////////////////////////
39 // Implementation of SGSubsystem
40 ////////////////////////////////////////////////////////////////////////
42 SGSubsystemTimingCb SGSubsystem::reportTimingCb = NULL;
43 void* SGSubsystem::reportTimingUserData = NULL;
45 SGSubsystem::SGSubsystem ()
50 SGSubsystem::~SGSubsystem ()
59 SGSubsystem::InitStatus
60 SGSubsystem::incrementalInit ()
67 SGSubsystem::postinit ()
72 SGSubsystem::reinit ()
77 SGSubsystem::shutdown ()
87 SGSubsystem::unbind ()
92 SGSubsystem::suspend ()
98 SGSubsystem::suspend (bool suspended)
100 _suspended = suspended;
104 SGSubsystem::resume ()
110 SGSubsystem::is_suspended () const
115 void SGSubsystem::stamp(const string& name)
117 timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
121 ////////////////////////////////////////////////////////////////////////
122 // Implementation of SGSubsystemGroup.
123 ////////////////////////////////////////////////////////////////////////
125 class SGSubsystemGroup::Member
128 Member (const Member &member);
133 virtual void update (double delta_time_sec);
135 void reportTiming(void) { if (reportTimingCb) reportTimingCb(reportTimingUserData, name, &timeStat); }
136 void updateExecutionTime(double time) { timeStat += time;}
138 SampleStatistic timeStat;
140 SGSubsystem * subsystem;
143 bool collectTimeStats;
150 SGSubsystemGroup::SGSubsystemGroup () :
151 _fixedUpdateTime(-1.0),
152 _updateTimeRemainder(0.0),
157 SGSubsystemGroup::~SGSubsystemGroup ()
159 // reverse order to prevent order dependency problems
160 for (unsigned int i = _members.size(); i > 0; i--)
162 delete _members[i-1];
167 SGSubsystemGroup::init ()
169 for (unsigned int i = 0; i < _members.size(); i++)
170 _members[i]->subsystem->init();
173 SGSubsystem::InitStatus
174 SGSubsystemGroup::incrementalInit()
176 if (_initPosition >= _members.size())
181 InitStatus memberStatus = _members[_initPosition]->subsystem->incrementalInit();
182 _members[_initPosition]->initTime += st.elapsedMSec();
184 if (memberStatus == INIT_DONE)
187 return INIT_CONTINUE;
191 SGSubsystemGroup::postinit ()
193 for (unsigned int i = 0; i < _members.size(); i++)
194 _members[i]->subsystem->postinit();
198 SGSubsystemGroup::reinit ()
200 for (unsigned int i = 0; i < _members.size(); i++)
201 _members[i]->subsystem->reinit();
205 SGSubsystemGroup::shutdown ()
207 // reverse order to prevent order dependency problems
208 for (unsigned int i = _members.size(); i > 0; i--)
209 _members[i-1]->subsystem->shutdown();
214 SGSubsystemGroup::bind ()
216 for (unsigned int i = 0; i < _members.size(); i++)
217 _members[i]->subsystem->bind();
221 SGSubsystemGroup::unbind ()
223 // reverse order to prevent order dependency problems
224 for (unsigned int i = _members.size(); i > 0; i--)
225 _members[i-1]->subsystem->unbind();
229 SGSubsystemGroup::update (double delta_time_sec)
232 // if dt == 0.0, we are paused, so we need to run one iteration
233 // of our members; if we have a fixed update time, we compute a
234 // loop count, and locally adjust dt
235 if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
236 double localDelta = delta_time_sec + _updateTimeRemainder;
237 loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
238 _updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
239 delta_time_sec = _fixedUpdateTime;
242 bool recordTime = (reportTimingCb != NULL);
243 SGTimeStamp timeStamp;
244 while (loopCount-- > 0) {
245 for (unsigned int i = 0; i < _members.size(); i++)
248 timeStamp = SGTimeStamp::now();
250 _members[i]->update(delta_time_sec); // indirect call
252 if ((recordTime)&&(reportTimingCb))
254 timeStamp = SGTimeStamp::now() - timeStamp;
255 _members[i]->updateExecutionTime(timeStamp.toUSecs());
258 } // of multiple update loop
262 SGSubsystemGroup::reportTiming(void)
264 for (unsigned int i = _members.size(); i > 0; i--)
266 _members[i-1]->reportTiming();
271 SGSubsystemGroup::suspend ()
273 for (unsigned int i = 0; i < _members.size(); i++)
274 _members[i]->subsystem->suspend();
278 SGSubsystemGroup::resume ()
280 for (unsigned int i = 0; i < _members.size(); i++)
281 _members[i]->subsystem->resume();
285 SGSubsystemGroup::is_suspended () const
291 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
294 Member * member = get_member(name, true);
295 if (member->subsystem != 0)
296 delete member->subsystem;
298 member->subsystem = subsystem;
299 member->min_step_sec = min_step_sec;
303 SGSubsystemGroup::get_subsystem (const string &name)
305 Member * member = get_member(name);
307 return member->subsystem;
313 SGSubsystemGroup::remove_subsystem (const string &name)
315 for (unsigned int i = 0; i < _members.size(); i++) {
316 if (name == _members[i]->name) {
317 _members.erase(_members.begin() + i);
324 SGSubsystemGroup::set_fixed_update_time(double dt)
326 _fixedUpdateTime = dt;
330 SGSubsystemGroup::has_subsystem (const string &name) const
332 return (((SGSubsystemGroup *)this)->get_member(name) != 0);
335 SGSubsystemGroup::Member *
336 SGSubsystemGroup::get_member (const string &name, bool create)
338 for (unsigned int i = 0; i < _members.size(); i++) {
339 if (_members[i]->name == name)
343 Member * member = new Member;
344 _members.push_back(member);
353 ////////////////////////////////////////////////////////////////////////
354 // Implementation of SGSubsystemGroup::Member
355 ////////////////////////////////////////////////////////////////////////
358 SGSubsystemGroup::Member::Member ()
368 // This shouldn't be called due to subsystem pointer ownership issues.
369 SGSubsystemGroup::Member::Member (const Member &)
373 SGSubsystemGroup::Member::~Member ()
379 SGSubsystemGroup::Member::update (double delta_time_sec)
381 elapsed_sec += delta_time_sec;
382 if (elapsed_sec < min_step_sec) {
386 if (subsystem->is_suspended()) {
391 subsystem->update(elapsed_sec);
393 } catch (sg_exception& e) {
394 SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
395 << "\nmessage:" << e.getMessage());
397 if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
398 SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
400 subsystem->suspend();
406 ////////////////////////////////////////////////////////////////////////
407 // Implementation of SGSubsystemMgr.
408 ////////////////////////////////////////////////////////////////////////
411 SGSubsystemMgr::SGSubsystemMgr () :
414 for (int i = 0; i < MAX_GROUPS; i++) {
415 _groups[i] = new SGSubsystemGroup;
419 SGSubsystemMgr::~SGSubsystemMgr ()
421 // ensure get_subsystem returns NULL from now onwards,
422 // before the SGSubsystemGroup destructors are run
423 _subsystem_map.clear();
425 for (int i = 0; i < MAX_GROUPS; i++) {
431 SGSubsystemMgr::init ()
433 for (int i = 0; i < MAX_GROUPS; i++)
437 SGSubsystem::InitStatus
438 SGSubsystemMgr::incrementalInit()
440 if (_initPosition >= MAX_GROUPS)
443 InitStatus memberStatus = _groups[_initPosition]->incrementalInit();
444 if (memberStatus == INIT_DONE)
447 return INIT_CONTINUE;
451 SGSubsystemMgr::postinit ()
453 for (int i = 0; i < MAX_GROUPS; i++)
454 _groups[i]->postinit();
458 SGSubsystemMgr::reinit ()
460 for (int i = 0; i < MAX_GROUPS; i++)
461 _groups[i]->reinit();
465 SGSubsystemMgr::shutdown ()
467 // reverse order to prevent order dependency problems
468 for (int i = MAX_GROUPS-1; i >= 0; i--)
469 _groups[i]->shutdown();
476 SGSubsystemMgr::bind ()
478 for (int i = 0; i < MAX_GROUPS; i++)
483 SGSubsystemMgr::unbind ()
485 // reverse order to prevent order dependency problems
486 for (int i = MAX_GROUPS-1; i >= 0; i--)
487 _groups[i]->unbind();
491 SGSubsystemMgr::update (double delta_time_sec)
493 for (int i = 0; i < MAX_GROUPS; i++) {
494 _groups[i]->update(delta_time_sec);
499 SGSubsystemMgr::suspend ()
501 for (int i = 0; i < MAX_GROUPS; i++)
502 _groups[i]->suspend();
506 SGSubsystemMgr::resume ()
508 for (int i = 0; i < MAX_GROUPS; i++)
509 _groups[i]->resume();
513 SGSubsystemMgr::is_suspended () const
519 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
520 GroupType group, double min_time_sec)
522 SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
523 get_group(group)->set_subsystem(name, subsystem, min_time_sec);
525 if (_subsystem_map.find(name) != _subsystem_map.end()) {
526 SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
527 throw sg_exception("duplicate subsystem");
529 _subsystem_map[name] = subsystem;
533 SGSubsystemMgr::remove(const char* name)
535 SubsystemDict::iterator s =_subsystem_map.find(name);
536 if (s == _subsystem_map.end()) {
540 SGSubsystem* sub = s->second;
541 _subsystem_map.erase(s);
543 // tedious part - we don't know which group the subsystem belongs too
544 for (int i = 0; i < MAX_GROUPS; i++) {
545 if (_groups[i]->get_subsystem(name) == sub) {
546 _groups[i]->remove_subsystem(name);
549 } // of groups iteration
556 SGSubsystemMgr::get_group (GroupType group)
558 return _groups[group];
562 SGSubsystemMgr::get_subsystem (const string &name) const
564 SubsystemDict::const_iterator s =_subsystem_map.find(name);
566 if (s == _subsystem_map.end())
572 /** Trigger the timing callback to report data for all subsystems. */
574 SGSubsystemMgr::reportTiming()
576 for (int i = 0; i < MAX_GROUPS; i++) {
577 _groups[i]->reportTiming();
578 } // of groups iteration
581 // end of subsystem_mgr.cxx