]> git.mxchange.org Git - simgear.git/blob - simgear/structure/subsystem_mgr.cxx
Keep Linux happy.
[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 string_list
285 SGSubsystemGroup::member_names() const
286 {
287         string_list result;
288         for (unsigned int i = 0; i < _members.size(); i++)
289                 result.push_back( _members[i]->name );
290         
291         return result;
292 }
293
294 bool
295 SGSubsystemGroup::is_suspended () const
296 {
297     return false;
298 }
299
300 void
301 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
302                                  double min_step_sec)
303 {
304     Member * member = get_member(name, true);
305     if (member->subsystem != 0)
306         delete member->subsystem;
307     member->name = name;
308     member->subsystem = subsystem;
309     member->min_step_sec = min_step_sec;
310 }
311
312 SGSubsystem *
313 SGSubsystemGroup::get_subsystem (const string &name)
314 {
315     Member * member = get_member(name);
316     if (member != 0)
317         return member->subsystem;
318     else
319         return 0;
320 }
321
322 void
323 SGSubsystemGroup::remove_subsystem (const string &name)
324 {
325     for (unsigned int i = 0; i < _members.size(); i++) {
326         if (name == _members[i]->name) {
327             _members.erase(_members.begin() + i);
328             return;
329         }
330     }
331 }
332
333 void
334 SGSubsystemGroup::set_fixed_update_time(double dt)
335 {
336   _fixedUpdateTime = dt;
337 }
338
339 bool
340 SGSubsystemGroup::has_subsystem (const string &name) const
341 {
342     return (((SGSubsystemGroup *)this)->get_member(name) != 0);
343 }
344
345 SGSubsystemGroup::Member *
346 SGSubsystemGroup::get_member (const string &name, bool create)
347 {
348     for (unsigned int i = 0; i < _members.size(); i++) {
349         if (_members[i]->name == name)
350             return _members[i];
351     }
352     if (create) {
353         Member * member = new Member;
354         _members.push_back(member);
355         return member;
356     } else {
357         return 0;
358     }
359 }
360
361
362 \f
363 ////////////////////////////////////////////////////////////////////////
364 // Implementation of SGSubsystemGroup::Member
365 ////////////////////////////////////////////////////////////////////////
366
367
368 SGSubsystemGroup::Member::Member ()
369     : name(""),
370       subsystem(0),
371       min_step_sec(0),
372       elapsed_sec(0),
373       exceptionCount(0),
374       initTime(0)
375 {
376 }
377
378 // This shouldn't be called due to subsystem pointer ownership issues.
379 SGSubsystemGroup::Member::Member (const Member &)
380 {
381 }
382
383 SGSubsystemGroup::Member::~Member ()
384 {
385     delete subsystem;
386 }
387
388 void
389 SGSubsystemGroup::Member::update (double delta_time_sec)
390 {
391     elapsed_sec += delta_time_sec;
392     if (elapsed_sec < min_step_sec) {
393         return;
394     }
395     
396     if (subsystem->is_suspended()) {
397         return;
398     }
399     
400     try {
401       subsystem->update(elapsed_sec);
402       elapsed_sec = 0;
403     } catch (sg_exception& e) {
404       SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
405         << "\nmessage:" << e.getMessage());
406       
407       if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
408         SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
409           ", suspending)");
410         subsystem->suspend();
411       }
412     }
413 }
414
415
416 ////////////////////////////////////////////////////////////////////////
417 // Implementation of SGSubsystemMgr.
418 ////////////////////////////////////////////////////////////////////////
419
420
421 SGSubsystemMgr::SGSubsystemMgr () :
422   _initPosition(0)
423 {
424   for (int i = 0; i < MAX_GROUPS; i++) {
425     _groups[i] = new SGSubsystemGroup;
426   }
427 }
428
429 SGSubsystemMgr::~SGSubsystemMgr ()
430 {
431   // ensure get_subsystem returns NULL from now onwards,
432   // before the SGSubsystemGroup destructors are run
433   _subsystem_map.clear();
434   
435   for (int i = 0; i < MAX_GROUPS; i++) {
436     delete _groups[i];
437   }
438 }
439
440 void
441 SGSubsystemMgr::init ()
442 {
443     for (int i = 0; i < MAX_GROUPS; i++)
444             _groups[i]->init();
445 }
446
447 SGSubsystem::InitStatus
448 SGSubsystemMgr::incrementalInit()
449 {
450   if (_initPosition >= MAX_GROUPS)
451     return INIT_DONE;
452   
453   InitStatus memberStatus = _groups[_initPosition]->incrementalInit();  
454   if (memberStatus == INIT_DONE)
455     ++_initPosition;
456   
457   return INIT_CONTINUE;
458 }
459
460 void
461 SGSubsystemMgr::postinit ()
462 {
463     for (int i = 0; i < MAX_GROUPS; i++)
464             _groups[i]->postinit();
465 }
466
467 void
468 SGSubsystemMgr::reinit ()
469 {
470     for (int i = 0; i < MAX_GROUPS; i++)
471             _groups[i]->reinit();
472 }
473
474 void
475 SGSubsystemMgr::shutdown ()
476 {
477     // reverse order to prevent order dependency problems
478     for (int i = MAX_GROUPS-1; i >= 0; i--)
479         _groups[i]->shutdown();
480   
481     _initPosition = 0;
482 }
483
484
485 void
486 SGSubsystemMgr::bind ()
487 {
488     for (int i = 0; i < MAX_GROUPS; i++)
489         _groups[i]->bind();
490 }
491
492 void
493 SGSubsystemMgr::unbind ()
494 {
495     // reverse order to prevent order dependency problems
496     for (int i = MAX_GROUPS-1; i >= 0; i--)
497         _groups[i]->unbind();
498 }
499
500 void
501 SGSubsystemMgr::update (double delta_time_sec)
502 {
503     for (int i = 0; i < MAX_GROUPS; i++) {
504         _groups[i]->update(delta_time_sec);
505     }
506 }
507
508 void
509 SGSubsystemMgr::suspend ()
510 {
511     for (int i = 0; i < MAX_GROUPS; i++)
512         _groups[i]->suspend();
513 }
514
515 void
516 SGSubsystemMgr::resume ()
517 {
518     for (int i = 0; i < MAX_GROUPS; i++)
519         _groups[i]->resume();
520 }
521
522 bool
523 SGSubsystemMgr::is_suspended () const
524 {
525     return false;
526 }
527
528 void
529 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
530                      GroupType group, double min_time_sec)
531 {
532     SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
533     get_group(group)->set_subsystem(name, subsystem, min_time_sec);
534
535     if (_subsystem_map.find(name) != _subsystem_map.end()) {
536         SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
537         throw sg_exception("duplicate subsystem");
538     }
539     _subsystem_map[name] = subsystem;
540 }
541
542 SGSubsystem* 
543 SGSubsystemMgr::remove(const char* name)
544 {
545   SubsystemDict::iterator s =_subsystem_map.find(name);
546   if (s == _subsystem_map.end()) {
547     return NULL;
548   }
549   
550   SGSubsystem* sub = s->second;
551   _subsystem_map.erase(s);
552   
553 // tedious part - we don't know which group the subsystem belongs too
554   for (int i = 0; i < MAX_GROUPS; i++) {
555     if (_groups[i]->get_subsystem(name) == sub) {
556       _groups[i]->remove_subsystem(name);
557       break;
558     }
559   } // of groups iteration
560   
561   return sub;
562 }
563
564
565 SGSubsystemGroup *
566 SGSubsystemMgr::get_group (GroupType group)
567 {
568     return _groups[group];
569 }
570
571 SGSubsystem *
572 SGSubsystemMgr::get_subsystem (const string &name) const
573 {
574     SubsystemDict::const_iterator s =_subsystem_map.find(name);
575
576     if (s == _subsystem_map.end())
577         return 0;
578     else
579         return s->second;
580 }
581
582 /** Trigger the timing callback to report data for all subsystems. */
583 void
584 SGSubsystemMgr::reportTiming()
585 {
586     for (int i = 0; i < MAX_GROUPS; i++) {
587         _groups[i]->reportTiming();
588     } // of groups iteration
589 }
590
591 // end of subsystem_mgr.cxx