module.cpp

Engine/source/core/module.cpp

More...

Public Defines

define

Detailed Description

Public Defines

DEBUG_SPEW_LEVEL() 2
  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "core/module.h"
 26#include "core/util/tVector.h"
 27#include "core/strings/stringFunctions.h"
 28
 29
 30//#define DEBUG_SPEW
 31#define DEBUG_SPEW_LEVEL 2
 32
 33
 34Module* Module::smFirst;
 35
 36
 37//-----------------------------------------------------------------------------
 38
 39bool Module::_constrainedToComeBefore( Module* module, Mode mode )
 40{
 41   if( module == this )
 42      return false;
 43      
 44   for( Dependency* dependency = _getDependencies( mode );
 45        dependency != NULL; dependency = dependency->mNext )
 46   {
 47      Module* depModule = dependency->mModule;
 48      if( !depModule )
 49      {
 50         depModule = EngineModuleManager::findModule( dependency->mModuleName );
 51         if( !depModule )
 52         {
 53            // Module does not exist.  Only emit a warning here so that modules
 54            // can be omitted from a link without requiring the module definitions
 55            // to be adapted.
 56            
 57            Platform::outputDebugString( "[EngineModuleManager] Module %s of '%s' depends on module '%s' which does not exist",
 58               mode == Module::ModeInitialize ? "init" : "shutdown",
 59               module->getName(), dependency->mModuleName );
 60            continue;
 61         }
 62         
 63         dependency->mModule = depModule;
 64      }
 65      
 66      if( dependency->mType == DependencyBefore )
 67      {
 68         if(    depModule == module
 69             || depModule->_constrainedToComeBefore( module, mode ) )
 70            return true;
 71      }
 72   }
 73   
 74   return false;
 75}
 76
 77//-----------------------------------------------------------------------------
 78
 79bool Module::_constrainedToComeAfter( Module* module, Mode mode )
 80{
 81   if( module == this )
 82      return false;
 83
 84   for( Dependency* dependency = _getDependencies( mode );
 85        dependency != NULL; dependency = dependency->mNext )
 86   {
 87      Module* depModule = dependency->mModule;
 88      if( !depModule )
 89      {
 90         depModule = EngineModuleManager::findModule( dependency->mModuleName );
 91         if( !depModule )
 92         {
 93            // Module does not exist.  Only emit a warning here so that modules
 94            // can be omitted from a link without requiring the module definitions
 95            // to be adapted.
 96            
 97            Platform::outputDebugString( "[EngineModuleManager] Module %s of '%s' depends on module '%s' which does not exist",
 98               mode == Module::ModeInitialize ? "init" : "shutdown",
 99               module->getName(), dependency->mModuleName );
100            continue;
101         }
102         
103         dependency->mModule = depModule;
104      }
105      
106      if( dependency->mType == DependencyAfter )
107      {
108         if(    depModule == module
109             || depModule->_constrainedToComeAfter( module, mode ) )
110            return true;
111      }
112   }
113   
114   return false;
115}
116
117//-----------------------------------------------------------------------------
118
119String EngineModuleManager::_moduleListToString( Vector< Module*>& moduleList )
120{
121   StringBuilder str;
122   
123   const U32 numModules = moduleList.size();
124   bool isFirst = true;
125   for( U32 i = 0; i < numModules; ++ i )
126   {
127      if( !isFirst )
128         str.append( " -> " );
129         
130      str.append( moduleList[ i ]->getName() );
131      
132      isFirst = false;
133   }
134   
135   return str.end();
136}
137
138//-----------------------------------------------------------------------------
139
140void EngineModuleManager::_printModuleList( Vector< Module*>& moduleList )
141{
142   Platform::outputDebugString( _moduleListToString( moduleList ) );
143}
144
145//-----------------------------------------------------------------------------
146
147void EngineModuleManager::_insertIntoModuleList( Module::Mode mode, Vector< Module*>& moduleList, Module* module )
148{
149   // If this module is being overridden, switch over to
150   // the module overriding it.
151      
152   Module* override;
153   do
154   {
155      override = _findOverrideFor( module );
156      if( override )
157         module = override;
158   }
159   while( override != NULL );
160
161   // If we are already on the list, return.
162   
163   if( _getIndexOfModuleInList( moduleList, module ) != -1 )
164      return;
165      
166   // If we don't have dependencies, just push the module
167   // to the back of the list.
168   
169   if( !module->_getDependencies( mode ) )
170   {
171      #if defined( DEBUG_SPEW ) && DEBUG_SPEW_LEVEL > 1
172      Platform::outputDebugString( "[EngineModuleManager] Appending '%s' to '%s'",
173         module->getName(), _moduleListToString( moduleList ).c_str() );
174      #endif
175
176      moduleList.push_back( module );         
177      return;
178   }
179   
180   // First make sure that all 'after' dependencies are in the list.
181      
182   #if defined( DEBUG_SPEW ) && DEBUG_SPEW_LEVEL > 1
183   Platform::outputDebugString( "[EngineModuleManager] Resolving %s dependencies of '%s'",
184      mode == Module::ModeInitialize ? "init" : "shutdown",
185      module->getName() );
186   #endif
187   
188   for( Module::Dependency* dependency = module->_getDependencies( mode );
189        dependency != NULL; dependency = dependency->mNext )
190   {
191      if( dependency->mType != Module::DependencyAfter )
192         continue;
193         
194      dependency->mModule = findModule( dependency->mModuleName );
195      if( !dependency->mModule )
196         continue; // Allow modules to not exist.
197         
198      if( _getIndexOfModuleInList( moduleList, dependency->mModule ) == -1 )
199         _insertIntoModuleList( mode, moduleList, dependency->mModule );
200   }
201   
202   AssertFatal( _getIndexOfModuleInList( moduleList, module ) == -1,
203      avar( "EngineModuleManager::_insertModuleIntoList - Cycle in 'after' %s dependency chain of '%s'",
204         mode == Module::ModeInitialize ? "init" : "shutdown",
205         module->getName() ) );
206      
207   // Now add the module itself.
208   
209   const U32 numModules = moduleList.size();
210   for( U32 i = 0; i < numModules; ++ i )
211   {
212      const bool thisBeforeCurrent  = module->_constrainedToComeBefore( moduleList[ i ], mode );
213      const bool currentAfterThis   = moduleList[ i ]->_constrainedToComeAfter( module, mode );
214      
215      AssertFatal( !( thisBeforeCurrent && currentAfterThis ),
216         avar( "EngineModuleManager::_insertModuleIntoList - Ambiguous %s placement of module '%s' relative to '%s'",
217            mode == Module::ModeInitialize ? "init" : "shutdown",
218            module->getName(), moduleList[ i ]->getName() ) );
219      
220      // If no contraints relate us to this module,
221      // push us one more position back in the line.
222      
223      if( !thisBeforeCurrent && !currentAfterThis )
224         continue;
225         
226      // If this module is contrained to come before the
227      // module at our current position but that module does
228      // not actually have dependencies of its own, make sure
229      // that module is at the back of the module list so that
230      // if we have more dependencies, it will not prevent us
231      // from correctly positioning us in relation to them.
232      
233      if( thisBeforeCurrent && !moduleList[ i ]->_getDependencies( mode ) && i != numModules - 1 )
234      {
235         #if defined( DEBUG_SPEW ) && DEBUG_SPEW_LEVEL > 1
236         Platform::outputDebugString( "[EngineModuleManager] Pushing '%s' to back end of chain for resolving '%s'",
237            moduleList[ i ]->getName(), module->getName() );
238         #endif
239         
240         Module* depModule = moduleList[ i ];
241         moduleList.erase( i );
242         -- i;
243         
244         moduleList.push_back( depModule );
245         continue;
246      }
247      
248      // Try the reverse constraint with all remaining modules in the list.
249      // If there is one for which we have one, then the placement of this
250      // module is ambiguous.
251      
252      for( U32 n = i + 1; n < numModules; ++ n )
253         AssertFatal( !(    moduleList[ n ]->_constrainedToComeBefore( module, mode )
254                         || module->_constrainedToComeAfter( moduleList[ n ], mode ) ),
255            avar( "EngineModuleManager::_insertModuleIntoList - Ambiguous %s constraint on module '%s' to come before '%s' yet after '%s'",
256               mode == Module::ModeInitialize ? "init" : "shutdown",
257               module->getName(),
258               moduleList[ i ]->getName(),
259               moduleList[ n ]->getName() ) );
260      
261      // Add the module at this position.
262   
263      #if defined( DEBUG_SPEW ) && DEBUG_SPEW_LEVEL > 1
264      Platform::outputDebugString( "[EngineModuleManager] Inserting '%s' at index %i into '%s'",
265         module->getName(), i, _moduleListToString( moduleList ).c_str() );
266      #endif
267
268      moduleList.insert( i, module );
269      return;
270   }
271   
272   // No constraint-based position.  Just append.
273
274   #if defined( DEBUG_SPEW ) && DEBUG_SPEW_LEVEL > 1
275   Platform::outputDebugString( "[EngineModuleManager] Appending '%s' to '%s'",
276      module->getName(), _moduleListToString( moduleList ).c_str() );
277   #endif
278
279   moduleList.push_back( module );
280}
281
282//-----------------------------------------------------------------------------
283
284Module* EngineModuleManager::_findOverrideFor( Module* module )
285{
286   const char* name = module->getName();
287   
288   for( Module* ptr = Module::smFirst; ptr != NULL; ptr = ptr->mNext )
289      for( Module::Override* override = ptr->mOverrides; override != NULL; override = override->mNext )
290         if( dStricmp( override->mModuleName, name ) == 0 )
291            return ptr;
292   
293   return NULL;
294}
295
296//-----------------------------------------------------------------------------
297
298S32 EngineModuleManager::_getIndexOfModuleInList( Vector< Module*>& moduleList, Module* module )
299{
300   const U32 numModules = moduleList.size();
301   for( U32 i = 0; i < numModules; ++ i )
302      if( moduleList[ i ] == module )
303         return i;
304         
305   return -1;
306}
307
308//-----------------------------------------------------------------------------
309
310S32 EngineModuleManager::_getIndexOfModuleInList( Vector< Module*>& moduleList, const char* moduleName )
311{
312   const U32 numModules = moduleList.size();
313   for( U32 i = 0; i < numModules; ++ i )
314      if( dStricmp( moduleList[ i ]->getName(), moduleName ) == 0 )
315         return i;
316         
317   return -1;
318}
319
320//-----------------------------------------------------------------------------
321
322void EngineModuleManager::_createModuleList( Module::Mode mode, Vector< Module*>& moduleList )
323{
324   for( Module* module = Module::smFirst; module != NULL; module = module->mNext )
325      _insertIntoModuleList( mode, moduleList, module );
326}
327
328//-----------------------------------------------------------------------------
329
330void EngineModuleManager::initializeSystem()
331{
332   Vector< Module*> modules;
333   
334   _createModuleList( Module::ModeInitialize, modules );
335   
336   const U32 numModules = modules.size();
337   for( U32 i = 0; i < numModules; ++ i )
338   {
339      Module* module = modules[ i ];      
340      if( !module->mIsInitialized )
341      {
342         #ifdef DEBUG_SPEW
343         Platform::outputDebugString( "[EngineModuleManager] Initializing %s",
344            module->getName() );
345         #endif
346         
347         module->initialize();
348         module->mIsInitialized = true;
349      }
350   }
351}
352
353//-----------------------------------------------------------------------------
354
355void EngineModuleManager::shutdownSystem()
356{
357   Vector< Module*> modules;
358   
359   _createModuleList( Module::ModeShutdown, modules );
360
361   const U32 numModules = modules.size();
362   for( U32 i = 0; i < numModules; ++ i )
363   {      
364      if( modules[ i ]->mIsInitialized )
365      {
366         #ifdef DEBUG_SPEW
367         Platform::outputDebugString( "[EngineModuleManager] Shutting down %s",
368            modules[ i ]->getName() );
369         #endif
370         
371         modules[ i ]->shutdown();
372         modules[ i ]->mIsInitialized = false;
373      }
374   }
375}
376
377//-----------------------------------------------------------------------------
378
379Module* EngineModuleManager::findModule( const char* name )
380{
381   for( Module* module = Module::smFirst; module != NULL; module = module->mNext )
382      if( dStricmp( module->getName(), name ) == 0 )
383         return module;
384   
385   return NULL;
386}
387