OSDLPeriodicSlot.cc

Go to the documentation of this file.
00001 #include "OSDLPeriodicSlot.h"
00002 
00003 using namespace OSDL::Events ;
00004 using namespace OSDL::Engine ;
00005 
00006 using namespace Ceylan::Log ;
00007 
00008 using std::string ;
00009 using std::list ;
00010 
00011 
00012 
00013 
00014 PeriodicSlot::PeriodicSlot( Period periodicity ) throw() :
00015     _period( periodicity ),
00016     _currentSlot( 0 )
00017 {
00018 
00019     /*
00020      * This array will contain _period pointers to ListOfActiveObjects 
00021      * instances :
00022      *
00023      */
00024     _slots = new ListOfActiveObjects *[ _period ] ;
00025     
00026     _slotWeights = new Weight[ _period ] ;
00027     
00028     // Initializes with null pointer for lists, and zero for weights :
00029     
00030     for ( Period i = 0; i < _period; i++ )
00031     {
00032         _slots[i] = 0 ;
00033         _slotWeights[ i ] = 0 ;
00034     }   
00035     
00036 }
00037 
00038 
00039 PeriodicSlot::~PeriodicSlot() throw() 
00040 {
00041 
00042     // The lists are deleted, but not the active objects they may contain.
00043     
00044     for ( Period i = 0; i < _period; i++ )
00045     {
00046         if ( _slots[i] != 0 )
00047             delete _slots[i] ;
00048     }
00049             
00050     delete [] _slots ;
00051 
00052     delete [] _slotWeights ;
00053     
00054     
00055 }
00056 
00057 
00058 void PeriodicSlot::add( ActiveObject & newObject ) throw( SchedulingException )
00059 {
00060     
00061     Period chosenSlot ;
00062     
00063     /*
00064      * If strict policy is requested, schedules the object exactly at 
00065      * next simulation step.
00066      *
00067      * If relaxed policy is allowed, schedule on least crowded slot.
00068      *
00069      */
00070     switch( newObject.getPolicy() )
00071     {
00072     
00073         case strict:
00074             chosenSlot = ( _currentSlot + 1 ) % _period ;
00075             break ;
00076             
00077         case relaxed:   
00078             chosenSlot = getLeastBusySlot() ;
00079             break ;
00080     
00081         default:
00082             throw SchedulingException( "PeriodicSlot::add : "
00083                 "unexpected scheduling policy." ) ;
00084                 
00085     }
00086             
00087     // Apply slot choice for all policies :
00088     addInSlot( newObject, chosenSlot ) ;
00089             
00090 }
00091 
00092 
00093 void PeriodicSlot::remove( ActiveObject & object ) throw( SchedulingException )
00094 {
00095 
00096     bool removed = false ;
00097     
00098     for ( Period i = 0; i < _period; i++ )
00099     {
00100         if ( removeFromSlot( object, i ) )
00101             removed = true ;
00102     }
00103     
00104     if ( ! removed )
00105         throw SchedulingException( 
00106             "PeriodicSlot::remove : all slots inspected for object ("
00107             + object.toString( Ceylan::low ) + "), but was never found." ) ;
00108 }
00109 
00110 
00111 void PeriodicSlot::onNextTick( Events::SimulationTick newTick ) throw()
00112 {
00113     
00114     /*
00115      * Protect from multiple calls. 
00116      * Unitary periods are special cases, since the current slot never changes.
00117      *
00118      */
00119     Period deducedSubSlot = getSubSlotForSimulationTick( newTick ) ;
00120     
00121     if ( _currentSlot != deducedSubSlot || _period == 1 )
00122     {
00123     
00124         // OK, it is not the last slot again. But is it really the next slot ?
00125         _currentSlot = ( _currentSlot + 1 ) % _period ; 
00126 
00127         if ( _currentSlot != deducedSubSlot )
00128             LogPlug::warning( 
00129                 "PeriodicSlot::onNextTick : expected next sub-slot to be " 
00130                 + Ceylan::toString( _currentSlot ) + ", got " 
00131                 + Ceylan::toString( deducedSubSlot )
00132                 + " for simulation tick "
00133                 + Ceylan::toString( newTick ) + "." ) ;
00134         
00135         /*
00136          * Nevermind, reset the current slot on all situations, and 
00137          * activate accordingly :       
00138          *
00139          */
00140         _currentSlot = deducedSubSlot ;
00141         activateAllObjectsInSubSlot( _currentSlot, newTick ) ;
00142         
00143     }
00144     else
00145     {
00146         
00147         /*
00148          * First simulation tick is a special case (bootstrap), since 
00149          * initial sub-slot is zero too.
00150          *
00151          */
00152         
00153         if ( newTick != 0 )
00154         {
00155         
00156             // The sub-slot has already been activated !
00157             LogPlug::warning( "PeriodicSlot::onNextTick : "
00158                 "apparently called multiple times for simulation time " 
00159                 + Ceylan::toString( newTick ) 
00160                 + " (last activated sub-slot was "
00161                 + Ceylan::toString( _currentSlot ) 
00162                 + "), no more activation performed." ) ;
00163         }       
00164         
00165     }       
00166 }
00167 
00168 
00169 void PeriodicSlot::onSimulationSkipped( SimulationTick skipped ) 
00170     throw( SchedulingException )
00171 {
00172 
00173     Period subSlot = getSubSlotForSimulationTick( skipped ) ;
00174     
00175     // Propagate the notification to all objects of the sub-slot :
00176     
00177     if ( _slots[subSlot] != 0 )
00178     {
00179         for ( ListOfActiveObjects::iterator it = _slots[subSlot]->begin() ;
00180                 it != _slots[subSlot]->end(); it++ )
00181             (*it)->onSkip( skipped ) ;
00182     }
00183     
00184     // Avoid to confuse onNextTick :
00185     _currentSlot = subSlot ;
00186     
00187 }
00188 
00189                     
00190 Period PeriodicSlot::getPeriod() throw()
00191 {
00192 
00193     return _period ;
00194     
00195 }
00196 
00197 
00198 const string PeriodicSlot::toString( Ceylan::VerbosityLevels level ) 
00199     const throw()
00200 {
00201 
00202     string res = "Periodic slot whose period is " 
00203         + Ceylan::toString( _period ) 
00204         + ". Current sub-slot is " 
00205         + Ceylan::toString( _currentSlot ) ; 
00206         
00207     if ( level == Ceylan::low )
00208         return res ;
00209     
00210     if ( level == Ceylan::medium )
00211     {
00212         
00213         unsigned int objectCount = 0 ;
00214         Weight weightCount = 0 ;
00215         
00216     
00217         for ( Period i = 0; i < _period; i++ )
00218         {   
00219             if ( _slots[i] != 0 )
00220                 objectCount += _slots[i]->size() ;
00221             weightCount += _slotWeights[i] ;
00222         }       
00223     
00224         return res + ". " + Ceylan::toString( objectCount ) 
00225             + " active objects are registered in its slots, "
00226             "for a total weight of "
00227             + Ceylan::toString( weightCount ) + "." ;
00228     }
00229         
00230     list<string> l ;
00231     
00232     for ( Period i = 0; i < _period; i++ )
00233     {   
00234         if ( _slots[i] != 0 && _slots[i]->size() != 0 )
00235             l.push_back( "slot #" + Ceylan::toString( i ) + " contains " 
00236                 + Ceylan::toString( _slots[i]->size() ) 
00237                 + " active object(s), for a total weight of "
00238                 + Ceylan::toString( _slotWeights[i] ) + "." ) ;
00239         else
00240             l.push_back( "slot #" + Ceylan::toString( i ) + " is empty." ) ;    
00241     }       
00242     
00243     return res + Ceylan::formatStringList( l ) ;
00244         
00245 }
00246                         
00247 
00248 Period PeriodicSlot::getSubSlotForSimulationTick( SimulationTick tick ) 
00249     const throw()
00250 {
00251 
00252     return ( tick % _period ) ;
00253     
00254 }
00255 
00256 
00257 void PeriodicSlot::addInSlot( ActiveObject & newObject, Period targetSlot )
00258     throw()
00259 {
00260 
00261     if ( _slots[ targetSlot ] == 0 )
00262         _slots[ targetSlot ] = new ListOfActiveObjects() ;
00263         
00264     _slots[ targetSlot ]->push_back( & newObject ) ;
00265     _slotWeights[ targetSlot ] += newObject.getWeight() ;
00266     
00267 }
00268 
00269 
00270 bool PeriodicSlot::removeFromSlot( ActiveObject & object, Period targetSlot )
00271     throw( SchedulingException )
00272 {
00273     
00274     if ( _slots[ targetSlot ] == 0 )
00275         return false ;
00276         
00277     Ceylan::Uint32 count = 0 ;
00278     
00279     /* 
00280      * Removes all occurences of this object, must use two passes since
00281      * otherwise an erase would invalidate the iterator.
00282      *
00283      */
00284     for ( ListOfActiveObjects::iterator it = _slots[ targetSlot ]->begin() ; 
00285         it != _slots[ targetSlot ]->end(); it++ )
00286     {
00287         if ( (*it) == & object )
00288             count++ ;
00289     }
00290     _slots[ targetSlot ]->remove( & object ) ;
00291     
00292     
00293     // An empty slot should be deleted :    
00294     if ( _slots[ targetSlot ]->empty() )
00295     {
00296         delete _slots[ targetSlot ] ;
00297         _slots[ targetSlot ] = 0 ;
00298         // _slotWeights will be zero on method return.
00299     }       
00300     
00301     // Update the precomputed weight :      
00302     _slotWeights[ targetSlot ] -= object.getWeight() * count ;
00303     
00304     return ( count != 0 ) ;
00305 
00306 }
00307 
00308 
00309 Period PeriodicSlot::getLeastBusySlot() const throw()
00310 {
00311 
00312     Weight minWeight = _slotWeights[ 0 ] ;
00313     Period minIndex = 0 ;
00314     
00315     for ( Period i = 1; i < _period; i++ )
00316     {
00317         if ( _slotWeights[ i ] < minWeight )
00318         {
00319             minIndex = i ;
00320             minWeight = _slotWeights[ i ] ;
00321         }
00322     }
00323     
00324     return minIndex ;
00325     
00326 }
00327 
00328 
00329 void PeriodicSlot::activateAllObjectsInSubSlot( Period subSlot,
00330     Events::SimulationTick currentTime ) throw()
00331 {
00332 
00333     if ( _slots[ subSlot ] == 0 )
00334     {
00335         // Nothing in this sub-slot, nothing to do !
00336         return ;
00337     }
00338     
00339     /*
00340      * There could be too a dynamic slip for heavy active objects with 
00341      * relaxed policy.
00342      *
00343      */
00344     
00345     for ( ListOfActiveObjects::iterator it = _slots[ subSlot ]->begin();
00346         it != _slots[ subSlot ]->end(); it++ )
00347     {   
00348         (*it)->onActivation( currentTime ) ;    
00349     }
00350 
00351 }
00352 

Generated on Fri Mar 30 14:46:59 2007 for OSDL by  doxygen 1.5.1