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