00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 #include "OSDLScheduler.h"
00028 
00029 #include "OSDLBasic.h"                  
00030 #include "OSDLVideo.h"                  
00031 #include "OSDLRenderer.h"               
00032 #include "OSDLActiveObject.h"           
00033 #include "OSDLPeriodicalActiveObject.h" 
00034 #include "OSDLProgrammedActiveObject.h" 
00035 
00036 
00037 
00038 #include <iostream>                   
00039 using std::ostringstream ;
00040 
00041 #include <iomanip>                    
00042 
00043 
00044 
00045 using namespace Ceylan::Log ;         
00046 
00047 
00048 using namespace Ceylan::System ;      
00049 
00050 
00051 using namespace OSDL ;
00052 using namespace OSDL::Events ;
00053 using namespace OSDL::Rendering ;
00054 using namespace OSDL::Engine ;
00055 
00056 using std::string ;
00057 using std::list ;
00058 using std::map ;
00059 
00060 using Ceylan::Maths::Hertz ;
00061 
00062 
00063 
00064 Scheduler * Scheduler::_internalScheduler = 0 ;
00065 
00066 
00067 const Delay Scheduler::ShutdownBucketLevel = 1000000 ;
00068 
00069 
00070 
00071 #ifdef OSDL_USES_CONFIG_H
00072 #include <OSDLConfig.h>               
00073 #endif // OSDL_USES_CONFIG_H
00074 
00075 
00076 
00077 #if OSDL_DEBUG_SCHEDULER
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088  
00089 #define OSDL_SCHEDULE_LOG(message) //send( message )
00090 
00091 
00092 
00093 
00094 
00095 
00096 
00097 
00098 
00099 #else // OSDL_DEBUG_SCHEDULER
00100 
00101 #define OSDL_SCHEDULE_LOG(message)
00102 
00103 #endif // OSDL_DEBUG_SCHEDULER
00104 
00105 
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 
00114 
00115 
00116 
00117 
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 
00128 
00129 
00130 
00131 
00132 
00133 
00134 
00135 
00136 
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 
00145 
00146 
00147 
00148 
00149 
00150 
00151 
00152 bool Scheduler::hasRenderer() const 
00153 {
00154 
00155     return ( _renderer != 0 ) ;
00156     
00157 }
00158 
00159 
00160 
00161 Renderer & Scheduler::getRenderer() const
00162 {
00163 
00164     if ( _renderer != 0 )
00165         return * _renderer ;
00166     else
00167         throw SchedulingException( 
00168             "Scheduler::getRenderer: no renderer available." ) ;
00169         
00170 }
00171 
00172 
00173 
00174 void Scheduler::setRenderer( Rendering::Renderer & newRenderer ) 
00175 {
00176 
00177     if ( _renderer != 0 )
00178         delete _renderer ;
00179     
00180     
00181     _renderer = & newRenderer ;
00182         
00183 }
00184 
00185 
00186 
00187 void Scheduler::setScreenshotMode( bool on, const string & frameFilenamePrefix, 
00188     Hertz frameFrequency ) 
00189 {
00190 
00191     LogPlug::trace( "Scheduler::setScreenshotMode: mode set to " 
00192         + Ceylan::toString( on ) + "." ) ;
00193         
00194     _screenshotMode = on ;
00195     _frameFilenamePrefix = frameFilenamePrefix ;
00196     
00197 }
00198 
00199 
00200                     
00201 void Scheduler::setTimeSliceDuration( Microsecond engineTickDuration ) 
00202 {
00203 
00204     _engineTickDuration = engineTickDuration ;
00205     
00206     
00207     setSimulationFrequency(   _desiredSimulationFrequency ) ;
00208     setRenderingFrequency(    _desiredRenderingFrequency ) ;
00209     setScreenshotFrequency(   _desiredScreenshotFrequency ) ;
00210     setInputPollingFrequency( _desiredInputFrequency ) ;
00211     
00212     _secondToEngineTick =  1000000 / _engineTickDuration ;
00213     
00214     OSDL_SCHEDULE_LOG( 
00215         "Multiplicative factor to convert seconds into engine ticks: "
00216         + Ceylan::toString( _secondToEngineTick ) ) ;
00217         
00218 }
00219 
00220 
00221 
00222 Microsecond Scheduler::getTimeSliceDuration() const 
00223 {
00224 
00225     return _engineTickDuration ;
00226     
00227 }
00228 
00229 
00230 
00231 void Scheduler::setSimulationFrequency( Hertz frequency ) 
00232 {
00233 
00234     
00235 
00236 
00237 
00238 
00239 
00240 
00241 
00242      
00243      if ( frequency * _engineTickDuration > 1E6 )
00244         throw SchedulingException( "Scheduler::setSimulationFrequency: "
00245             " requested simulation frequency (" 
00246             + Ceylan::toString( frequency ) 
00247             + " Hz) is too high for engine tick,"
00248             " which lasts for " 
00249             + Ceylan::toString( _engineTickDuration ) 
00250             + " microseconds." ) ;
00251     
00252     _desiredSimulationFrequency = frequency ;
00253     _simulationPeriod = static_cast<Period>( 
00254         1E6 / ( frequency * _engineTickDuration ) ) ;
00255 
00256 #if OSDL_DEBUG
00257 
00258     send( "Scheduler::setSimulationFrequency: for a requested "
00259         "simulation frequency of " + Ceylan::toString( frequency ) 
00260         + " Hz, the simulation period corresponds to " 
00261         + Ceylan::toString( _simulationPeriod ) + " engine ticks." ) ;
00262         
00263 #endif // OSDL_DEBUG
00264     
00265 }
00266 
00267 
00268 
00269 Period Scheduler::getSimulationTickCount() const 
00270 {
00271 
00272     return _simulationPeriod ;
00273     
00274 }
00275 
00276 
00277 
00278 void Scheduler::setRenderingFrequency( Hertz frequency )    
00279 {
00280 
00281     
00282 
00283 
00284 
00285 
00286 
00287 
00288 
00289 
00290      
00291      if ( frequency * _engineTickDuration > 1E6 )
00292         throw SchedulingException( "Scheduler::setRenderingFrequency: "
00293             "requested rendering frequency (" 
00294             + Ceylan::toString( frequency ) 
00295             + " Hz) is too high for engine tick,"
00296             " which lasts for " 
00297             + Ceylan::toString( _engineTickDuration ) 
00298             + " microseconds." ) ;
00299             
00300     _desiredRenderingFrequency = frequency ;        
00301     _renderingPeriod = static_cast<Period>( 
00302         1E6 / ( frequency * _engineTickDuration ) ) ;
00303 
00304 #if OSDL_DEBUG
00305 
00306     send( "Scheduler::setRenderingFrequency: for a requested "
00307         "rendering frequency of " + Ceylan::toString( frequency ) 
00308         + " Hz, the rendering period corresponds to " 
00309         + Ceylan::toString( _renderingPeriod ) + " engine ticks." ) ;
00310         
00311 #endif // OSDL_DEBUG
00312 
00313 }
00314 
00315 
00316 
00317 Period Scheduler::getRenderingTickCount() const 
00318 {
00319 
00320     return _renderingPeriod ;
00321     
00322 }
00323 
00324 
00325 
00326 void Scheduler::setScreenshotFrequency( Hertz frequency ) 
00327 {
00328 
00329     
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340 
00341 
00342      
00343      if ( frequency * _engineTickDuration > 1E6 )
00344         throw SchedulingException( "Scheduler::setScreenshotFrequency: "
00345             " requested screenshot frequency (" 
00346             + Ceylan::toString( frequency )
00347             + " Hz) is too high for engine tick,"
00348             " which lasts for " + Ceylan::toString( _engineTickDuration ) 
00349             + " microseconds." ) ;
00350             
00351     _desiredScreenshotFrequency = frequency ;       
00352     _screenshotPeriod = static_cast<Period>( 
00353         1E6 / ( frequency * _engineTickDuration ) ) ;
00354 
00355 #if OSDL_DEBUG
00356 
00357     send( "Scheduler::setScreenshotFrequency: for a requested "
00358         "screenshot frequency of " + Ceylan::toString( frequency ) 
00359         + " Hz, the screenshot period corresponds to " 
00360         + Ceylan::toString( _screenshotPeriod ) + " engine ticks." ) ;
00361         
00362 #endif // OSDL_DEBUG
00363 
00364 }
00365 
00366 
00367 
00368 Period Scheduler::getScreenshotTickCount() const 
00369 {
00370 
00371     return _screenshotPeriod ;
00372     
00373 }
00374 
00375 
00376 
00377 void Scheduler::setInputPollingFrequency( Hertz frequency )     
00378 {
00379 
00380     
00381 
00382 
00383 
00384 
00385 
00386 
00387 
00388 
00389      
00390      if ( frequency * _engineTickDuration > 1E6 )
00391         throw SchedulingException( 
00392             "Scheduler::setInputPollingFrequency: requested input "
00393             "frequency (" + Ceylan::toString( frequency ) 
00394             + " Hz) is too high for engine tick,"
00395             " which lasts for " 
00396             + Ceylan::toString( _engineTickDuration ) + " microseconds." ) ;
00397             
00398     _desiredInputFrequency = frequency ;        
00399     _inputPeriod = static_cast<Period>( 
00400         1E6 / ( frequency * _engineTickDuration ) ) ;
00401 
00402 #if OSDL_DEBUG
00403 
00404     send( "Scheduler::setInputPollingFrequency: for a requested "
00405         "input frequency of " + Ceylan::toString( frequency ) 
00406         + " Hz, the input period corresponds to " 
00407         + Ceylan::toString( _inputPeriod ) + " engine ticks." ) ;
00408         
00409 #endif // OSDL_DEBUG
00410 
00411 }
00412 
00413 
00414 
00415 void Scheduler::setIdleCallback( 
00416     Ceylan::System::Callback idleCallback, 
00417     void * callbackData, 
00418     Ceylan::System::Microsecond callbackExpectedMaxDuration )   
00419 {
00420 
00421     _idleCallback     = idleCallback ;
00422     _idleCallbackData = callbackData ;
00423     
00424     if ( callbackExpectedMaxDuration != 0 )
00425         _idleCallbackMaxDuration = callbackExpectedMaxDuration ;
00426     else
00427         _idleCallbackMaxDuration = EventsModule::EvaluateCallbackduration(
00428             idleCallback, callbackData ) ;
00429     
00430 }
00431     
00432                     
00433                     
00434 Period Scheduler::getInputPollingTickCount() const 
00435 {
00436 
00437     return _inputPeriod ;
00438     
00439 }
00440 
00441 
00442 
00443 EngineTick Scheduler::getCurrentEngineTick() const  
00444 {
00445 
00446     return _currentEngineTick ;
00447     
00448 }
00449 
00450 
00451 
00452 SimulationTick Scheduler::getCurrentSimulationTick() const 
00453 {
00454 
00455     return _currentSimulationTick ;
00456     
00457 }
00458 
00459 
00460 
00461 RenderingTick Scheduler::getCurrentRenderingTick() const 
00462 {
00463 
00464     return _currentRenderingTick ;
00465     
00466 }
00467 
00468 
00469 
00470 InputTick Scheduler::getCurrentInputTick() const 
00471 {
00472 
00473     return _currentInputTick ;
00474     
00475 }
00476 
00477 
00478 
00479 
00480 Events::SimulationTick Scheduler::getNumberOfSimulationTicksFor(
00481     Ceylan::System::Millisecond duration ) const
00482 {
00483 
00484     return static_cast<Events::SimulationTick>( 
00485         Ceylan::Maths::Round( duration * 1000.f  / 
00486             ( _simulationPeriod * _engineTickDuration ) ) ) ;
00487         
00488 }
00489 
00490     
00491 
00492 Events::RenderingTick Scheduler::getNumberOfRenderingTicksFor(
00493     Ceylan::System::Millisecond duration ) const
00494 {
00495 
00496     return static_cast<Events::RenderingTick>( 
00497         Ceylan::Maths::Round( duration * 1000.f  / 
00498             ( _renderingPeriod * _engineTickDuration ) ) ) ;
00499         
00500 }
00501 
00502     
00503 
00504 Events::InputTick Scheduler::getNumberOfInputTicksFor(
00505     Ceylan::System::Millisecond duration ) const
00506 {
00507 
00508     return static_cast<Events::InputTick>( 
00509         Ceylan::Maths::Round( duration * 1000.f  / 
00510             ( _inputPeriod * _engineTickDuration ) ) ) ;
00511         
00512 
00513 }
00514 
00515     
00516 
00517 
00518 void Scheduler::registerPeriodicalObject( 
00519     PeriodicalActiveObject & objectToRegister ) 
00520 {
00521     
00522     
00523     PeriodicSlot & slot = returnPeriodicSlotFor( 
00524         objectToRegister.getPeriod() ) ;
00525             
00526     
00527     Events::Period subslot = slot.add( objectToRegister ) ; 
00528     
00529     objectToRegister.onRegistering( subslot ) ;
00530     
00531     
00532     if ( _isRunning )
00533     {
00534     
00535         
00536         objectToRegister.setBirthTick( _currentSimulationTick ) ;
00537         
00538     }   
00539     else
00540     {
00541     
00542         
00543         _initialRegisteredObjects.push_back( & objectToRegister ) ;
00544         
00545     }   
00546     
00547 }
00548 
00549 
00550 
00551 void Scheduler::unregisterPeriodicalObject( 
00552     PeriodicalActiveObject & toUnregister ) 
00553 {
00554 
00555 
00556     
00557 
00558 
00559 
00560 
00561 
00562 
00563 
00564 
00565 
00566 
00567 
00568 
00569 
00570 
00571 
00572 
00573 
00574 
00575 
00576 
00577     
00578     PeriodicSlot & slot = getPeriodicSlotFor( toUnregister.getPeriod() ) ;
00579     
00580     slot.removeFromSubslot( toUnregister ) ;
00581     
00582     send( "New scheduler state: " + toString() ) ;
00583          
00584 }
00585 
00586 
00587 
00588 void Scheduler::registerProgrammedObject( 
00589     ProgrammedActiveObject & objectToRegister ) 
00590 {
00591 
00592     
00593     
00594     const list<SimulationTick> & programmed =
00595             objectToRegister.getProgrammedActivations() ;
00596     
00597     SimulationTick offset = 0 ;
00598     
00599     if ( ! objectToRegister.areProgrammedActivationsAbsolute() )
00600     {
00601     
00602         
00603         
00604         if ( _isRunning )
00605             offset = _currentSimulationTick ;
00606         
00607         
00608 
00609 
00610 
00611 
00612 
00613 
00614 
00615     
00616     }
00617     
00618     
00619     for ( list<SimulationTick>::const_iterator it = programmed.begin(); 
00620         it != programmed.end(); it++ )
00621     {
00622         programTriggerFor( objectToRegister, (*it) + offset ) ;         
00623     }
00624         
00625     objectToRegister.onRegistering() ;
00626         
00627     
00628     if ( _isRunning )
00629     {
00630     
00631         
00632         objectToRegister.setBirthTick( _currentSimulationTick ) ;
00633         
00634     }   
00635     else
00636     {
00637     
00638         
00639         _initialRegisteredObjects.push_back( & objectToRegister ) ;
00640         
00641     }   
00642             
00643     
00644 }
00645 
00646 
00647 
00648 void Scheduler::unregisterProgrammedObject( 
00649     ProgrammedActiveObject & objectToUnregister )
00650 {
00651     
00652     
00653 
00654 
00655 
00656      
00657 
00658     
00659 
00660 
00661 
00662 
00663 
00664 
00665 
00666 
00667 
00668 
00669 
00670 
00671 
00672 
00673 
00674     
00675     
00676 
00677 
00678 
00679 
00680     SimulationTick offset = 0 ;
00681     
00682     
00683     if ( ! objectToUnregister.areProgrammedActivationsAbsolute() )
00684         offset = objectToUnregister.getBirthTick() ;
00685         
00686     const list<SimulationTick> & programmed =
00687         objectToUnregister.getProgrammedActivations() ;
00688 
00689     list<SimulationTick>::const_iterator it = programmed.begin() ;
00690 
00691     
00692     while ( ( it != programmed.end() ) 
00693         && ( (*it) + offset < _currentSimulationTick ) )
00694     {
00695         
00696         
00697 
00698 
00699 
00700          
00701         it++ ;
00702     
00703     }   
00704     
00705     
00706     
00707     
00708     while ( it != programmed.end() ) 
00709     {
00710     
00711         
00712 
00713         
00714 
00715 
00716 
00717          
00718         
00719         map<SimulationTick, ListOfProgrammedActiveObjects>::iterator mapIt =
00720             _programmedActivated.find( *it ) ;
00721         
00722         if ( mapIt != _programmedActivated.end() )
00723         {
00724         
00725             
00726 
00727 
00728 
00729 
00730             ListOfProgrammedActiveObjects::iterator listIt = 
00731                 (*mapIt).second.begin() ; 
00732             
00733             
00734 
00735 
00736 
00737 
00738 
00739 #if OSDL_DEBUG_SCHEDULER
00740             bool found = false ;            
00741 #endif // OSDL_DEBUG_SCHEDULER                  
00742 
00743 
00744             while ( listIt != (*mapIt).second.end() )
00745             {
00746             
00747 
00748                 if ( *listIt == & objectToUnregister )
00749                 {
00750                 
00751                     
00752 
00753 
00754 
00755 
00756                         
00757                     *listIt = 0 ;
00758                      
00759 #if OSDL_DEBUG_SCHEDULER
00760 
00761                     
00762                     if ( found )
00763                         throw SchedulingException( 
00764                             "Scheduler::unregisterProgrammedObject: "
00765                             "object was registered more than once for tick "
00766                             + Ceylan::toString(*it) + "." ) ;
00767                     else
00768                         found = true ;                          
00769                     
00770 #else // OSDL_DEBUG_SCHEDULER
00771                      
00772                     
00773                     break ;
00774                     
00775 #endif // OSDL_DEBUG_SCHEDULER                  
00776                 }
00777                     
00778                 listIt++ ;
00779                 
00780             }
00781     
00782     
00783             
00784 #if OSDL_DEBUG_SCHEDULER
00785 
00786             if ( ! found )
00787 
00788 #else // OSDL_DEBUG_SCHEDULER
00789             
00790             
00791             if ( listIt == (*mapIt).second.end() )
00792             
00793 #endif 
00794             
00795                 throw SchedulingException( 
00796                     "Scheduler::unregisterProgrammedObject failed when "
00797                     "unregistering " + objectToUnregister.toString() 
00798                     + ": expected to find a programmed activation for tick #"
00799                     + Ceylan::toString( *it ) 
00800                     + ", while current scheduler state is: "
00801                     + toString() ) ;
00802             
00803 
00804 
00805 
00806 
00807                                                     
00808         }
00809         else
00810         {
00811         
00812             throw SchedulingException( 
00813                 "Scheduler::unregisterProgrammedObject failed when "
00814                 "unregistering " + objectToUnregister.toString() 
00815                 + ": a programmed activation list for tick #"
00816                 + Ceylan::toString( *it ) + " should have existed." ) ; 
00817         }
00818 
00819         it++ ;
00820         
00821     }
00822     
00823     
00824 
00825     
00826 }
00827 
00828     
00829                     
00830 void Scheduler::schedule()
00831 {
00832     
00833     try
00834     {
00835     
00836         _eventsModule = & OSDL::getExistingCommonModule().getEventsModule() ;
00837         
00838     }
00839     catch( OSDL::Exception & e )
00840     {
00841         throw SchedulingException( "Scheduler::schedule: "
00842             "no events module available." ) ;
00843     }
00844     
00845     
00846     if ( _renderer != 0 )
00847     {
00848         send( "Scheduling now, using renderer: " + _renderer->toString() ) ;
00849     }
00850     else
00851     {
00852         
00853         try
00854         {
00855         
00856             _videoModule = & OSDL::getExistingCommonModule().getVideoModule() ;
00857             
00858         }
00859         catch( OSDL::Exception & e )
00860         {
00861             throw SchedulingException( "Scheduler::schedule: "
00862                 "no renderer nor video module available." ) ;
00863         }
00864         
00865         send( "Scheduling now, using video module (no renderer)." ) ;
00866         
00867     }
00868     
00869     
00870     if ( _screenshotMode )
00871         scheduleNoDeadline() ;
00872     else
00873         scheduleBestEffort() ;  
00874         
00875 }
00876 
00877 
00878 
00879 void Scheduler::stop() 
00880 {
00881 
00882     _stopRequested = true ;
00883     
00884 }
00885 
00886 
00887 
00888 void Scheduler::setStopCallback( Ceylan::System::Callback stopCallback, 
00889     void * callbackData )
00890 {
00891 
00892     _stopCallback = stopCallback ;
00893     _stopCallbackData = callbackData ;
00894     
00895 }
00896 
00897 
00898 
00899 const string Scheduler::toString( Ceylan::VerbosityLevels level ) const 
00900 {   
00901 
00902     ostringstream buf ;
00903     buf.precision( 2 ) ;
00904 
00905     buf << setiosflags( std::ios::fixed ) 
00906         << "Scheduler, whose internal frequency is " 
00907         << 1E6 / _engineTickDuration
00908         << " Hz (engine tick duration is " 
00909         + Ceylan::toString( _engineTickDuration )
00910         + " microseconds). Current engine tick is " 
00911         + Ceylan::toString( _currentEngineTick ) 
00912         + ", current simulation tick is "
00913         + Ceylan::toString( _currentSimulationTick )
00914         + ", current rendering tick is "
00915         + Ceylan::toString( _currentRenderingTick ) 
00916         + " and current input tick is " 
00917         + Ceylan::toString( _currentInputTick )
00918         + ". Screenshot mode is "
00919         + ( _screenshotMode ? "on.": "off." ) ;
00920     
00921                     
00922     if ( _isRunning )
00923     {
00924     
00925         Ceylan::System::Second sec ;
00926         Ceylan::System::Microsecond microsec ;
00927         Ceylan::System::getPreciseTime( sec, microsec ) ;
00928         
00929         
00930 
00931 
00932 
00933 
00934         buf << " Scheduler has been running for " 
00935             << Ceylan::System::durationToString( _scheduleStartingSecond,
00936                 _scheduleStartingMicrosecond, sec, microsec )
00937             << "." ;
00938         
00939     }   
00940     else
00941     {
00942     
00943         buf << " Scheduler is not running." ;
00944 
00945     }
00946 
00947 
00948     if ( _renderer != 0 )
00949         buf << " Using a renderer (" 
00950             + _renderer->toString( Ceylan::low ) + ")" ;
00951     else
00952         buf << " No renderer registered, using directly video module" ;
00953 
00954     if ( _idleCallback == 0 )
00955         buf << ". Using default atomic sleep idle callback" ;
00956     else
00957         buf << ". Using user-specified idle callback" ;
00958     
00959     
00960     if ( _idleCallbackData )
00961     {
00962     
00963         if ( _idleCallback != 0 )
00964             buf << ", callback data has been set as well." ;
00965         else
00966             buf << ", callback data has been set, "
00967                 " whereas it is not used by default idle callback (abnormal)." ;
00968                 
00969     }
00970     
00971     
00972     buf << ". The estimated upper-bound for idle callback duration is "
00973         + Ceylan::toString( _idleCallbackMaxDuration )
00974         + " microseconds" ;
00975                 
00976     buf << ". Minimal measured callback duration was "
00977         + Ceylan::toString( _idleCallbackMinMeasuredDuration )
00978         + " microseconds, maximal was " 
00979         + Ceylan::toString( _idleCallbackMaxMeasuredDuration )
00980         + " microseconds" ;
00981                 
00982                 
00983     if ( level == Ceylan::low )
00984         return buf.str() ;
00985             
00986     
00987             
00988     buf <<  ". User-defined simulation frequency is " 
00989         + Ceylan::toString( 1E6 / ( _simulationPeriod * _engineTickDuration ), 
00990              2 )
00991         + " Hz (a period of " 
00992         + Ceylan::toString( _simulationPeriod ) 
00993         + " engine ticks), rendering frequency is "
00994         + Ceylan::toString( 1E6 / ( _renderingPeriod * _engineTickDuration ),
00995              2 ) 
00996         + " Hz (a period of " 
00997         + Ceylan::toString( _renderingPeriod ) 
00998         + " engine ticks), input polling frequency is "
00999         + Ceylan::toString( 1E6 / ( _inputPeriod * _engineTickDuration ),
01000              2 ) 
01001         + " Hz (a period of " 
01002         + Ceylan::toString( _inputPeriod ) 
01003         + " engine ticks). There are "
01004         + Ceylan::toString( 
01005             static_cast<Ceylan::Uint32>( _periodicSlots.size() ) ) 
01006         + " used periodic slot(s) and "
01007         + Ceylan::toString( 
01008             static_cast<Ceylan::Uint32>( _programmedActivated.size() ) )
01009         + " programmed object(s)" ;
01010         
01011         
01012     if ( level == Ceylan::medium )
01013         return buf.str() ;
01014         
01015         
01016     if ( ! _periodicSlots.empty() )
01017     {
01018         
01019         buf << ". Enumerating scheduling periodic slots: " ;
01020         
01021         std::list<string> slots ;
01022         
01023         for ( list<PeriodicSlot*>::const_iterator it = _periodicSlots.begin(); 
01024                 it != _periodicSlots.end(); it++ )
01025             slots.push_back( (*it)->toString( level ) ) ;
01026 
01027         buf << Ceylan::formatStringList( slots ) ;
01028             
01029     }
01030     
01031     if ( ! _programmedActivated.empty() )
01032     {
01033     
01034         buf << ". Enumerating scheduling programmed slots: " ;
01035         
01036         std::list<string> programmed ;
01037         
01038         for( map<SimulationTick, 
01039                 ListOfProgrammedActiveObjects>::const_iterator it 
01040                     = _programmedActivated.begin(); 
01041                 it != _programmedActivated.end(); it++ )
01042             programmed.push_back( "For simulation tick #" 
01043                 + Ceylan::toString( (*it).first ) + ", there are " 
01044                 + Ceylan::toString( 
01045                     static_cast<Ceylan::Uint32>( (*it).second.size() ) )
01046                 + " object(s) programmed (note: some of them may be null "
01047                  "pointers corresponding to unregistered objects)" ) ;
01048                 
01049         buf << Ceylan::formatStringList( programmed ) ;
01050         
01051     }   
01052     
01053     
01054     if ( _screenshotMode )
01055     {
01056     
01057         buf << ". Current movie frame period for screenshot mode is " 
01058             + Ceylan::toString( _screenshotPeriod ) 
01059             + " engine ticks, which corresponds to a frequency of "
01060             + Ceylan::toString( 1E6 /
01061                 ( _screenshotPeriod * _engineTickDuration ),  2 )
01062             + " frames per second" ;    
01063 
01064         
01065         return buf.str() ;
01066     }
01067     
01068         
01069     if ( _missedSimulationTicks == 0 )
01070     {
01071     
01072         buf << ". No simulation tick was missed" ;
01073     
01074     }   
01075     else
01076     {
01077     
01078         Ceylan::System::Second sec ;
01079         Ceylan::System::Microsecond microsec ;
01080         Ceylan::System::getPreciseTime( sec, microsec ) ;
01081 
01082         
01083         buf << ". " + Ceylan::toString( _missedSimulationTicks ) 
01084             + " simulation ticks were missed, "
01085             "it sums up to an actual average simulation frequency of "  
01086             << 1E6 * ( _currentSimulationTick - _missedSimulationTicks ) / 
01087                 static_cast<Ceylan::Float64>( 
01088                     ( sec - _scheduleStartingSecond ) * 1E6
01089                     + microsec - _scheduleStartingMicrosecond ) 
01090             << " Hz" ;  
01091                             
01092     }   
01093         
01094         
01095     if ( _missedRenderingTicks == 0 )
01096         buf << ". No rendering tick was missed" ;
01097     else
01098     {
01099     
01100         Ceylan::System::Second sec ;
01101         Ceylan::System::Microsecond microsec ;
01102         Ceylan::System::getPreciseTime( sec, microsec ) ;
01103 
01104         buf << ". " + Ceylan::toString( _missedRenderingTicks ) 
01105             + " rendering ticks were missed, "
01106             "it sums up to an actual average rendering frequency of "
01107             << 1E6 * ( _currentRenderingTick - _missedRenderingTicks ) / 
01108                 static_cast<Ceylan::Float64>( 
01109                     ( sec - _scheduleStartingSecond ) * 1E6
01110                     + microsec - _scheduleStartingMicrosecond )
01111             << " Hz" ;  
01112     }
01113             
01114             
01115     if ( _missedInputPollingTicks == 0 )
01116         buf << ". No input tick was missed" ;
01117     else
01118     {
01119     
01120         Ceylan::System::Second sec ;
01121         Ceylan::System::Microsecond microsec ;
01122         Ceylan::System::getPreciseTime( sec, microsec ) ;
01123 
01124         buf << ". " + Ceylan::toString( _missedInputPollingTicks ) 
01125             + " input ticks were missed, "
01126             "it sums up to an actual average input frequency of "
01127             << 1E6 * ( _currentInputTick - _missedInputPollingTicks ) / 
01128                 static_cast<Ceylan::Float64>( 
01129                     ( sec - _scheduleStartingSecond ) * 1E6
01130                     + microsec - _scheduleStartingMicrosecond ) 
01131             << " Hz" ;  
01132     }       
01133     
01134     return buf.str() ;
01135                 
01136 }
01137 
01138 
01139 
01140 
01141 
01142 
01143 
01144 
01145 
01146 Scheduler & Scheduler::GetExistingScheduler()
01147 {
01148 
01149     if ( Scheduler::_internalScheduler == 0 )
01150         throw SchedulingException( 
01151             "Scheduler::GetExistingScheduler: no scheduler available." ) ;
01152             
01153     return * Scheduler::_internalScheduler ;
01154 
01155 }
01156 
01157 
01158 
01159 Scheduler & Scheduler::GetScheduler()
01160 {
01161 
01162     if ( Scheduler::_internalScheduler == 0 )
01163     {
01164     
01165         LogPlug::debug( "Scheduler::GetScheduler: "
01166             "no scheduler available, creating a new one." ) ;
01167             
01168         Scheduler::_internalScheduler = new Scheduler() ;
01169         
01170     }
01171     else
01172     {
01173     
01174         LogPlug::debug( "Scheduler::GetScheduler: "
01175             "returning already constructed instance of scheduler, "
01176             "no creation." ) ;
01177             
01178     }
01179 
01180     LogPlug::debug( "Scheduler::GetScheduler: returning Scheduler instance "
01181         + Ceylan::toString( Scheduler::_internalScheduler ) ) ;
01182 
01183     return * Scheduler::_internalScheduler ;
01184 
01185 }
01186 
01187 
01188 
01189 void Scheduler::DeleteExistingScheduler()
01190 {
01191 
01192     if ( Scheduler::_internalScheduler != 0 )
01193         throw SchedulingException( "Scheduler::DeleteExistingScheduler: "
01194             "there was no already existing scheduler." ) ;
01195             
01196 #if OSDL_DEBUG_SCHEDULER
01197     LogPlug::debug( 
01198         "Scheduler::DeleteExistingScheduler: effective deleting." ) ;
01199 #endif // OSDL_DEBUG_SCHEDULER
01200         
01201     delete Scheduler::_internalScheduler ;
01202     Scheduler::_internalScheduler = 0 ;
01203 
01204 }
01205 
01206 
01207 
01208 void Scheduler::DeleteScheduler() 
01209 {
01210 
01211     if ( Scheduler::_internalScheduler != 0 )
01212     {
01213     
01214 #if OSDL_DEBUG_SCHEDULER
01215         LogPlug::debug( "Scheduler::DeleteScheduler: effective deleting." ) ;
01216 #endif // OSDL_DEBUG_SCHEDULER
01217         
01218         delete Scheduler::_internalScheduler ;
01219         Scheduler::_internalScheduler = 0 ;
01220         
01221     }
01222     else
01223     {
01224     
01225 #if OSDL_DEBUG_SCHEDULER
01226         LogPlug::debug( "Scheduler::DeleteScheduler: no deleting needed." ) ;
01227 #endif // OSDL_DEBUG_SCHEDULER
01228         
01229     }
01230 
01231 }
01232 
01233 
01234 
01235 void Scheduler::StopExistingScheduler() 
01236 {
01237 
01238     if ( Scheduler::_internalScheduler != 0 )
01239     {
01240     
01241 #if OSDL_DEBUG_SCHEDULER
01242         LogPlug::debug( "Scheduler::StopExistingScheduler: stopping now." ) ;
01243 #endif // OSDL_DEBUG_SCHEDULER
01244         
01245         Scheduler::_internalScheduler->stop() ;
01246 
01247     }
01248     else
01249     {
01250     
01251         throw SchedulingException( "Scheduler::StopExistingScheduler failed: "
01252             "no scheduler available." ) ;
01253         
01254     }
01255 
01256 }
01257 
01258 
01259 
01260 
01261 
01262 
01263 
01264 Scheduler::Scheduler():
01265     _screenshotMode( false ),
01266     _desiredScreenshotFrequency( DefaultMovieFrameFrequency ),
01267     _screenshotPeriod( 0 ),
01268     _periodicSlots(),
01269     _initialRegisteredObjects(),
01270     _programmedActivated(),
01271     _engineTickDuration( 0 ),
01272     _secondToEngineTick( 0 ),
01273     _currentEngineTick( 0 ),
01274     _currentSimulationTick( 0 ),
01275     _currentRenderingTick( 0 ),
01276     _currentInputTick( 0 ),
01277     _simulationPeriod( 0 ),
01278     _renderingPeriod( 0 ),
01279     _inputPeriod( 0 ),
01280     _desiredSimulationFrequency( DefaultSimulationFrequency ),
01281     _desiredRenderingFrequency( DefaultRenderingFrequency ),
01282     _desiredInputFrequency( DefaultInputFrequency ),
01283     _idleCallback( 0 ),
01284     _idleCallbackData( 0 ),
01285     _idleCallbackMaxDuration( 0 ),
01286     _idleCallbackMinMeasuredDuration( 0 ),
01287     _idleCallbackMaxMeasuredDuration( 0 ),
01288     _idleCallsCount( 0 ),
01289     _isRunning( false ),
01290     _stopRequested( false ),
01291     _stopCallback( 0 ),
01292     _stopCallbackData( 0 ),
01293     _scheduleStartingSecond( 0 ),
01294     _scheduleStartingMicrosecond( 0 ),
01295     _recoveredSimulationTicks( 0 ),
01296     _missedSimulationTicks( 0 ),
01297     _recoveredRenderingTicks( 0 ),
01298     _missedRenderingTicks( 0 ),
01299     _recoveredInputPollingTicks( 0 ),
01300     _missedInputPollingTicks( 0 ),
01301     _scheduleFailureCount( 0 ),
01302     _eventsModule( 0 ),
01303     _renderer( 0 ),
01304     _videoModule( 0 )
01305 {
01306 
01307     _subSecondSleepsAvailable = Ceylan::System::areSubSecondSleepsAvailable() ;
01308 
01309     if ( ! _subSecondSleepsAvailable )
01310         throw SchedulingException( "Scheduler constructor: "
01311             "scheduler could not be created as no subsecond sleep is "
01312             "available on this platform." ) ;
01313         
01314     
01315     send( "On scheduler creation, "
01316         "detected operating system scheduling granularity is about "
01317         + Ceylan::toString( getSchedulingGranularity() ) + " microseconds." ) ;
01318 
01319     
01320     setTimeSliceDuration( DefaultEngineTickDuration ) ;
01321         
01322     send( "Scheduler created." ) ;
01323 
01324     dropIdentifier() ;
01325     
01326 }
01327 
01328 
01329 
01330 Scheduler::~Scheduler() throw()
01331 {
01332 
01333     send( "Deleting scheduler." ) ;
01334     
01335     for ( list<PeriodicSlot *>::iterator it = _periodicSlots.begin(); 
01336             it != _periodicSlots.end(); it++ )
01337         delete (*it ) ;
01338 
01339     send( "Periodic slots deleted." ) ;
01340     
01341     
01342     if ( _renderer != 0 )
01343         delete _renderer ;
01344         
01345     send( "Scheduler deleted." ) ;
01346     
01347 }
01348 
01349 
01350 
01351 void Scheduler::scheduleBestEffort()
01352 {
01353 
01354     _isRunning = true ;
01355     
01356     
01357 
01358 
01359 
01360 
01361     if ( _idleCallback == 0 && _idleCallbackMaxDuration == 0 )
01362     {
01363 
01364         Ceylan::System::Second testStartingSecond, testStoppingSecond ;
01365     
01366         Ceylan::System::Microsecond testStartingMicrosecond, 
01367             testStoppingMicrosecond ;
01368         
01369         getPreciseTime( testStartingSecond, testStartingMicrosecond ) ;
01370         
01371         onIdle() ;
01372 
01373         getPreciseTime( testStoppingSecond, testStoppingMicrosecond ) ;
01374         
01375         Microsecond testDuration = getDurationBetween( 
01376             testStartingSecond, testStartingMicrosecond,
01377             testStoppingSecond, testStoppingMicrosecond ) ;
01378 
01379         
01380 
01381 
01382 
01383 
01384 
01385         _idleCallbackMaxDuration = Ceylan::Maths::Max( testDuration, 
01386             getSchedulingGranularity() ) ;
01387 
01388         OSDL_SCHEDULE_LOG( 
01389             "Evaluating the maximum duration of the default idle callback to " 
01390             + Ceylan::toString( _idleCallbackMaxDuration )+ " microseconds." ) ;
01391 
01392     }
01393     
01394         
01395     
01396 
01397 
01398 
01399 
01400 
01401 
01402 
01403 
01404 
01405 
01406 
01407 
01408 
01409 
01410 
01411 
01412 
01413 
01414 
01415 
01416 
01417 
01418 
01419 
01420 
01421     
01422     Microsecond baseIdleCallbackDuration = _idleCallbackMaxDuration ;
01423                 
01424     
01425     EngineTick baseIdleCallbackTickCount = static_cast<EngineTick>( 
01426         Ceylan::Maths::Ceil( 
01427             static_cast<Ceylan::Float32>( baseIdleCallbackDuration ) /
01428                 _engineTickDuration ) ) ;
01429 
01430     if ( baseIdleCallbackTickCount == 0 )
01431         baseIdleCallbackTickCount = 1 ;
01432         
01433                     
01434         
01435 
01436     OSDL_SCHEDULE_LOG( "Initial estimated duration for the idle callback is "
01437         + Ceylan::toString( _idleCallbackMaxDuration ) + " microseconds, i.e. "
01438         + Ceylan::toString( baseIdleCallbackTickCount ) 
01439         + " engine ticks." ) ;
01440         
01441 
01442     
01443 
01444 
01445 
01446 
01447 
01448 
01449 
01450 
01451 
01452 
01453 
01454  
01455     getPreciseTime( _scheduleStartingSecond, _scheduleStartingMicrosecond ) ;
01456     
01457     send( "Scheduler starting in soft real-time best effort mode. " 
01458         "Scheduler informations: " + toString( Ceylan::low ) ) ;
01459     
01460     
01461 
01462 
01463 
01464 
01465 
01466     _idleCallbackMinMeasuredDuration = 10 * _idleCallbackMaxDuration ;
01467     
01468     
01469     
01470 
01471 
01472 
01473 
01474 
01475     _idleCallbackMaxMeasuredDuration = _idleCallbackMaxDuration ;
01476     
01477     Events::EngineTick idleCallbackMaxTickCount = 
01478         _idleCallbackMaxMeasuredDuration / _engineTickDuration + 1 ;
01479     
01480     
01481     
01482     
01483     _stopRequested = false ;
01484     
01485     _recoveredSimulationTicks = 0 ;
01486     _missedSimulationTicks    = 0 ;
01487     
01488     _recoveredRenderingTicks = 0 ;
01489     _missedRenderingTicks    = 0 ;
01490     
01491     _recoveredInputPollingTicks = 0 ;
01492     _missedInputPollingTicks    = 0 ;
01493     
01494     
01495 #if OSDL_DEBUG_SCHEDULER
01496     
01497     
01498 
01499 
01500 
01501 
01502 
01503      
01504     list<SimulationTick> metSimulations ;
01505     list<SimulationTick> recoveredSimulations ;
01506     list<SimulationTick> missedSimulations ;
01507     
01508     list<RenderingTick>  metRenderings ;    
01509     list<RenderingTick>  recoveredRenderings ;  
01510     list<RenderingTick>  missedRenderings ;
01511         
01512     list<InputTick>      metInputPollings ; 
01513     list<InputTick>      recoveredInputPollings ;   
01514     list<InputTick>      missedInputPollings ;  
01515 
01516     list<Microsecond>    forecastIdleCallbackDurationList ;
01517     list<Microsecond>    actualIdleCallbackDurationList ;
01518         
01519 #endif // OSDL_DEBUG_SCHEDULER
01520     
01521     
01522      
01523     
01524 
01525 
01526 
01527 
01528 
01529     _currentEngineTick = computeEngineTickFromCurrentTime() ;   
01530 
01531     OSDL_SCHEDULE_LOG( "Simulation period: " 
01532         + Ceylan::toString( _simulationPeriod ) + " engine ticks" ) ;
01533         
01534     OSDL_SCHEDULE_LOG( "Rendering period: " 
01535         + Ceylan::toString( _renderingPeriod ) + " engine ticks" ) ;
01536 
01537     OSDL_SCHEDULE_LOG( "Input period: " 
01538         + Ceylan::toString( _inputPeriod ) + " engine ticks" ) ;
01539     
01540     _currentSimulationTick = _currentEngineTick / _simulationPeriod  ;  
01541     _currentRenderingTick  = _currentEngineTick / _renderingPeriod;
01542     _currentInputTick      = _currentEngineTick / _inputPeriod;
01543     
01544 
01545     
01546 
01547 
01548 
01549 
01550 
01551     setInitialBirthTicks( _currentSimulationTick ) ;    
01552 
01553     OSDL_SCHEDULE_LOG( "Initial engine tick: " 
01554         + Ceylan::toString( _currentEngineTick ) ) ;
01555         
01556     OSDL_SCHEDULE_LOG( "Initial simulation tick: "
01557         + Ceylan::toString( _currentSimulationTick ) ) ;
01558         
01559     OSDL_SCHEDULE_LOG( "Initial rendering tick: "
01560         + Ceylan::toString( _currentRenderingTick ) ) ;
01561         
01562     OSDL_SCHEDULE_LOG( "Initial input tick: "
01563         + Ceylan::toString( _currentInputTick ) ) ;
01564         
01565 
01566     EngineTick nextSimulationDeadline = _currentEngineTick + _simulationPeriod ;
01567     EngineTick nextRenderingDeadline  = _currentEngineTick + _renderingPeriod ;
01568     EngineTick nextInputDeadline      = _currentEngineTick + _inputPeriod ;
01569     
01570     EngineTick nextDeadline = Ceylan::Maths::Min( nextSimulationDeadline,
01571         nextRenderingDeadline, nextInputDeadline ) ;
01572     
01573     OSDL_SCHEDULE_LOG( "Initial deadline: " 
01574         + Ceylan::toString( nextDeadline ) ) ;
01575     
01576     
01577 
01578 
01579 
01580 
01581 
01582 
01583 
01584 
01585 
01586 
01587 
01588 
01589 
01590 
01591 
01592 
01593 
01594 
01595 
01596 
01597 
01598 
01599 
01600 
01601 
01602 
01603 
01604     
01605     
01606     Delay delayBucket = 0 ;
01607     
01608     
01609     Delay maxDelayBucket = 0 ;
01610 
01611     
01612 
01613 
01614 
01615 
01616     Delay delayCumulativeBucket = 0 ;
01617     
01618     
01619     
01620 
01621 
01622 
01623 
01624     const Delay bucketFillThreshold = 100000 ;
01625 
01626 
01627     
01628 
01629 
01630 
01631 
01632     const Ceylan::Float32 bucketLeakingFactor = 0.9f ;
01633     
01634     _scheduleFailureCount = 0 ;
01635     
01636     
01637     
01638 
01639 
01640 
01641 
01642 
01643 
01644 
01645 
01646 
01647 
01648 
01649 
01650 
01651     const Microsecond simulationToleranceTime = 800000 ;
01652     
01653     const EngineTick simulationToleranceTick = static_cast<EngineTick>( 
01654         simulationToleranceTime / _engineTickDuration ) ; 
01655     
01656     send( "Simulation tolerance time is " 
01657         + Ceylan::toString( simulationToleranceTime ) + " microseconds, i.e. "
01658         + Ceylan::toString( simulationToleranceTick ) + " engine ticks." ) ;
01659         
01660         
01661     
01662 
01663 
01664 
01665 
01666 
01667 
01668 
01669 
01670 
01671 
01672 
01673 
01674 
01675     
01676     
01677 
01678 
01679 
01680 
01681     const EngineTick renderingToleranceTick = _renderingPeriod / 4 ;
01682     
01683     send( "Rendering tolerance is "
01684         + Ceylan::toString( renderingToleranceTick ) 
01685         + " engine ticks, which translates into a tolerance of " 
01686         + Ceylan::toString( renderingToleranceTick * _engineTickDuration )
01687         + " microseconds." ) ;
01688         
01689         
01690     
01691 
01692 
01693 
01694 
01695 
01696 
01697 
01698 
01699 
01700 
01701 
01702 
01703 
01704 
01705     
01706 
01707 
01708 
01709 
01710     const EngineTick inputToleranceTick = _inputPeriod / 2 ;
01711     
01712     send( "Input polling tolerance is "
01713         + Ceylan::toString( inputToleranceTick ) 
01714         + " engine ticks, which translates into a tolerance of " 
01715         + Ceylan::toString( inputToleranceTick * _engineTickDuration )
01716         + " microseconds." ) ;
01717         
01718         
01719     
01720     getPreciseTime( _scheduleStartingSecond, _scheduleStartingMicrosecond ) ;
01721     
01722     Ceylan::System::Second idleStartingSecond, idleStoppingSecond ;
01723     
01724     Ceylan::System::Microsecond idleStartingMicrosecond, 
01725         idleStoppingMicrosecond ;
01726     
01727     
01728     _idleCallsCount = 0 ;
01729 
01730 
01731     
01732     Events::EngineTick lastIdleTickCount = idleCallbackMaxTickCount ;
01733     
01734         
01735     
01736 
01737 
01738 
01739 
01740     Events::EngineTick forecastIdleCallbackTickCount = 
01741          idleCallbackMaxTickCount / 2 ; 
01742     
01743 
01744     
01745     
01746     
01747     while ( ! _stopRequested )
01748     {
01749         
01750         
01751         OSDL_SCHEDULE_LOG( "[ E: " + Ceylan::toString( _currentEngineTick  )
01752             + " ; S: " + Ceylan::toString( _currentSimulationTick )
01753             + " ; R: " + Ceylan::toString( _currentRenderingTick )
01754             + " ; I: " + Ceylan::toString( _currentInputTick )
01755             + " ; B: " + Ceylan::toString(  delayBucket ) + " ]" ) ;
01756 
01757 
01758 #if OSDL_DEBUG_SCHEDULER
01759 
01760         
01761         if ( _currentEngineTick % 1000 == 0 )
01762             send( "[ E: " + Ceylan::toString( _currentEngineTick )
01763                 + " ; S: " + Ceylan::toString( _currentSimulationTick )
01764                 + " ; R: " + Ceylan::toString( _currentRenderingTick )
01765                 + " ; I: " + Ceylan::toString( _currentInputTick )
01766                 + " ; B: " + Ceylan::toString( delayBucket )
01767                 + " ]" ) ;          
01768                 
01769 #endif // OSDL_DEBUG_SCHEDULER
01770 
01771         
01772         delayCumulativeBucket += delayBucket ;
01773         
01774         
01775         delayBucket = static_cast<Delay>( delayBucket * bucketLeakingFactor ) ;
01776                 
01777         
01778 
01779 
01780 
01781 
01782 
01783 
01784 
01785 
01786 
01787 
01788                                 
01789         
01790         
01791         
01792         
01793         
01794         
01795         
01796         if ( _currentEngineTick == nextSimulationDeadline )
01797         {
01798             
01799             
01800                 
01801 #if OSDL_DEBUG_SCHEDULER
01802             metSimulations.push_back( _currentSimulationTick ) ;
01803 #endif // OSDL_DEBUG_SCHEDULER
01804             
01805             scheduleSimulation( _currentSimulationTick ) ;
01806             
01807             _currentSimulationTick++ ;
01808             nextSimulationDeadline += _simulationPeriod ;
01809             
01810         }
01811         
01812 
01813 
01814         if ( _currentEngineTick == nextRenderingDeadline )
01815         {
01816         
01817             
01818                 
01819 #if OSDL_DEBUG_SCHEDULER
01820             metRenderings.push_back( _currentRenderingTick ) ;
01821 #endif // OSDL_DEBUG_SCHEDULER
01822 
01823             scheduleRendering( _currentRenderingTick ) ;
01824 
01825             _currentRenderingTick++ ;
01826             nextRenderingDeadline += _renderingPeriod ;
01827             
01828         }
01829         
01830 
01831 
01832         if ( _currentEngineTick == nextInputDeadline )
01833         {
01834         
01835             
01836                 
01837 #if OSDL_DEBUG_SCHEDULER
01838             metInputPollings.push_back( _currentInputTick ) ;
01839 #endif // OSDL_DEBUG_SCHEDULER
01840 
01841             scheduleInput( _currentInputTick ) ;
01842 
01843             _currentInputTick++ ;
01844             nextInputDeadline += _inputPeriod ;
01845             
01846         }
01847         
01848 
01849         
01850         
01851 
01852 
01853 
01854 
01855 
01856 
01857 
01858 
01859 
01860 
01861 
01862 
01863 
01864 
01865 
01866 
01867         _currentEngineTick = computeEngineTickFromCurrentTime() ;
01868         
01869         
01870         
01871 
01872 
01873 
01874 
01875 
01876         while ( nextSimulationDeadline < _currentEngineTick + 1 
01877             && delayBucket < ShutdownBucketLevel )  
01878         {           
01879         
01880         
01881             
01882             EngineTick missedTicks = 
01883                 _currentEngineTick + 1 - nextSimulationDeadline ;
01884             
01885             if ( missedTicks > simulationToleranceTick )
01886             {
01887             
01888                 
01889 
01890 
01891 
01892 
01893 
01894 
01895 
01896                  
01897                 
01898 
01899 
01900 
01901 
01902 
01903 
01904 
01905 
01906 
01907 
01908 
01909 
01910 
01911 
01912 
01913 
01914 
01915 
01916 
01917 
01918 
01919 
01920 
01921 
01922 
01923 
01924 
01925 
01926 
01927 
01928 
01929 
01930 
01931 
01932                 delayBucket += 35 * static_cast<Delay>( 
01933                     Ceylan::Maths::Sqrt( 2.0f * missedTicks ) ) ;
01934                 
01935                 
01936 
01937 
01938 
01939 
01940 #if OSDL_DEBUG_SCHEDULER
01941                 missedSimulations.push_back( _currentSimulationTick ) ;
01942 #endif // OSDL_DEBUG_SCHEDULER
01943             
01944                 
01945                 
01946 
01947 
01948 
01949 
01950                 onSimulationSkipped( _currentSimulationTick ) ;
01951             
01952                 
01953             }   
01954             else
01955             {
01956             
01957                 
01958                 _recoveredSimulationTicks++ ;
01959                 
01960                 
01961                 missedTicks-- ;
01962                 
01963                 OSDL_SCHEDULE_LOG( "@@@@@ Simulation deadline #"
01964                     + Ceylan::toString( _currentSimulationTick ) 
01965                     + " recovered from "
01966                     + Ceylan::toString( missedTicks )
01967                     + " engine ticks delay (" 
01968                     + Ceylan::toString( missedTicks * _engineTickDuration )  
01969                     + " microseconds)." ) ;
01970                 
01971                 
01972                 delayBucket += 20 ;
01973 
01974 #if OSDL_DEBUG_SCHEDULER
01975                 recoveredSimulations.push_back( _currentSimulationTick ) ;
01976 #endif // OSDL_DEBUG_SCHEDULER
01977             
01978                 scheduleSimulation( _currentSimulationTick ) ;
01979             
01980             }
01981 
01982             _currentSimulationTick++ ;
01983             
01984             nextSimulationDeadline += _simulationPeriod ;
01985             
01986             _currentEngineTick = computeEngineTickFromCurrentTime() ;
01987             
01988             
01989                     
01990         }
01991         
01992         
01993         
01994 
01995 
01996 
01997 
01998 
01999 
02000 
02001 
02002 
02003 
02004 
02005 
02006 
02007 
02008 
02009 
02010 
02011 
02012         bool renderingCompensated = false ;
02013                  
02014         while ( nextRenderingDeadline < _currentEngineTick + 1
02015             && delayBucket < ShutdownBucketLevel )  
02016         {           
02017         
02018             
02019             EngineTick missedTicks = 
02020                 _currentEngineTick + 1 - nextRenderingDeadline ;
02021 
02022             if ( missedTicks > renderingToleranceTick 
02023                 || renderingCompensated )
02024             {
02025 
02026                 
02027 
02028 
02029 
02030 
02031 
02032 
02033 
02034                  
02035                 
02036                 delayBucket += 5 * static_cast<Delay>( 
02037                     Ceylan::Maths::Sqrt( 2.0f * missedTicks ) ) ;
02038                     
02039                                 
02040 #if OSDL_DEBUG_SCHEDULER
02041                 missedRenderings.push_back( _currentRenderingTick ) ;
02042 #endif // OSDL_DEBUG_SCHEDULER
02043             
02044                 onRenderingSkipped( _currentRenderingTick ) ;
02045             
02046             }
02047             else
02048             {   
02049             
02050                 
02051                 _recoveredRenderingTicks++ ;
02052             
02053                 
02054                 missedTicks-- ;
02055 
02056                 OSDL_SCHEDULE_LOG( "@@@@@ Rendering deadline #"
02057                     + Ceylan::toString( _currentRenderingTick ) 
02058                     + " recovered from "    + Ceylan::toString( missedTicks )
02059                     + " engine ticks delay (" 
02060                     + Ceylan::toString( missedTicks * _engineTickDuration )  
02061                     + " microseconds)." ) ;
02062                 
02063                 
02064                 delayBucket += 10 ;
02065 
02066 #if OSDL_DEBUG_SCHEDULER
02067                 recoveredRenderings.push_back( _currentRenderingTick ) ;
02068 #endif // OSDL_DEBUG_SCHEDULER
02069 
02070                 scheduleRendering( _currentRenderingTick ) ;
02071 
02072                 renderingCompensated = true ;
02073 
02074             }
02075             
02076             _currentRenderingTick++ ;
02077             
02078             nextRenderingDeadline += _renderingPeriod ;
02079             
02080             _currentEngineTick = computeEngineTickFromCurrentTime() ;
02081                                     
02082         }
02083         
02084         
02085         
02086 
02087 
02088 
02089 
02090 
02091 
02092 
02093 
02094 
02095 
02096 
02097         bool inputPollingCompensated = false ;
02098         
02099         while ( nextInputDeadline < _currentEngineTick + 1  
02100             && delayBucket < ShutdownBucketLevel )  
02101         {           
02102         
02103             
02104 
02105 
02106 
02107 
02108             EngineTick missedTicks = 
02109                 _currentEngineTick + 1 - nextInputDeadline ;
02110 
02111             if ( missedTicks > inputToleranceTick || inputPollingCompensated )
02112             {
02113             
02114                 
02115 
02116 
02117 
02118 
02119 
02120 
02121 
02122                  
02123                 
02124                 delayBucket += static_cast<Delay>( 
02125                     Ceylan::Maths::Sqrt( 2.0f * missedTicks ) ) ;
02126             
02127 #if OSDL_DEBUG_SCHEDULER
02128                 missedInputPollings.push_back( _currentInputTick ) ;
02129 #endif // OSDL_DEBUG_SCHEDULER
02130             
02131                 onInputSkipped( _currentInputTick ) ;
02132             
02133             }
02134             else
02135             {
02136             
02137                 
02138                 _recoveredInputPollingTicks++ ;
02139                 
02140                 
02141                 missedTicks-- ;
02142 
02143                 OSDL_SCHEDULE_LOG( "@@@@@ Input deadline #"
02144                     + Ceylan::toString( _currentInputTick ) 
02145                     + " recovered from " + Ceylan::toString( missedTicks )
02146                     + " engine ticks delay (" 
02147                     + Ceylan::toString( missedTicks * _engineTickDuration )  
02148                     + " microseconds)." ) ;
02149                 
02150                 
02151                 delayBucket += 5 ;
02152 
02153 #if OSDL_DEBUG_SCHEDULER
02154                 recoveredInputPollings.push_back( _currentInputTick ) ;
02155 #endif // OSDL_DEBUG_SCHEDULER
02156 
02157                 scheduleInput( _currentInputTick ) ;
02158             
02159                 inputPollingCompensated = true ;
02160             
02161             }   
02162 
02163             _currentInputTick++ ;
02164             
02165             nextInputDeadline += _inputPeriod ;
02166             
02167             _currentEngineTick = computeEngineTickFromCurrentTime() ;
02168                         
02169         }
02170                 
02171         if ( maxDelayBucket < delayBucket )
02172             maxDelayBucket = delayBucket ;
02173 
02174 
02175         
02176         if ( delayBucket > bucketFillThreshold )
02177             onScheduleFailure( delayBucket ) ;
02178 
02179         
02180 
02181 
02182 
02183 
02184         nextDeadline = Ceylan::Maths::Min( nextSimulationDeadline,
02185             nextRenderingDeadline, nextInputDeadline ) ;
02186 
02187         _currentEngineTick = computeEngineTickFromCurrentTime() ;
02188 
02189         if ( nextDeadline < _currentEngineTick )
02190         {
02191         
02192             string message = "We are at engine tick #" 
02193                 + Ceylan::toString( _currentEngineTick ) 
02194                 + ", already late for next deadline, which is at "
02195                 + Ceylan::toString( nextDeadline ) + "." ;
02196             
02197             OSDL_SCHEDULE_LOG( message ) ;
02198             LogPlug::warning( message ) ;
02199             
02200             
02201             continue ;
02202         }
02203         else if ( nextDeadline <= _currentEngineTick + 1 )
02204         {
02205             
02206             
02207 
02208 
02209 
02210 
02211 
02212             OSDL_SCHEDULE_LOG( 
02213                 "No jump could be performed, just continuing." ) ;
02214             
02215         }
02216         else
02217         {
02218         
02219             
02220         
02221             
02222 
02223 
02224 
02225             EngineTick jumpLength = nextDeadline - _currentEngineTick - 1 ;
02226 
02227             OSDL_SCHEDULE_LOG( "Next deadline is " 
02228                 + Ceylan::toString( jumpLength + 1 ) 
02229                 + " engine tick(s) away, preparing jump." ) ;
02230 
02231 
02232             
02233             while ( jumpLength > 0 )
02234             {
02235         
02236                 delayBucket = static_cast<Delay>( 
02237                     delayBucket * bucketLeakingFactor ) ;
02238                 delayCumulativeBucket += delayBucket ;
02239                 jumpLength-- ;
02240             
02241             } ;
02242 
02243         }
02244         
02245         _currentEngineTick = computeEngineTickFromCurrentTime() ;
02246 
02247         OSDL_SCHEDULE_LOG( "We are now at engine tick " 
02248             + Ceylan::toString( _currentEngineTick ) 
02249             + ", just before attempting idle call." ) ;
02250         
02251         
02252 
02253 
02254 
02255 
02256 
02257                 
02258         Microsecond lastIdleDuration ;
02259 
02260         
02261         while ( _currentEngineTick + forecastIdleCallbackTickCount
02262             < nextDeadline )
02263         {
02264 
02265             OSDL_SCHEDULE_LOG( "baseIdleCallbackTickCount = "
02266                 + Ceylan::toString( baseIdleCallbackTickCount )
02267                 + " engine ticks" ) ;
02268                 
02269             OSDL_SCHEDULE_LOG( "forecastIdleCallbackTickCount = "
02270                 + Ceylan::toString( forecastIdleCallbackTickCount )
02271                 + " engine ticks" ) ;
02272                 
02273             OSDL_SCHEDULE_LOG( "lastIdleTickCount = "
02274                 + Ceylan::toString( lastIdleTickCount )
02275                 + " engine ticks" ) ;
02276                 
02277             OSDL_SCHEDULE_LOG( "idleCallbackMaxTickCount = "
02278                 + Ceylan::toString( idleCallbackMaxTickCount )
02279                 + " engine ticks" ) ;
02280                 
02281             
02282             forecastIdleCallbackTickCount = static_cast<Microsecond>(
02283                 ( baseIdleCallbackTickCount + 3 * forecastIdleCallbackTickCount
02284                     + lastIdleTickCount + idleCallbackMaxTickCount ) / 6.0f ) ;
02285                             
02286             OSDL_SCHEDULE_LOG( "Current forecasted idle callback duration is "
02287                 + Ceylan::toString( forecastIdleCallbackTickCount 
02288                     * _engineTickDuration ) + " microseconds, i.e. " 
02289                 + Ceylan::toString( forecastIdleCallbackTickCount ) 
02290                 + " engine ticks." ) ;
02291         
02292 #if OSDL_DEBUG_SCHEDULER
02293             forecastIdleCallbackDurationList.push_back(
02294                 forecastIdleCallbackTickCount * _engineTickDuration ) ;
02295 #endif // OSDL_DEBUG_SCHEDULER
02296                     
02297             getPreciseTime( idleStartingSecond, idleStartingMicrosecond ) ;
02298                     
02299             
02300 
02301 
02302 
02303 
02304             onIdle() ;
02305 
02306             getPreciseTime( idleStoppingSecond, idleStoppingMicrosecond ) ;
02307             
02308             lastIdleDuration = getDurationBetween( 
02309                 idleStartingSecond, idleStartingMicrosecond,
02310                 idleStoppingSecond, idleStoppingMicrosecond ) ;
02311 
02312 #if OSDL_DEBUG_SCHEDULER
02313             actualIdleCallbackDurationList.push_back( lastIdleDuration ) ;
02314 #endif // OSDL_DEBUG_SCHEDULER
02315                         
02316             lastIdleTickCount = lastIdleDuration / _engineTickDuration ;
02317                 
02318             OSDL_SCHEDULE_LOG( Ceylan::toString( lastIdleDuration ) 
02319                 + " microseconds were spent in the idle call, "
02320                 "corresponding to " + Ceylan::toString( lastIdleTickCount ) 
02321                 + " engine ticks." ) ;
02322             
02323             
02324             
02325             
02326             _idleCallbackMinMeasuredDuration = Ceylan::Maths::Min(
02327                 _idleCallbackMinMeasuredDuration, lastIdleDuration ) ;
02328                     
02329             _idleCallbackMaxMeasuredDuration = Ceylan::Maths::Max(
02330                 _idleCallbackMaxMeasuredDuration, lastIdleDuration ) ;
02331                     
02332             _currentEngineTick = computeEngineTickFromCurrentTime() ;
02333 
02334             OSDL_SCHEDULE_LOG( "We are now at engine tick " 
02335                 + Ceylan::toString( _currentEngineTick ) ) ;
02336             
02337         }   
02338         
02339         OSDL_SCHEDULE_LOG( "We are now at engine tick " 
02340             + Ceylan::toString( _currentEngineTick ) 
02341             + ", just after having attempted idle calls." ) ;
02342         
02343         
02344         
02345         while ( _currentEngineTick < nextDeadline )
02346         {
02347         
02348             OSDL_SCHEDULE_LOG( "Busy waiting at engine tick "
02349                 + Ceylan::toString( _currentEngineTick ) ) ;
02350             
02351             _currentEngineTick = computeEngineTickFromCurrentTime() ;
02352         
02353         }
02354         
02355         
02356         
02357 
02358 
02359 
02360 
02361         
02362         
02363     } 
02364 
02365 
02366     Second scheduleStoppingSecond ;
02367     Microsecond scheduleStoppingMicrosecond ;
02368     
02369     getPreciseTime( scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
02370     
02371     
02372     Ceylan::Float64 totalRuntimeFactor ;
02373     
02374     
02375     if ( scheduleStoppingSecond - _scheduleStartingSecond <
02376             MaximumDurationWithMicrosecondAccuracy )
02377     {   
02378          
02379         totalRuntimeFactor = 1E6 / getDurationBetween( 
02380             _scheduleStartingSecond, _scheduleStartingMicrosecond,
02381             scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
02382             
02383     }
02384     else
02385     {
02386     
02387         
02388         totalRuntimeFactor =  1.0f / 
02389             ( scheduleStoppingSecond - _scheduleStartingSecond ) ;
02390         
02391     }
02392     
02393     
02394     string table = 
02395         "<table border=1>"
02396         "   <tr>"
02397         "       <th>Tick types</th>"
02398         "       <th>Requested frequency</th>" 
02399         "       <th>Agreed frequency</th>" 
02400         "       <th>Measured frequency</th>" 
02401         "       <th>Tick duration (microsec)</th>" 
02402         "       <th>Tick duration (engine ticks)</th>" 
02403         "       <th>Stopped at tick</th>" 
02404         "       <th>Recovered count</th>"
02405         "       <th>Recovered percentage</th>"
02406         "       <th>Missed count</th>"
02407         "       <th>Missed percentage</th>"
02408         "   </tr>" ;
02409     
02410     
02411     Ceylan::Uint8 precision = 2  ;
02412     
02413     
02414     table += 
02415         "   <tr>"
02416         "       <td>Engine tick</td>"
02417         "       <td>" 
02418         + Ceylan::toString( 1E6 / DefaultEngineTickDuration, precision ) 
02419         + " Hz</td>"
02420         "       <td>" 
02421         + Ceylan::toString( 1E6 / DefaultEngineTickDuration, precision ) 
02422         + " Hz</td>"
02423         "       <td>" 
02424         + Ceylan::toString( _currentEngineTick * totalRuntimeFactor,
02425             precision )
02426         + " Hz</td>"
02427         "       <td>" + Ceylan::toString( _engineTickDuration ) + "</td>"
02428         "       <td>1</td>"
02429         "       <td>" + Ceylan::toString( _currentEngineTick ) + "</td>"
02430         "       <td>N/A</td>"       
02431         "       <td>N/A</td>"       
02432         "       <td>N/A</td>"       
02433         "       <td>N/A</td>"       
02434         "   </tr>" ;
02435         
02436         
02437     
02438     table += 
02439         "   <tr>"
02440         "       <td>Simulation tick</td>"
02441         "       <td>" 
02442         + Ceylan::toString( _desiredSimulationFrequency ) 
02443         + " Hz</td>"
02444         "       <td>" 
02445         + Ceylan::toString( 1E6 / ( _simulationPeriod * _engineTickDuration ), 
02446             precision ) + " Hz</td>"
02447         "       <td>"
02448         + Ceylan::toString( 
02449             ( _currentSimulationTick - _missedSimulationTicks ) *
02450                 totalRuntimeFactor, precision ) + " Hz</td>"
02451         "       <td>" + Ceylan::toString( 
02452             _simulationPeriod * _engineTickDuration ) + "</td>"
02453         "       <td>" + Ceylan::toString( _simulationPeriod ) + "</td>"
02454         "       <td>" + Ceylan::toString( _currentSimulationTick ) + "</td>"
02455         "       <td>" + Ceylan::toString( _recoveredSimulationTicks ) + "</td>" 
02456         "       <td>" + Ceylan::toString( 
02457             100.0f * _recoveredSimulationTicks / _currentSimulationTick, 
02458             precision ) 
02459         + "%</td>"  
02460         "       <td>" + Ceylan::toString( _missedSimulationTicks ) + "</td>"    
02461         "       <td>" + Ceylan::toString( 
02462             100.0f * _missedSimulationTicks / _currentSimulationTick, 
02463             precision ) 
02464         + "%</td>"  
02465         "   </tr>" ;
02466         
02467         
02468     
02469     table += 
02470         "   <tr>"
02471         "       <td>Rendering tick</td>"
02472         "       <td>" 
02473         + Ceylan::toString( _desiredRenderingFrequency ) 
02474         + " Hz</td>"
02475         "       <td>" 
02476         + Ceylan::toString( 1E6 / ( _renderingPeriod * _engineTickDuration ), 
02477             precision ) + " Hz</td>"
02478         "       <td>"
02479         + Ceylan::toString( 
02480             ( _currentRenderingTick - _missedRenderingTicks ) * 
02481                 totalRuntimeFactor, precision ) + " Hz</td>"
02482         "       <td>" + Ceylan::toString( 
02483             _renderingPeriod * _engineTickDuration ) + "</td>"
02484         "       <td>" + Ceylan::toString( _renderingPeriod ) + "</td>"
02485         "       <td>" + Ceylan::toString( _currentRenderingTick ) + "</td>"
02486         "       <td>" + Ceylan::toString( _recoveredRenderingTicks ) + "</td>"  
02487         "       <td>" + Ceylan::toString( 
02488             100.0f * _recoveredRenderingTicks / _currentRenderingTick, 
02489                 precision ) 
02490         + "%</td>"  
02491         "       <td>" + Ceylan::toString( _missedRenderingTicks ) + "</td>" 
02492         "       <td>" + Ceylan::toString( 
02493             100.0f * _missedRenderingTicks / _currentRenderingTick, precision ) 
02494         + "%</td>"  
02495         "   </tr>" ;
02496         
02497     
02498     table += 
02499         "   <tr>"
02500         "       <td>Input polling tick</td>"
02501         "       <td>" 
02502         + Ceylan::toString( _desiredInputFrequency ) 
02503         + " Hz</td>"
02504         "       <td>" 
02505         + Ceylan::toString( 1E6 / ( _inputPeriod * _engineTickDuration ), 
02506             precision ) + " Hz</td>"
02507         "       <td>"
02508         + Ceylan::toString( 
02509             ( _currentInputTick - _missedInputPollingTicks ) * 
02510                 totalRuntimeFactor, precision ) + " Hz</td>"
02511         "       <td>" + Ceylan::toString( 
02512             _inputPeriod * _engineTickDuration ) + "</td>"
02513         "       <td>" + Ceylan::toString( _inputPeriod ) + "</td>"
02514         "       <td>" + Ceylan::toString( _currentInputTick ) + "</td>"
02515         "       <td>" + Ceylan::toString( _recoveredInputPollingTicks ) 
02516         + "</td>"   
02517         "       <td>" + Ceylan::toString( 
02518             100.0f * _recoveredInputPollingTicks / _currentInputTick, 
02519                 precision ) 
02520         + "%</td>"  
02521         "       <td>" + Ceylan::toString( _missedInputPollingTicks ) + "</td>"  
02522         "       <td>" + Ceylan::toString( 
02523             100.0f * _missedInputPollingTicks / _currentInputTick, precision ) 
02524         + "%</td>"  
02525         "   </tr>" ;
02526         
02527     table += "</table>" ;   
02528     
02529     if ( Ceylan::TextDisplayable::GetOutputFormat() ==
02530             Ceylan::TextDisplayable::html )
02531         send( table ) ;
02532     
02533     list<string> summary ;
02534     
02535     string durationComment = "The scheduler ran for " 
02536         + Ceylan::Timestamp::DescribeDuration( 
02537             scheduleStoppingSecond - _scheduleStartingSecond ) ;
02538             
02539     
02540     if ( scheduleStoppingSecond - _scheduleStartingSecond <
02541             MaximumDurationWithMicrosecondAccuracy )            
02542         durationComment += ", more precisely " 
02543             + Ceylan::toString( getDurationBetween(
02544                 _scheduleStartingSecond, _scheduleStartingMicrosecond,
02545                 scheduleStoppingSecond, scheduleStoppingMicrosecond ) )
02546             + " microseconds." ;
02547     else
02548         durationComment += "." ;
02549             
02550     summary.push_back( durationComment ) ;
02551     
02552     summary.push_back( Ceylan::toString( _idleCallsCount ) 
02553         + " idle calls have been made." ) ;
02554 
02555     summary.push_back( "Each idle call was expected to last for "
02556         + Ceylan::toString( _idleCallbackMaxDuration ) + " microseconds, i.e. "
02557         + Ceylan::toString( baseIdleCallbackTickCount ) + " engine ticks." ) ;
02558 
02559     summary.push_back( "Average bucket level has been " 
02560         + Ceylan::toString( 
02561             ( 1.0f * delayCumulativeBucket ) / _currentEngineTick,
02562              2 ) 
02563         + ", maximum bucket level has been "
02564         + Ceylan::toString( maxDelayBucket ) 
02565         + ", bucket fill threshold is " 
02566         + Ceylan::toString( bucketFillThreshold )
02567         + ", this threshold has been reached "
02568         + Ceylan::toString( _scheduleFailureCount )
02569         + " times, shutdown bucket level is "
02570         + Ceylan::toString( ShutdownBucketLevel) + "." ) ;
02571 
02572 #if OSDL_DEBUG_SCHEDULER
02573 
02574     send( "Displaying list of successive forecast idle callback durations: "
02575         + Ceylan::toString( forecastIdleCallbackDurationList ) ) ;
02576 
02577     send( "Displaying list of successive actual idle callback durations: "
02578         + Ceylan::toString( actualIdleCallbackDurationList ) ) ;
02579 
02580     const string logFilename = "idle-calls.dat" ;
02581 
02582     Ceylan::System::File * idleComparisonFile = & File::Create( logFilename ) ;
02583     
02584     idleComparisonFile->write( 
02585             "# This file records the forecasted and measured durations\n"
02586             "# of idle calls.\n"
02587             "# One may use gnuplot to analyze the result,\n"
02588             "# see test/engine/testOSDLScheduler.cc.\n\n"   ) ;
02589             
02590     LogPlug::trace( "Recording forecasted and actual durations in the '"
02591             + logFilename + "' file." ) ;
02592 
02593     Ceylan::Uint32 count = 0 ;
02594     Ceylan::Uint32 finalCount = forecastIdleCallbackDurationList.size() ;
02595     
02596     while ( count != finalCount )
02597     {
02598     
02599         idleComparisonFile->write( Ceylan::toString( count ) + " \t " 
02600             + Ceylan::toString( forecastIdleCallbackDurationList.front() ) 
02601             + " \t " 
02602             + Ceylan::toString( actualIdleCallbackDurationList.front() )
02603             + " \n" ) ;
02604 
02605         forecastIdleCallbackDurationList.pop_front() ;
02606         actualIdleCallbackDurationList.pop_front() ;
02607         
02608         count++ ;
02609             
02610     }
02611 
02612     idleComparisonFile->close() ;
02613     delete idleComparisonFile ;
02614             
02615 #endif // OSDL_DEBUG_SCHEDULER
02616 
02617     
02618     send( "Scheduler stopping, run summary is: " 
02619         + Ceylan::formatStringList( summary ) ) ;
02620     
02621     send( "Full scheduler infos: " + toString( Ceylan::high ) ) ;   
02622 
02623     _scheduleStartingSecond = 0 ;
02624     _scheduleStartingMicrosecond = 0 ;
02625     
02626             
02627 #if OSDL_DEBUG_SCHEDULER
02628     
02629     
02630 
02631 
02632 
02633 
02634 
02635     bool beVerbose = true ;
02636     bool beVeryVerbose = true ;
02637     
02638     
02639     
02640     
02641     
02642     SimulationTick totalSimulationTicks = static_cast<SimulationTick>( 
02643         metSimulations.size() + recoveredSimulations.size() 
02644         + missedSimulations.size() ) ;
02645         
02646     send( "Total simulation ticks: " 
02647         + Ceylan::toString( 
02648             static_cast<Ceylan::Uint32>( totalSimulationTicks ) ) 
02649         + "." ) ;
02650 
02651     send( "Directly met simulation ticks: " 
02652         + Ceylan::toString( 
02653             static_cast<Ceylan::Uint32>( metSimulations.size() ) )
02654         + " (" + Ceylan::toString( 100.0f * metSimulations.size() 
02655             / totalSimulationTicks,  2 ) + "%)." ) ;
02656                         
02657     send( "Recovered (indirectly met) simulation ticks: " 
02658         + Ceylan::toString( 
02659             static_cast<Ceylan::Uint32>( recoveredSimulations.size() ) )
02660         + " (" + Ceylan::toString( 100.0f * recoveredSimulations.size() 
02661             / totalSimulationTicks,  2 ) + "%)." ) ;
02662 
02663     if ( recoveredSimulations.size() != _recoveredSimulationTicks )
02664         LogPlug::error( "Inconsistency in recovered simulation count." ) ;
02665 
02666                 
02667     send( "Missed simulation ticks: " 
02668         + Ceylan::toString( 
02669             static_cast<Ceylan::Uint32>( missedSimulations.size() ) )
02670         + " (" + Ceylan::toString( 100.0f * missedSimulations.size() 
02671             / totalSimulationTicks,  2 ) + "%)." ) ;
02672     
02673     if ( missedSimulations.size() != _missedSimulationTicks )
02674         LogPlug::error( "Inconsistency in missed simulation count." ) ;
02675 
02676     if ( _currentSimulationTick - _recoveredSimulationTicks 
02677             - _missedSimulationTicks != metSimulations.size() )
02678         LogPlug::error( "Inconsistency in overall simulation count." ) ;
02679             
02680              
02681     string res ;
02682     
02683 
02684     if ( beVerbose )
02685     {
02686     
02687         if ( beVeryVerbose )
02688         {
02689         
02690             for ( list<SimulationTick>::const_iterator it 
02691                     = metSimulations.begin(); it != metSimulations.end(); it++ )
02692                 res +=  Ceylan::toString( *it ) + " - " ;
02693          
02694             send( "Met simulation ticks: " + res ) ;
02695             res.clear() ;
02696     
02697         }
02698         
02699         
02700         for ( list<SimulationTick>::const_iterator it 
02701                 = recoveredSimulations.begin(); 
02702                     it != recoveredSimulations.end(); it++ )
02703             res +=  Ceylan::toString( *it ) + " - " ;
02704 
02705         send( "Recovered simulation ticks: " + res ) ;
02706         res.clear() ;
02707         
02708         for ( list<SimulationTick>::const_iterator it =
02709                 missedSimulations.begin(); it != missedSimulations.end(); it++ )
02710             res += Ceylan::toString( *it ) + " - " ;
02711 
02712         if ( res.empty() )
02713             send( "No simulation tick was missed." ) ;
02714         else    
02715             send( "Missed simulation ticks: " + res ) ;
02716             
02717         res.clear() ;
02718         
02719     }
02720     
02721         
02722     
02723 
02724 
02725 
02726 
02727     SimulationTick newSimulationTick ;
02728     
02729     bool * simulationTicks = new bool[ _currentSimulationTick ] ;
02730     
02731     for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
02732         simulationTicks[i] = false ;
02733         
02734     for ( list<SimulationTick>::const_iterator it = metSimulations.begin(); 
02735         it != metSimulations.end(); it++ )
02736     {
02737     
02738         newSimulationTick = (*it) ;
02739         
02740         if ( simulationTicks[ newSimulationTick ] == false )
02741             simulationTicks[ newSimulationTick ] = true ;
02742         else
02743             LogPlug::error( "Met simulation tick #" 
02744                 + Ceylan::toString( newSimulationTick ) 
02745                 + " should not have been scheduled more than once." ) ; 
02746                         
02747     }
02748     
02749     
02750     for ( list<SimulationTick>::const_iterator it =
02751         recoveredSimulations.begin(); it != recoveredSimulations.end(); it++ )
02752     {
02753     
02754         newSimulationTick = (*it) ;
02755         
02756         if ( simulationTicks[ newSimulationTick ] == false )
02757             simulationTicks[ newSimulationTick ] = true ;
02758         else
02759             LogPlug::error( "Recovered simulation tick #" 
02760                 + Ceylan::toString( newSimulationTick ) 
02761                 + " should not have been scheduled more than once." ) ; 
02762                         
02763     }
02764     
02765     
02766     for ( list<SimulationTick>::const_iterator it = missedSimulations.begin(); 
02767         it != missedSimulations.end(); it++ )
02768     {
02769     
02770         newSimulationTick = (*it) ;
02771         
02772         if ( simulationTicks[ newSimulationTick ] == false )
02773             simulationTicks[ newSimulationTick ] = true ;
02774         else
02775             LogPlug::error( "Missed simulation tick #" 
02776                 + Ceylan::toString( newSimulationTick ) 
02777                 + " should not have been skipped, "
02778                 "since had already been taken into account." ) ;
02779                             
02780     }
02781     
02782     for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
02783         if ( simulationTicks[ i ] == false )
02784             LogPlug::error( "Simulation tick #" + Ceylan::toString( i ) 
02785                 + " has never been scheduled." ) ;  
02786                 
02787     delete simulationTicks ;
02788     
02789 
02790 
02791     
02792 
02793     RenderingTick totalRenderingTicks = static_cast<RenderingTick>( 
02794         metRenderings.size() + recoveredRenderings.size() 
02795         + missedRenderings.size() ) ;
02796 
02797     send( "Total rendering ticks: " 
02798         + Ceylan::toString( totalRenderingTicks ) + "." ) ;
02799         
02800     send( "Directly met rendering ticks: " 
02801         + Ceylan::toString( 
02802             static_cast<Ceylan::Uint32>( metRenderings.size() ) )
02803         + " (" + Ceylan::toString( 100.0f * metRenderings.size() 
02804             / totalRenderingTicks,  2 ) + "%)." ) ;
02805                 
02806     send( "Recovered (indirectly met) rendering ticks: " 
02807         + Ceylan::toString( 
02808             static_cast<Ceylan::Uint32>( recoveredRenderings.size() ) ) 
02809         + " (" + Ceylan::toString( 100.0f * recoveredRenderings.size() 
02810             / totalRenderingTicks,  2 ) + "%)." ) ;
02811 
02812     if ( recoveredRenderings.size() != _recoveredRenderingTicks )
02813         LogPlug::error( "Inconsistency in recovered rendering count." ) ;
02814 
02815                 
02816     send( "Missed rendering ticks: " 
02817         + Ceylan::toString( 
02818             static_cast<Ceylan::Uint32>( missedRenderings.size() ) ) 
02819         + " (" + Ceylan::toString( 100.0f * missedRenderings.size() 
02820             / totalRenderingTicks,  2 ) + "%)." ) ;
02821 
02822     if ( missedRenderings.size() != _missedRenderingTicks )
02823         LogPlug::error( "Inconsistency in missed rendering count." ) ;
02824 
02825     if ( _currentRenderingTick - _recoveredRenderingTicks 
02826             - _missedRenderingTicks != metRenderings.size() )
02827         LogPlug::error( "Inconsistency in overall rendering count." ) ;
02828                 
02829         
02830                 
02831     if ( beVerbose )
02832     {
02833     
02834         if ( beVeryVerbose )
02835         {
02836         
02837             for ( list<RenderingTick>::const_iterator it 
02838                     = metRenderings.begin(); it != metRenderings.end(); it++ )
02839                 res +=  Ceylan::toString( *it ) + " - " ;
02840          
02841             send( "Met rendering ticks: " + res ) ;
02842             res.clear() ;
02843     
02844         }
02845         
02846         for ( list<RenderingTick>::const_iterator it 
02847                 = recoveredRenderings.begin(); 
02848                 it != recoveredRenderings.end(); it++ )
02849             res +=  Ceylan::toString( *it ) + " - " ;
02850 
02851         send( "Recovered rendering ticks: " + res ) ;
02852         res.clear() ;
02853 
02854         for ( list<RenderingTick>::const_iterator it 
02855                 = missedRenderings.begin(); it != missedRenderings.end(); it++ )
02856             res +=  Ceylan::toString( *it ) + " - " ;
02857 
02858         if ( res.empty() )
02859             send( "No rendering tick was missed." ) ;
02860         else    
02861             send( "Missed rendering ticks: " + res ) ;
02862             
02863         res.clear() ;
02864 
02865     }
02866     
02867                 
02868     
02869 
02870 
02871 
02872 
02873     
02874     RenderingTick newRenderingTick ;
02875     
02876     bool * renderingTicks = new bool[ _currentRenderingTick ] ;
02877     
02878     for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
02879         renderingTicks[i] = false ;
02880         
02881     for ( list<RenderingTick>::const_iterator it = metRenderings.begin(); 
02882         it != metRenderings.end(); it++ )
02883     {
02884     
02885         newRenderingTick = (*it) ;
02886         if ( renderingTicks[ newRenderingTick ] == false )
02887             renderingTicks[ newRenderingTick ] = true ;
02888         else
02889             LogPlug::error( "Met rendering tick #" 
02890                 + Ceylan::toString( newRenderingTick ) 
02891                 + " should not have been scheduled more than once." ) ;     
02892                 
02893     }
02894     
02895     for ( list<RenderingTick>::const_iterator it = 
02896         recoveredRenderings.begin(); it != recoveredRenderings.end(); it++ )
02897     {
02898     
02899         newRenderingTick = (*it) ;
02900         if ( renderingTicks[ newRenderingTick ] == false )
02901             renderingTicks[ newRenderingTick ] = true ;
02902         else
02903             LogPlug::error( "Recovered rendering tick #" 
02904                 + Ceylan::toString( newRenderingTick ) 
02905                 + " should not have been scheduled more than once." ) ;     
02906                 
02907     }
02908     
02909     
02910     for ( list<RenderingTick>::const_iterator it = missedRenderings.begin(); 
02911         it != missedRenderings.end(); it++ )
02912     {
02913         newRenderingTick = (*it) ;
02914         if ( renderingTicks[ newRenderingTick ] == false )
02915             renderingTicks[ newRenderingTick ] = true ;
02916         else
02917             LogPlug::error( "Missed rendering tick #" 
02918                 + Ceylan::toString( newRenderingTick ) 
02919                 + " should not have been been skipped, "
02920                 "since had already been taken into account." ) ;
02921                             
02922     }
02923     
02924     for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
02925         if ( renderingTicks[ i ] == false )
02926             LogPlug::error( "Rendering tick #" + Ceylan::toString( i ) 
02927                 + " has never been scheduled." ) ;  
02928 
02929     delete renderingTicks ;
02930 
02931 
02932 
02933     
02934 
02935 
02936     InputTick totalInputTicks = static_cast<InputTick>( 
02937         metInputPollings.size() + recoveredInputPollings.size() 
02938         + missedInputPollings.size() ) ;
02939 
02940     send( "Total input ticks: " 
02941         + Ceylan::toString( totalInputTicks ) + "." ) ;
02942         
02943     send( "Directly met input ticks: " 
02944         + Ceylan::toString( 
02945             static_cast<Ceylan::Uint32>( metInputPollings.size() ) ) 
02946         + " (" + Ceylan::toString( 100.0f * metInputPollings.size() 
02947             / totalInputTicks,  2 ) + "%)." ) ;
02948                 
02949     send( "Recovered (indirectly met) input ticks: " 
02950         + Ceylan::toString( 
02951             static_cast<Ceylan::Uint32>( recoveredInputPollings.size() ) ) 
02952         + " (" + Ceylan::toString( 100.0f * recoveredInputPollings.size() 
02953             / totalInputTicks,  2 ) + "%)." ) ;
02954 
02955     if ( recoveredInputPollings.size() != _recoveredInputPollingTicks )
02956         LogPlug::error( "Inconsistency in recovered input polling count." ) ;
02957             
02958                 
02959     send( "Missed input ticks: " 
02960         + Ceylan::toString( 
02961             static_cast<Ceylan::Uint32>( missedInputPollings.size() ) ) 
02962         + " (" + Ceylan::toString( 100.0f * missedInputPollings.size() 
02963             / totalInputTicks,  2 ) + "%)." ) ;
02964                 
02965     if ( missedInputPollings.size() != _missedInputPollingTicks )
02966         LogPlug::error( "Inconsistency in missed input polling count." ) ;
02967 
02968     if ( _currentInputTick - _recoveredInputPollingTicks 
02969             - _missedInputPollingTicks != metInputPollings.size() )
02970         LogPlug::error( "Inconsistency in overall input polling count." ) ;
02971         
02972                 
02973     if ( beVerbose )
02974     {
02975     
02976         if ( beVeryVerbose )
02977         {
02978         
02979             for ( list<InputTick>::const_iterator it 
02980                     = metInputPollings.begin(); 
02981                     it != metInputPollings.end(); it++ )
02982                 res +=  Ceylan::toString( *it ) + " - " ;
02983          
02984             send( "Met input ticks: " + res ) ;
02985             res.clear() ;
02986     
02987         }
02988         
02989         for ( list<InputTick>::const_iterator it 
02990                 = recoveredInputPollings.begin(); 
02991                 it != recoveredInputPollings.end(); it++ )
02992             res +=  Ceylan::toString( *it ) + " - " ;
02993 
02994         send( "Recovered input ticks: " + res ) ;
02995         res.clear() ;
02996 
02997         for ( list<InputTick>::const_iterator it 
02998                 = missedInputPollings.begin(); 
02999                 it != missedInputPollings.end(); it++ )
03000             res +=  Ceylan::toString( *it ) + " - " ;
03001 
03002         if ( res.empty() )
03003             send( "No input tick was missed." ) ;
03004         else    
03005             send( "Missed input ticks: " + res ) ;
03006 
03007         res.clear() ;
03008 
03009     }
03010                 
03011                 
03012     
03013 
03014 
03015 
03016 
03017 
03018     
03019     InputTick newInputTick ;
03020     
03021     bool * inputTicks = new bool[ _currentInputTick ] ;
03022     
03023     for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
03024         inputTicks[i] = false ;
03025         
03026     for ( list<InputTick>::const_iterator it = metInputPollings.begin(); 
03027         it != metInputPollings.end(); it++ )
03028     {
03029     
03030         newInputTick = (*it) ;
03031         if ( inputTicks[ newInputTick ] == false )
03032             inputTicks[ newInputTick ] = true ;
03033         else
03034             LogPlug::error( "Met input tick #" 
03035                 + Ceylan::toString( newInputTick ) 
03036                 + " should not have been scheduled more than once." ) ;
03037                 
03038     }
03039     
03040     for ( list<InputTick>::const_iterator it = recoveredInputPollings.begin(); 
03041         it != recoveredInputPollings.end(); it++ )
03042     {
03043     
03044         newInputTick = (*it) ;
03045         if ( inputTicks[ newInputTick ] == false )
03046             inputTicks[ newInputTick ] = true ;
03047         else
03048             LogPlug::error( "Recovered input tick #" 
03049                 + Ceylan::toString( newInputTick ) 
03050                 + " should not have been scheduled more than once." ) ;
03051                 
03052     }
03053     
03054     
03055     for ( list<InputTick>::const_iterator it = missedInputPollings.begin(); 
03056         it != missedInputPollings.end(); it++ )
03057     {
03058         newInputTick = (*it) ;
03059         if ( inputTicks[ newInputTick ] == false )
03060             inputTicks[ newInputTick ] = true ;
03061         else
03062             LogPlug::error( "Missed input tick #" 
03063                 + Ceylan::toString( newInputTick ) 
03064                 + " should not have been been skipped, "
03065                 "since had already been taken into account." ) ;
03066                         
03067     }
03068     
03069     for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
03070         if ( inputTicks[ i ] == false )
03071             LogPlug::error( "Input tick #" + Ceylan::toString( i ) 
03072                 + " has never been scheduled." ) ;  
03073 
03074     delete inputTicks ;
03075     
03076 #endif // OSDL_DEBUG_SCHEDULER
03077     
03078     _isRunning = false ;
03079 
03080     if ( _stopCallback != 0 )
03081     {
03082     
03083         
03084         
03085         
03086         (*_stopCallback)( _stopCallbackData ) ;
03087         
03088     }
03089     else
03090     {
03091     
03092         
03093 
03094 
03095 
03096 
03097         
03098     }
03099             
03100 }
03101 
03102     
03103     
03104     
03105     
03106 
03107 void Scheduler::scheduleNoDeadline( bool pollInputs ) 
03108 {
03109     
03110     
03111     
03112     _isRunning= true ;
03113     _stopRequested = false ;    
03114     
03115 #if OSDL_DEBUG_SCHEDULER
03116     
03117     
03118 
03119 
03120 
03121 
03122 
03123      
03124     list<SimulationTick> metSimulations ;
03125     list<RenderingTick>  metRenderings ;    
03126     list<InputTick>      metInputPollings ; 
03127     
03128 #endif // OSDL_DEBUG_SCHEDULER
03129 
03130     
03131     
03132     getPreciseTime( _scheduleStartingSecond, _scheduleStartingMicrosecond ) ;
03133          
03134     
03135     _currentEngineTick     = 0 ;
03136         
03137     _currentSimulationTick = 0 ;    
03138     _currentRenderingTick  = 0 ;
03139     _currentInputTick      = 0 ;
03140     
03141 
03142     
03143 
03144 
03145 
03146 
03147 
03148     setInitialBirthTicks( _currentSimulationTick ) ;    
03149 
03150     OSDL_SCHEDULE_LOG( "Simulation period: " 
03151         + Ceylan::toString( _simulationPeriod ) + " engine ticks" ) ;
03152         
03153     OSDL_SCHEDULE_LOG( "Rendering period: " 
03154         + Ceylan::toString( _renderingPeriod ) + " engine ticks" ) ;
03155 
03156     OSDL_SCHEDULE_LOG( "Input period: " 
03157         + Ceylan::toString( _inputPeriod ) + " engine ticks" ) ;
03158     
03159     _currentSimulationTick = _currentEngineTick / _simulationPeriod  ;  
03160     _currentRenderingTick  = _currentEngineTick / _renderingPeriod;
03161     _currentInputTick      = _currentEngineTick / _inputPeriod;
03162     
03163 
03164     OSDL_SCHEDULE_LOG( "Initial engine tick: " 
03165         + Ceylan::toString( _currentEngineTick ) ) ;
03166         
03167     OSDL_SCHEDULE_LOG( "Initial simulation tick: "
03168         + Ceylan::toString( _currentSimulationTick ) ) ;
03169         
03170     OSDL_SCHEDULE_LOG( "Initial rendering tick: "
03171         + Ceylan::toString( _currentRenderingTick ) ) ;
03172         
03173     OSDL_SCHEDULE_LOG( "Initial input tick: "
03174         + Ceylan::toString( _currentInputTick ) ) ;
03175 
03176 
03177 
03178 
03179     
03180     EngineTick nextSimulationDeadline = _currentEngineTick + _simulationPeriod ;
03181     EngineTick nextRenderingDeadline  = _currentEngineTick + _renderingPeriod ;
03182     EngineTick nextInputDeadline      = _currentEngineTick + _inputPeriod ;
03183     
03184     EngineTick countBeforeSleep = 0 ;
03185     
03186     
03187     
03188     
03189     
03190     while ( ! _stopRequested )
03191     {
03192             
03193         OSDL_SCHEDULE_LOG( "[ E: " + Ceylan::toString( _currentEngineTick  )
03194             + " ; S: " + Ceylan::toString( _currentSimulationTick )
03195             + " ; R: " + Ceylan::toString( _currentRenderingTick )
03196             + " ; I: " + Ceylan::toString( _currentInputTick ) + " ]" ) ;
03197 
03198         countBeforeSleep++ ;
03199         
03200         
03201 
03202 
03203 
03204 
03205 
03206 
03207 
03208             
03209                     
03210         
03211         
03212         
03213         
03214         
03215         if ( _currentEngineTick == nextSimulationDeadline )
03216         {
03217         
03218             
03219                 
03220 #if OSDL_DEBUG_SCHEDULER
03221             metSimulations.push_back( _currentSimulationTick ) ;
03222 #endif // OSDL_DEBUG_SCHEDULER
03223             
03224             scheduleSimulation( _currentSimulationTick ) ;
03225             
03226             _currentSimulationTick++ ;
03227             nextSimulationDeadline += _simulationPeriod ;
03228             
03229         }
03230 
03231         if ( _currentEngineTick == nextRenderingDeadline )
03232         {
03233         
03234             
03235                 
03236 #if OSDL_DEBUG_SCHEDULER
03237             metRenderings.push_back( _currentRenderingTick ) ;
03238 #endif // OSDL_DEBUG_SCHEDULER
03239 
03240             scheduleRendering( _currentRenderingTick ) ;
03241 
03242             _currentRenderingTick++ ;
03243             nextRenderingDeadline += _renderingPeriod ;
03244         }
03245         
03246         if ( pollInputs && _currentEngineTick == nextInputDeadline )
03247         {
03248         
03249             
03250                 
03251 #if OSDL_DEBUG_SCHEDULER
03252             metInputPollings.push_back( _currentInputTick ) ;
03253 #endif // OSDL_DEBUG_SCHEDULER
03254 
03255             scheduleInput( _currentInputTick ) ;
03256 
03257             _currentInputTick++ ;
03258             nextInputDeadline += _inputPeriod ;
03259         }
03260 
03261         _currentEngineTick++ ;
03262         
03263         
03264         if ( _subSecondSleepsAvailable && countBeforeSleep == 500 )
03265         {
03266             countBeforeSleep = 0 ;
03267             atomicSleep() ;
03268         }   
03269         
03270         
03271 
03272 
03273 
03274 
03275         
03276     }
03277     
03278     Second scheduleStoppingSecond ;
03279     Microsecond scheduleStoppingMicrosecond ;
03280     
03281     getPreciseTime( scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
03282 
03283 
03284     
03285     Ceylan::Float64 totalRuntimeFactor ;
03286     
03287     
03288     if ( scheduleStoppingSecond - _scheduleStartingSecond <
03289             MaximumDurationWithMicrosecondAccuracy )
03290     {   
03291          
03292         totalRuntimeFactor = 1E6 / getDurationBetween( 
03293             _scheduleStartingSecond, _scheduleStartingMicrosecond,
03294             scheduleStoppingSecond, scheduleStoppingMicrosecond ) ;
03295             
03296     }
03297     else
03298     {
03299     
03300         
03301         totalRuntimeFactor =  1.0f / 
03302             ( scheduleStoppingSecond - _scheduleStartingSecond ) ;
03303         
03304     }
03305 
03306     
03307     send( "Scheduler stopping. Scheduler infos: " 
03308         + toString( Ceylan::high ) ) ;  
03309     
03310 
03311     ostringstream buf ;
03312     
03313     buf.precision( 4 ) ;
03314         
03315     buf << "Actual average engine frequency was "  
03316         << Ceylan::toString( totalRuntimeFactor * _currentEngineTick, 
03317              2 )
03318         << " Hz, average simulation frequency was " 
03319         << Ceylan::toString( totalRuntimeFactor * _currentSimulationTick,
03320              2 )
03321         << " Hz, average rendering frequency was " 
03322         << Ceylan::toString( totalRuntimeFactor * _currentRenderingTick,
03323              2 )
03324         << " Hz, average input frequency was " 
03325         << Ceylan::toString( totalRuntimeFactor * _currentInputTick, 
03326              2 )
03327         << " Hz." ;
03328          
03329     send( buf.str() ) ;
03330             
03331 #if OSDL_DEBUG_SCHEDULER
03332     
03333     
03334     
03335 
03336 
03337 
03338 
03339     
03340     send( "Total simulation ticks: " 
03341         + Ceylan::toString( 
03342             static_cast<Ceylan::Uint32>( metSimulations.size() ) ) 
03343         + "." ) ;
03344             
03345 
03346     
03347 
03348 
03349 
03350     SimulationTick newSimulationTick ;
03351     
03352     bool * simulationTicks = new bool[ _currentSimulationTick ] ;
03353     
03354     for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
03355         simulationTicks[i] = false ;
03356         
03357     for ( list<SimulationTick>::const_iterator it = metSimulations.begin(); 
03358         it != metSimulations.end(); it++ )
03359     {
03360     
03361         newSimulationTick = (*it) ;
03362         if ( simulationTicks[ newSimulationTick ] == false )
03363             simulationTicks[ newSimulationTick ] = true ;
03364         else
03365             LogPlug::error( "Simulation tick #" 
03366                 + Ceylan::toString( newSimulationTick ) 
03367                 + " should not have been scheduled more than once." ) ;     
03368                 
03369     }   
03370     
03371     for ( Events::SimulationTick i = 0; i < _currentSimulationTick; i++ )
03372         if ( simulationTicks[ i ] == false )
03373             LogPlug::error( "Simulation tick #" + Ceylan::toString( i ) 
03374                 + " has never been scheduled." ) ;  
03375 
03376     delete simulationTicks ;
03377                 
03378                 
03379                 
03380                 
03381     send( "Total rendering ticks: " 
03382         + Ceylan::toString( 
03383             static_cast<Ceylan::Uint32>( metRenderings.size() ) ) + "." ) ;
03384                 
03385     
03386 
03387 
03388 
03389     
03390     RenderingTick newRenderingTick ;
03391     
03392     bool * renderingTicks = new bool[ _currentRenderingTick ] ;
03393     
03394     for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
03395         renderingTicks[i] = false ;
03396         
03397     for ( list<RenderingTick>::const_iterator it = metRenderings.begin(); 
03398         it != metRenderings.end(); it++ )
03399     {
03400     
03401         newRenderingTick = (*it) ;
03402         if ( renderingTicks[ newRenderingTick ] == false )
03403             renderingTicks[ newRenderingTick ] = true ;
03404         else
03405             LogPlug::error( "Rendering tick #" 
03406                 + Ceylan::toString( newRenderingTick ) 
03407                 + " should not have been scheduled more than once." ) ;
03408                 
03409     }
03410     
03411     for ( Events::RenderingTick i = 0; i < _currentRenderingTick; i++ )
03412         if ( renderingTicks[ i ] == false )
03413             LogPlug::error( "Rendering tick #" + Ceylan::toString( i ) 
03414                 + " has never been scheduled." ) ;  
03415 
03416     delete renderingTicks ;
03417     
03418     
03419 
03420     send( "Total input polling ticks: " 
03421         + Ceylan::toString( 
03422             static_cast<Ceylan::Uint32>( metInputPollings.size() ) ) 
03423         + "." ) ;
03424 
03425     
03426 
03427 
03428 
03429     if ( pollInputs )
03430     {
03431     
03432         InputTick newInputTick ;
03433     
03434         bool * inputTicks = new bool[ _currentInputTick ] ;
03435         
03436         for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
03437             inputTicks[i] = false ;
03438         
03439         for ( list<InputTick>::const_iterator it = metInputPollings.begin(); 
03440             it != metInputPollings.end(); it++ )
03441         {
03442         
03443             newInputTick = (*it) ;
03444             if ( inputTicks[ newInputTick ] == false )
03445                 inputTicks[ newInputTick ] = true ;
03446             else
03447                 LogPlug::error( "Input tick #" 
03448                     + Ceylan::toString( newInputTick ) 
03449                     + " should not have been scheduled more than once." ) ;
03450                     
03451         }
03452         
03453         for ( Events::InputTick i = 0; i < _currentInputTick; i++ )
03454             if ( inputTicks[ i ] == false )
03455                 LogPlug::error( "Input tick #" + Ceylan::toString( i ) 
03456                     + " has never been scheduled." ) ;  
03457         
03458         delete inputTicks ;
03459                 
03460     }
03461                         
03462 #endif // OSDL_DEBUG_SCHEDULER
03463 
03464     _isRunning = false ;
03465     
03466     if ( _stopCallback != 0 )
03467     {
03468     
03469         
03470         (*_stopCallback)( _stopCallbackData ) ;
03471         
03472     }
03473     
03474 }
03475 
03476 
03477 
03478 EngineTick Scheduler::computeEngineTickFromCurrentTime() 
03479 {
03480 
03481     Second currentSecond ;
03482     Microsecond currentMicrosecond ;
03483     
03484     getPreciseTime( currentSecond, currentMicrosecond ) ;
03485     
03486     
03487 
03488 
03489 
03490 
03491 
03492 
03493 
03494 
03495 
03496 
03497 
03498     
03499     
03500 
03501 
03502 
03503 
03504     if ( currentMicrosecond < _scheduleStartingMicrosecond )
03505     {
03506         
03507         
03508 #if OSDL_DEBUG_SCHEDULER
03509         if ( currentSecond == 0 )
03510         {
03511         
03512             LogPlug::fatal( "Scheduler::computeEngineTickFromCurrentTime: "
03513                 "abnormal clock skew." ) ;
03514                 
03515             _stopRequested = true ;
03516                 
03517         }   
03518 #endif // OSDL_DEBUG_SCHEDULER
03519         
03520         currentSecond-- ;
03521         currentMicrosecond += 1000000 ;
03522         
03523     }
03524         
03525     return static_cast<EngineTick>( 
03526         ( currentSecond - _scheduleStartingSecond ) * _secondToEngineTick
03527         + ( currentMicrosecond - _scheduleStartingMicrosecond ) 
03528             / _engineTickDuration ) ;
03529         
03530 }
03531 
03532 
03533 
03534 void Scheduler::scheduleSimulation( SimulationTick current ) 
03535 {
03536 
03537     
03538     
03539     OSDL_SCHEDULE_LOG( "--- simulating! " ) ;
03540         
03541     
03542     scheduleProgrammedObjects( current ) ;
03543         
03544     
03545     schedulePeriodicObjects( current ) ;
03546 
03547 }
03548 
03549 
03550 
03551 void Scheduler::scheduleProgrammedObjects( 
03552     SimulationTick currentSimulationTick ) 
03553 {
03554 
03555     map<SimulationTick, ListOfProgrammedActiveObjects>::iterator it 
03556         = _programmedActivated.find( currentSimulationTick ) ;
03557         
03558     if ( it != _programmedActivated.end() )
03559     {
03560     
03561         scheduleProgrammedObjectList( currentSimulationTick, (*it).second ) ;
03562         
03563         
03564         _programmedActivated.erase( it ) ;
03565         
03566     }
03567     
03568     
03569     
03570 }
03571 
03572 
03573 
03574 void Scheduler::schedulePeriodicObjects( SimulationTick current ) 
03575 {
03576 
03577     
03578 
03579 
03580  
03581     
03582     
03583     
03584     list<PeriodicSlot*>::iterator it = _periodicSlots.begin() ;
03585     
03586     while ( it != _periodicSlots.end() )
03587     {
03588         
03589         
03590 
03591 
03592 
03593          
03594         if ( ! (*it)->onNextTick( current ) )
03595         {
03596         
03597             
03598 
03599             send( " Scheduler::schedulePeriodicObjects for tick "
03600                 + Ceylan::toString( current) + ": removing slot "
03601                 + (*it)->toString() ) ;
03602              
03603             delete *it ;
03604             it = _periodicSlots.erase( it ) ;
03605             
03606         }   
03607         else
03608         {
03609             it++ ;
03610             
03611         }   
03612     }
03613     
03614     
03615     
03616 
03617 
03618 
03619         
03620 }
03621 
03622 
03623 
03624 void Scheduler::scheduleRendering( RenderingTick current ) 
03625 {
03626 
03627     OSDL_SCHEDULE_LOG( "--- rendering!" ) ;
03628 
03629     if ( _renderer != 0 )
03630         _renderer->render( current ) ;
03631     else
03632     {
03633 
03634 #if OSDL_DEBUG
03635         if ( _videoModule == 0 )
03636             Ceylan::emergencyShutdown( "Scheduler::scheduleRendering: "
03637                 "no video module available." ) ;        
03638 #endif // OSDL_DEBUG
03639         _videoModule->redraw() ;
03640             
03641     }   
03642         
03643 }
03644 
03645 
03646 
03647 void Scheduler::scheduleInput( InputTick current ) 
03648 {
03649 
03650     OSDL_SCHEDULE_LOG( "--- input polling!" ) ;
03651 
03652 #if OSDL_DEBUG
03653     if ( _eventsModule == 0 )
03654         Ceylan::emergencyShutdown( "Scheduler::scheduleRendering: "
03655             "no events module available." ) ;       
03656 #endif // OSDL_DEBUG
03657     
03658     _eventsModule->updateInputState() ; 
03659                 
03660 }
03661 
03662 
03663 
03664 void Scheduler::scheduleProgrammedObjectList( 
03665     Events::RenderingTick currentSimulationTick, 
03666     ListOfProgrammedActiveObjects & objectList ) 
03667 {
03668 
03669     for ( ListOfProgrammedActiveObjects::iterator it = objectList.begin(); 
03670         it != objectList.end(); it++ )
03671     {
03672     
03673         
03674         if ( *it != 0 )
03675             (*it)->onActivation( currentSimulationTick ) ;
03676     }
03677         
03678 }
03679 
03680 
03681      
03682 void Scheduler::onSimulationSkipped( SimulationTick skipped ) 
03683 {
03684 
03685     _missedSimulationTicks++ ;
03686     
03687         
03688     
03689 
03690 
03691 
03692 
03693     
03694     
03695 
03696 
03697 
03698 
03699     
03700     for ( list<PeriodicSlot*>::iterator it = _periodicSlots.begin(); 
03701         it != _periodicSlots.end(); it++ )
03702     {
03703         (*it)->onSimulationSkipped( skipped ) ;
03704     }
03705     
03706     
03707 
03708     map<SimulationTick, ListOfProgrammedActiveObjects>::iterator it 
03709         = _programmedActivated.find( skipped ) ;
03710         
03711     if ( it != _programmedActivated.end() )
03712     {
03713         
03714         for ( ListOfProgrammedActiveObjects::iterator itObjects =
03715                     (*it).second.begin() ; 
03716                 itObjects != (*it).second.end(); itObjects++ )
03717         {   
03718 
03719             
03720 
03721 
03722 
03723             if ( *itObjects != 0 )
03724                 (*itObjects)->onSkip( skipped ) ;
03725 
03726         }
03727                 
03728     }
03729     
03730 #if OSDL_DEBUG_SCHEDULER    
03731     LogPlug::warning( "Simulation tick " + Ceylan::toString( skipped ) 
03732         + " had to be skipped." ) ;
03733 #endif // OSDL_DEBUG_SCHEDULER
03734     
03735 }
03736 
03737 
03738 
03739 void Scheduler::onRenderingSkipped( RenderingTick skipped ) 
03740 {
03741 
03742     _missedRenderingTicks++ ;
03743     
03744     if ( _renderer != 0 )
03745         _renderer->onRenderingSkipped( skipped ) ;
03746         
03747 #if OSDL_DEBUG_SCHEDULER
03748     LogPlug::warning( "Rendering tick " + Ceylan::toString( skipped ) 
03749         + " had to be skipped." ) ;
03750 #endif // OSDL_DEBUG_SCHEDULER
03751         
03752 }
03753 
03754 
03755 
03756 void Scheduler::onInputSkipped( InputTick skipped ) 
03757 {
03758 
03759     _missedInputPollingTicks++ ;
03760         
03761     
03762     
03763 }
03764 
03765 
03766 
03767 void Scheduler::onIdle() 
03768 {
03769 
03770     OSDL_SCHEDULE_LOG( "--- idle callback called!" ) ;
03771 
03772     _idleCallsCount++ ;
03773 
03774     if ( _idleCallback != 0 )
03775     {
03776     
03777         
03778         (*_idleCallback)( _idleCallbackData ) ;
03779         
03780     }
03781     else
03782     {
03783     
03784         
03785 
03786 
03787 
03788 
03789         if ( _subSecondSleepsAvailable )
03790         {
03791         
03792             Ceylan::System::atomicSleep() ;
03793         
03794         }   
03795         else
03796         {
03797         
03798             
03799             if ( _idleCallsCount % 100 == 1 ) 
03800                 LogPlug::warning( 
03801                     "No idle call performed, no atomic call available." ) ;     
03802                 
03803         } 
03804     }   
03805     
03806 }
03807 
03808 
03809 
03810 void Scheduler::onScheduleFailure( Delay currentBucket ) 
03811 {
03812 
03813     _scheduleFailureCount++ ;
03814     
03815     
03816     
03817     if ( currentBucket < ShutdownBucketLevel )
03818     {
03819     
03820         string message = "Non-fatal schedule failure for engine tick #"
03821             + Ceylan::toString( _currentEngineTick )
03822             + ", delay bucket reached level "
03823             + Ceylan::toString( currentBucket ) 
03824             + ", this computer does not seem able to satisfy "
03825             "the requested load." ;
03826             
03827         
03828         OSDL_SCHEDULE_LOG( "!!!!! " + message ) ;
03829         
03830         LogPlug::error( message) ;  
03831         
03832     }
03833     else
03834     {
03835 
03836         OSDL_SCHEDULE_LOG( "[ E: " + Ceylan::toString( _currentEngineTick  )
03837             + " ; S: " + Ceylan::toString( _currentSimulationTick )
03838             + " ; R: " + Ceylan::toString( _currentRenderingTick )
03839             + " ; I: " + Ceylan::toString( _currentInputTick ) 
03840             + " ; B: " + Ceylan::toString( currentBucket ) + " ]" ) ;
03841 
03842         string message = "Fatal schedule failure for engine tick #"
03843             + Ceylan::toString( _currentEngineTick )
03844             + ", delay bucket reached level "
03845             + Ceylan::toString( currentBucket ) 
03846             + ", this computer cannot take in charge the requested load, "
03847             "stopping the scheduler now." ;
03848             
03849         
03850         OSDL_SCHEDULE_LOG( "XXXXX " + message ) ;
03851         
03852         LogPlug::fatal( message) ;  
03853                  
03854         stop() ;
03855         
03856         throw SchedulingException( message ) ;
03857     
03858     }
03859     
03860 }
03861 
03862 
03863 
03864 void Scheduler::programTriggerFor( ProgrammedActiveObject & objectToProgram, 
03865     SimulationTick targetTick ) 
03866 {
03867         
03868     map<SimulationTick, ListOfProgrammedActiveObjects>::iterator it 
03869         = _programmedActivated.find( targetTick ) ;
03870         
03871     if ( it != _programmedActivated.end() )
03872     {
03873     
03874         
03875         (*it).second.push_back( & objectToProgram ) ;
03876         
03877     }
03878     else
03879     {
03880     
03881         
03882         
03883         ListOfProgrammedActiveObjects newList ;
03884         
03885         newList.push_back( & objectToProgram ) ; 
03886         _programmedActivated[ targetTick ] = newList ;
03887                 
03888     }
03889     
03890 }
03891         
03892                     
03893 
03894 PeriodicSlot & Scheduler::getPeriodicSlotFor( Events::Period period ) 
03895 {
03896 
03897     for ( list<PeriodicSlot*>::iterator it = _periodicSlots.begin(); 
03898         it != _periodicSlots.end(); it++ )
03899     {
03900     
03901         if ( (*it)->getPeriod() == period )
03902             return * (*it) ;
03903         
03904         if ( (*it)->getPeriod() > period )
03905             throw SchedulingException( "Scheduler::getPeriodicSlotFor: "
03906                 "no slot found for period " + Ceylan::toString( period ) ) ;
03907                 
03908     }   
03909     
03910 
03911     throw SchedulingException( "Scheduler::getPeriodicSlotFor: "
03912         "no slot found for period " + Ceylan::toString( period ) ) ;
03913     
03914 }
03915 
03916 
03917                     
03918 PeriodicSlot & Scheduler::returnPeriodicSlotFor( Events::Period period ) 
03919 {
03920 
03921     for ( list<PeriodicSlot*>::iterator it = _periodicSlots.begin(); 
03922         it != _periodicSlots.end(); it++ )
03923     {
03924     
03925         if ( (*it)->getPeriod() == period )
03926             return * (*it) ;
03927         
03928         if ( (*it)->getPeriod() > period )
03929         {
03930         
03931             
03932 
03933 
03934 
03935 
03936             PeriodicSlot * newSlot = new PeriodicSlot( period ) ;
03937             _periodicSlots.insert( it, newSlot ) ;
03938             return * newSlot ;
03939              
03940         }   
03941 
03942     }   
03943     
03944     
03945 
03946 
03947 
03948 
03949     PeriodicSlot * newSlot = new PeriodicSlot( period ) ;
03950     _periodicSlots.push_back( newSlot ) ;
03951     
03952     return * newSlot ; 
03953     
03954 }
03955 
03956 
03957     
03958 void Scheduler::setInitialBirthTicks( 
03959     Events::SimulationTick birthSimulationTick ) 
03960 {
03961 
03962     
03963     for ( list<ActiveObject *>::iterator it = _initialRegisteredObjects.begin();
03964             it != _initialRegisteredObjects.end(); it++ )
03965         (*it)->setBirthTick( birthSimulationTick ) ;
03966         
03967     _initialRegisteredObjects.clear() ;
03968             
03969 }
03970 
03971 
03972 
03973 std::string Scheduler::describeProgrammedTicks() const
03974 {
03975 
03976     Ceylan::Uint32 tickCount = static_cast<Ceylan::Uint32>(
03977         _programmedActivated.size() ) ;
03978     
03979     if ( tickCount == 0 )   
03980         return "There is no programmed tick" ;
03981     else
03982         return "There are " + Ceylan::toString(tickCount) 
03983             + " programmed tick(s)" ;
03984             
03985 }
03986