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
00021
00022
00023
00024 _slots = new ListOfActiveObjects *[ _period ] ;
00025
00026 _slotWeights = new Weight[ _period ] ;
00027
00028
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
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
00065
00066
00067
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
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
00116
00117
00118
00119 Period deducedSubSlot = getSubSlotForSimulationTick( newTick ) ;
00120
00121 if ( _currentSlot != deducedSubSlot || _period == 1 )
00122 {
00123
00124
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
00137
00138
00139
00140 _currentSlot = deducedSubSlot ;
00141 activateAllObjectsInSubSlot( _currentSlot, newTick ) ;
00142
00143 }
00144 else
00145 {
00146
00147
00148
00149
00150
00151
00152
00153 if ( newTick != 0 )
00154 {
00155
00156
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
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
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
00281
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
00294 if ( _slots[ targetSlot ]->empty() )
00295 {
00296 delete _slots[ targetSlot ] ;
00297 _slots[ targetSlot ] = 0 ;
00298
00299 }
00300
00301
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
00336 return ;
00337 }
00338
00339
00340
00341
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