]> git.mxchange.org Git - simgear.git/blob - simgear/structure/subsystem_mgr.cxx
Avoid signed/unsigned compiler warning.
[simgear.git] / simgear / structure / subsystem_mgr.cxx
1 // Written by David Megginson, started 2000-12
2 //
3 // Copyright (C) 2000  David Megginson, david@megginson.com
4 //
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.
9 //
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.
14 //
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.
18 //
19 // $Id$
20
21 #ifdef HAVE_CONFIG_H
22 #  include <simgear_config.h>
23 #endif
24
25 #include <simgear/debug/logstream.hxx>
26 #include <simgear/timing/timestamp.hxx>
27
28 #include "exception.hxx"
29 #include "subsystem_mgr.hxx"
30
31 #include <simgear/math/SGMath.hxx>
32 #include "SGSmplstat.hxx"
33
34 const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
35
36 using std::string;
37
38 ////////////////////////////////////////////////////////////////////////
39 // Implementation of SGSubsystem
40 ////////////////////////////////////////////////////////////////////////
41
42 SGSubsystemTimingCb SGSubsystem::reportTimingCb = NULL;
43 void* SGSubsystem::reportTimingUserData = NULL;
44
45 SGSubsystem::SGSubsystem ()
46   : _suspended(false)
47 {
48 }
49
50 SGSubsystem::~SGSubsystem ()
51 {
52 }
53
54 void
55 SGSubsystem::init ()
56 {
57 }
58
59 SGSubsystem::InitStatus
60 SGSubsystem::incrementalInit ()
61 {
62   init();
63   return INIT_DONE;
64 }
65
66 void
67 SGSubsystem::postinit ()
68 {
69 }
70
71 void
72 SGSubsystem::reinit ()
73 {
74 }
75
76 void
77 SGSubsystem::shutdown ()
78 {
79 }
80
81 void
82 SGSubsystem::bind ()
83 {
84 }
85
86 void
87 SGSubsystem::unbind ()
88 {
89 }
90
91 void
92 SGSubsystem::suspend ()
93 {
94   _suspended = true;
95 }
96
97 void
98 SGSubsystem::suspend (bool suspended)
99 {
100   _suspended = suspended;
101 }
102
103 void
104 SGSubsystem::resume ()
105 {
106   _suspended = false;
107 }
108
109 bool
110 SGSubsystem::is_suspended () const
111 {
112   return _suspended;
113 }
114
115 void SGSubsystem::stamp(const string& name)
116 {
117     timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
118 }
119
120 \f
121 ////////////////////////////////////////////////////////////////////////
122 // Implementation of SGSubsystemGroup.
123 ////////////////////////////////////////////////////////////////////////
124
125 class SGSubsystemGroup::Member
126 {    
127 private:
128     Member (const Member &member);
129 public:
130     Member ();
131     virtual ~Member ();
132     
133     virtual void update (double delta_time_sec);
134
135     void reportTiming(void) { if (reportTimingCb) reportTimingCb(reportTimingUserData, name, &timeStat); }
136     void updateExecutionTime(double time) { timeStat += time;}
137
138     SampleStatistic timeStat;
139     std::string name;
140     SGSubsystem * subsystem;
141     double min_step_sec;
142     double elapsed_sec;
143     bool collectTimeStats;
144     int exceptionCount;
145     int initTime;
146 };
147
148
149
150 SGSubsystemGroup::SGSubsystemGroup () :
151   _fixedUpdateTime(-1.0),
152   _updateTimeRemainder(0.0),
153   _initPosition(0)
154 {
155 }
156
157 SGSubsystemGroup::~SGSubsystemGroup ()
158 {
159     // reverse order to prevent order dependency problems
160     for (unsigned int i = _members.size(); i > 0; i--)
161     {
162         delete _members[i-1];
163     }
164 }
165
166 void
167 SGSubsystemGroup::init ()
168 {
169     for (unsigned int i = 0; i < _members.size(); i++)
170         _members[i]->subsystem->init();
171 }
172
173 SGSubsystem::InitStatus
174 SGSubsystemGroup::incrementalInit()
175 {
176   if (_initPosition >= _members.size())
177     return INIT_DONE;
178   
179   SGTimeStamp st;
180   st.stamp();
181   InitStatus memberStatus = _members[_initPosition]->subsystem->incrementalInit();
182   _members[_initPosition]->initTime += st.elapsedMSec();
183   
184   if (memberStatus == INIT_DONE)
185     ++_initPosition;
186   
187   return INIT_CONTINUE;
188 }
189
190 void
191 SGSubsystemGroup::postinit ()
192 {
193     for (unsigned int i = 0; i < _members.size(); i++)
194         _members[i]->subsystem->postinit();
195 }
196
197 void
198 SGSubsystemGroup::reinit ()
199 {
200     for (unsigned int i = 0; i < _members.size(); i++)
201         _members[i]->subsystem->reinit();
202 }
203
204 void
205 SGSubsystemGroup::shutdown ()
206 {
207     // reverse order to prevent order dependency problems
208     for (unsigned int i = _members.size(); i > 0; i--)
209         _members[i-1]->subsystem->shutdown();
210   _initPosition = 0;
211 }
212
213 void
214 SGSubsystemGroup::bind ()
215 {
216     for (unsigned int i = 0; i < _members.size(); i++)
217         _members[i]->subsystem->bind();
218 }
219
220 void
221 SGSubsystemGroup::unbind ()
222 {
223     // reverse order to prevent order dependency problems
224     for (unsigned int i = _members.size(); i > 0; i--)
225        _members[i-1]->subsystem->unbind();
226 }
227
228 void
229 SGSubsystemGroup::update (double delta_time_sec)
230 {
231     int loopCount = 1;
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;
240     }
241
242     bool recordTime = (reportTimingCb != NULL);
243     SGTimeStamp timeStamp;
244     while (loopCount-- > 0) {
245       for (unsigned int i = 0; i < _members.size(); i++)
246       {
247           if (recordTime)
248               timeStamp = SGTimeStamp::now();
249
250           _members[i]->update(delta_time_sec); // indirect call
251
252           if ((recordTime)&&(reportTimingCb))
253           {
254               timeStamp = SGTimeStamp::now() - timeStamp;
255               _members[i]->updateExecutionTime(timeStamp.toUSecs());
256           }
257       }
258     } // of multiple update loop
259 }
260
261 void
262 SGSubsystemGroup::reportTiming(void)
263 {
264     for (unsigned int i = _members.size(); i > 0; i--)
265     {
266         _members[i-1]->reportTiming();
267     }
268 }
269
270 void
271 SGSubsystemGroup::suspend ()
272 {
273     for (unsigned int i = 0; i < _members.size(); i++)
274         _members[i]->subsystem->suspend();
275 }
276
277 void
278 SGSubsystemGroup::resume ()
279 {
280     for (unsigned int i = 0; i < _members.size(); i++)
281         _members[i]->subsystem->resume();
282 }
283
284 bool
285 SGSubsystemGroup::is_suspended () const
286 {
287     return false;
288 }
289
290 void
291 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
292                                  double min_step_sec)
293 {
294     Member * member = get_member(name, true);
295     if (member->subsystem != 0)
296         delete member->subsystem;
297     member->name = name;
298     member->subsystem = subsystem;
299     member->min_step_sec = min_step_sec;
300 }
301
302 SGSubsystem *
303 SGSubsystemGroup::get_subsystem (const string &name)
304 {
305     Member * member = get_member(name);
306     if (member != 0)
307         return member->subsystem;
308     else
309         return 0;
310 }
311
312 void
313 SGSubsystemGroup::remove_subsystem (const string &name)
314 {
315     for (unsigned int i = 0; i < _members.size(); i++) {
316         if (name == _members[i]->name) {
317             _members.erase(_members.begin() + i);
318             return;
319         }
320     }
321 }
322
323 void
324 SGSubsystemGroup::set_fixed_update_time(double dt)
325 {
326   _fixedUpdateTime = dt;
327 }
328
329 bool
330 SGSubsystemGroup::has_subsystem (const string &name) const
331 {
332     return (((SGSubsystemGroup *)this)->get_member(name) != 0);
333 }
334
335 SGSubsystemGroup::Member *
336 SGSubsystemGroup::get_member (const string &name, bool create)
337 {
338     for (unsigned int i = 0; i < _members.size(); i++) {
339         if (_members[i]->name == name)
340             return _members[i];
341     }
342     if (create) {
343         Member * member = new Member;
344         _members.push_back(member);
345         return member;
346     } else {
347         return 0;
348     }
349 }
350
351
352 \f
353 ////////////////////////////////////////////////////////////////////////
354 // Implementation of SGSubsystemGroup::Member
355 ////////////////////////////////////////////////////////////////////////
356
357
358 SGSubsystemGroup::Member::Member ()
359     : name(""),
360       subsystem(0),
361       min_step_sec(0),
362       elapsed_sec(0),
363       exceptionCount(0),
364       initTime(0)
365 {
366 }
367
368 // This shouldn't be called due to subsystem pointer ownership issues.
369 SGSubsystemGroup::Member::Member (const Member &)
370 {
371 }
372
373 SGSubsystemGroup::Member::~Member ()
374 {
375     delete subsystem;
376 }
377
378 void
379 SGSubsystemGroup::Member::update (double delta_time_sec)
380 {
381     elapsed_sec += delta_time_sec;
382     if (elapsed_sec < min_step_sec) {
383         return;
384     }
385     
386     if (subsystem->is_suspended()) {
387         return;
388     }
389     
390     try {
391       subsystem->update(elapsed_sec);
392       elapsed_sec = 0;
393     } catch (sg_exception& e) {
394       SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
395         << "\nmessage:" << e.getMessage());
396       
397       if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
398         SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
399           ", suspending)");
400         subsystem->suspend();
401       }
402     }
403 }
404
405
406 ////////////////////////////////////////////////////////////////////////
407 // Implementation of SGSubsystemMgr.
408 ////////////////////////////////////////////////////////////////////////
409
410
411 SGSubsystemMgr::SGSubsystemMgr () :
412   _initPosition(0)
413 {
414   for (int i = 0; i < MAX_GROUPS; i++) {
415     _groups[i] = new SGSubsystemGroup;
416   }
417 }
418
419 SGSubsystemMgr::~SGSubsystemMgr ()
420 {
421   // ensure get_subsystem returns NULL from now onwards,
422   // before the SGSubsystemGroup destructors are run
423   _subsystem_map.clear();
424   
425   for (int i = 0; i < MAX_GROUPS; i++) {
426     delete _groups[i];
427   }
428 }
429
430 void
431 SGSubsystemMgr::init ()
432 {
433     for (int i = 0; i < MAX_GROUPS; i++)
434             _groups[i]->init();
435 }
436
437 SGSubsystem::InitStatus
438 SGSubsystemMgr::incrementalInit()
439 {
440   if (_initPosition >= MAX_GROUPS)
441     return INIT_DONE;
442   
443   InitStatus memberStatus = _groups[_initPosition]->incrementalInit();  
444   if (memberStatus == INIT_DONE)
445     ++_initPosition;
446   
447   return INIT_CONTINUE;
448 }
449
450 void
451 SGSubsystemMgr::postinit ()
452 {
453     for (int i = 0; i < MAX_GROUPS; i++)
454             _groups[i]->postinit();
455 }
456
457 void
458 SGSubsystemMgr::reinit ()
459 {
460     for (int i = 0; i < MAX_GROUPS; i++)
461             _groups[i]->reinit();
462 }
463
464 void
465 SGSubsystemMgr::shutdown ()
466 {
467     // reverse order to prevent order dependency problems
468     for (int i = MAX_GROUPS-1; i >= 0; i--)
469         _groups[i]->shutdown();
470   
471     _initPosition = 0;
472 }
473
474
475 void
476 SGSubsystemMgr::bind ()
477 {
478     for (int i = 0; i < MAX_GROUPS; i++)
479         _groups[i]->bind();
480 }
481
482 void
483 SGSubsystemMgr::unbind ()
484 {
485     // reverse order to prevent order dependency problems
486     for (int i = MAX_GROUPS-1; i >= 0; i--)
487         _groups[i]->unbind();
488 }
489
490 void
491 SGSubsystemMgr::update (double delta_time_sec)
492 {
493     for (int i = 0; i < MAX_GROUPS; i++) {
494         _groups[i]->update(delta_time_sec);
495     }
496 }
497
498 void
499 SGSubsystemMgr::suspend ()
500 {
501     for (int i = 0; i < MAX_GROUPS; i++)
502         _groups[i]->suspend();
503 }
504
505 void
506 SGSubsystemMgr::resume ()
507 {
508     for (int i = 0; i < MAX_GROUPS; i++)
509         _groups[i]->resume();
510 }
511
512 bool
513 SGSubsystemMgr::is_suspended () const
514 {
515     return false;
516 }
517
518 void
519 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
520                      GroupType group, double min_time_sec)
521 {
522     SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
523     get_group(group)->set_subsystem(name, subsystem, min_time_sec);
524
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");
528     }
529     _subsystem_map[name] = subsystem;
530 }
531
532 SGSubsystem* 
533 SGSubsystemMgr::remove(const char* name)
534 {
535   SubsystemDict::iterator s =_subsystem_map.find(name);
536   if (s == _subsystem_map.end()) {
537     return NULL;
538   }
539   
540   SGSubsystem* sub = s->second;
541   _subsystem_map.erase(s);
542   
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);
547       break;
548     }
549   } // of groups iteration
550   
551   return sub;
552 }
553
554
555 SGSubsystemGroup *
556 SGSubsystemMgr::get_group (GroupType group)
557 {
558     return _groups[group];
559 }
560
561 SGSubsystem *
562 SGSubsystemMgr::get_subsystem (const string &name) const
563 {
564     SubsystemDict::const_iterator s =_subsystem_map.find(name);
565
566     if (s == _subsystem_map.end())
567         return 0;
568     else
569         return s->second;
570 }
571
572 /** Trigger the timing callback to report data for all subsystems. */
573 void
574 SGSubsystemMgr::reportTiming()
575 {
576     for (int i = 0; i < MAX_GROUPS; i++) {
577         _groups[i]->reportTiming();
578     } // of groups iteration
579 }
580
581 // end of subsystem_mgr.cxx