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