Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

PsPvmController.cxx

Go to the documentation of this file.
00001 /*
00002  * This file is part of openMask © INRIA, CNRS, Universite de Rennes 1 1993-2002, thereinafter the Software
00003  * 
00004  * The Software has been developped within the Siames Project. 
00005  * INRIA, the University of Rennes 1 and CNRS jointly hold intellectual property rights
00006  * 
00007  * The Software has been registered with the Agence pour la Protection des
00008  * Programmes (APP) under registration number IDDN.FR.001.510008.00.S.P.2001.000.41200
00009  *  
00010  * This file may be distributed under the terms of the Q Public License
00011  * version 1.0 as defined by Trolltech AS of Norway and appearing in the file
00012  * LICENSE.QPL included in the packaging of this file.
00013  *
00014  * Licensees holding valid specific licenses issued by INRIA, CNRS or Université de Rennes 1 
00015  * for the software may use this file in accordance with that specific license
00016  *
00017  */
00018 #ifdef _PVM
00019 #include <unistd.h>
00020 #include <signal.h>
00021 #include <PsPvmController.h>
00022 #include "PsSynchronisationMessage.h"
00023 // Pour une mise en oeuvre PVM
00024 #include <PsnPvmSvm.h>
00025 #include <PsnSvmLink.h>
00026 #include "PsnPvmUnicastMessage.h"
00027 
00028 #include <PsObjectDescriptor.h>
00029 #include <PsSimulatedObject.h>
00030 #include <PsDuplicatedObject.h>
00031 #include <PsnProcess.h>
00032 #include <PsnMirrorObjectHandle.h>
00033 #include <PsnPvmReferenceObjectHandle.h>
00034 #include <PsnPvmDuplicatedObjectHandle.h>
00035 #include <unistd.h>
00036 #include <PsnDoubleListElement.h>
00037 #include <PsnDoubleList.h>
00038 #include "PsSystemEventIdentifier.h"
00039 #include "PsMultipleConfigurationParameter.h"
00040 
00041 #include "PsPvmException.h"
00042 #include "stdio.h"
00043 #include "pvm3.h"
00044 
00045 //------------------------------------------------------------------------
00046 
00047 PsPvmController::PsPvmController (PsObjectDescriptor & initialObjects,
00048                                   const PsDate & initialDate,
00049                                   int argc,
00050                                   char * argv [])
00051    : PsDistributedController (initialObjects, initialDate),
00052      _finishing ( false ) 
00053 {
00054    PsDate latence = 0 ;
00055    PsNameToPointerMap<PsnProcess> * processTable = new PsNameToPointerMap<PsnProcess>() ;
00056 
00057    PsMultipleConfigurationParameter * schedulingParameters = getSchedulingParametersOfObject( initialObjects ) ;
00058    if ( schedulingParameters != NULL)
00059       {
00060          PsConfigurationParameterDescriptor * param = schedulingParameters->getSubDescriptorByName("Latency") ;
00061          if (param != NULL)
00062             {
00063                latence = atoi (param->getAssociatedString().c_str()) ;
00064             }
00065          param = schedulingParameters->getSubDescriptorByName("Machines") ;
00066          PsMultipleConfigurationParameter * describedMachines = dynamic_cast<PsMultipleConfigurationParameter *>(param);
00067          if (describedMachines != NULL)
00068             {
00069                int numberOfMachines = describedMachines->getNumberOfSubItems () ;
00070                for (int machineNumber = 0 ;
00071                     machineNumber != numberOfMachines ;
00072                     ++machineNumber )
00073                   {
00074                      param = describedMachines->getSubDescriptorByPosition ( machineNumber ) ;
00075                      processTable->addObjectWithIndex ( describedMachines->getNameOfSubDescriptor (machineNumber),
00076                                                         new PsnProcess ( describedMachines->getNameOfSubDescriptor (machineNumber),
00077                                                                          param->getAssociatedString() )
00078                                                         ) ;
00079                   }
00080             }
00081       }
00082 
00083    // virtual member functions aren't initiallised in constructor
00084    // therefore, recreate the correct objectHandle
00085    delete _objectHandle ;
00086    
00087    _objectHandle = NULL ;
00088    
00089    PsnDuplicatedObjectHandle * localObjectHandle = newPsnDuplicatedObjectHandle( *this ) ;
00090    _objectHandle = localObjectHandle ;
00091 
00092   for (PsNameToPointerMap<PsnProcess>::const_iterator i = processTable->begin() ;
00093        i != processTable->end () ;
00094        ++i) 
00095      {
00096         localObjectHandle->addProcessOfDuplicate ( (*i).second ) ;
00097      }
00098 
00099 
00100    _distributedVirtualMachine = new PsnPvmSvm (processTable, latence, argc, argv) ;
00101 
00102    _distributedVirtualMachine->init (initialDate ) ;
00103 
00104    _processName = _distributedVirtualMachine->getSiteName () ;
00105 
00106    setProcessOfDescriptor ( initialObjects, _processName ) ;
00107 
00108    cout << "PsPvmController::PsPvmController (...)" 
00109         << "of process: " << _distributedVirtualMachine->getSiteName () << endl ;
00110 
00111 
00112    //rewritten 2001/12/5 by D. Margery
00113    list < PsObjectDescriptor *> * descriptorList = _simulationTree.getDescendants() ;
00114    for (list < PsObjectDescriptor *>::iterator descriptorIterator = descriptorList->begin() ;
00115         descriptorIterator != descriptorList->end() ;
00116         ++ descriptorIterator )
00117       {
00118          PsFrequency currentFreq = (*descriptorIterator)->getFrequency() ;
00119          PsName currentProcess = (*descriptorIterator)->getProcess() ;
00120          PsnProcess * currentProcessDescriptor = processTable->getObjectOfIndex( currentProcess ) ;
00121          if ( currentProcessDescriptor != NULL )
00122             // the process could have been removed by the svm
00123             {
00124                if ( currentFreq > currentProcessDescriptor->getMaxFrequencyOfHostedObjects () ) 
00125                   {
00126                      currentProcessDescriptor->setMaxHostedFrequency (currentFreq) ;
00127                   }
00128                currentProcessDescriptor->setFrequency ( PsController::lcm(currentFreq, currentProcessDescriptor->getFrequency() ) ) ;
00129             }
00130       }
00131    delete descriptorList ;
00132 
00133    //subscribe to system signals to receive notification on what is happening on other controllers
00134    registerForSignalBy(PsSystemEventIdentifier::MaskObjectDestroyed, getName()) ;
00135 
00136 }
00137 
00138 //------------------------------------------------------------------------------
00139 
00140 PsPvmController::~PsPvmController () 
00141 {
00142    // deconnexion de la machine virtuelle
00143 #ifdef _DEBUGEXECPVM
00144    cout << "PsPvmController::~PsPvmController : " << endl;
00145 #endif
00146    _distributedVirtualMachine->disconnectFromDistributedSimulation ( getSimulatedDate () ) ;
00147    delete _distributedVirtualMachine ;  
00148 }
00149 
00150 
00151 //------------------------------------------------------------------------------
00152 
00153 void PsPvmController::run()
00154 {
00155    if ( pvm_parent() != PvmNoParent )
00156       {
00157          PsDistributedController::run() ;
00158 
00159          // the simulation is locally finished, so notify all the controllers before exiting 
00160          PsDate lastDate = _date + 2 * _stepPeriod + _distributedVirtualMachine->getSynchronisationLatency() ;
00161 
00162          while (_date < lastDate )
00163             {
00164 #ifdef _DEBUGPVMMESS
00165                cerr<<"PsPvmController::run(): trying a clean exit"<<endl;
00166 #endif
00167                PsnReferenceObjectHandle * objectHandle = dynamic_cast<PsnReferenceObjectHandle *> ( _objectHandle ) ;
00168 
00169                assert ( objectHandle != NULL ) ;
00170                
00171                //the controller has to process residual system events adressed to itself
00172                objectHandle->processEvents() ;
00173                
00174                //send enought empty signals to enable other controllers to finish their job
00175                makeSynchronisationMessage( _referenceObjectsMap ) ;
00176                
00177                // send the synchronisation messages
00178                _distributedVirtualMachine->sendCurrentBuffersWithTag (PsnPvmMessage::SynchronisationMessage) ; 
00179 
00180                //wait a little, to try and get clean exit
00181                sleep(1) ;
00182 
00183                // for cleanup, read any arrived messages
00184                _distributedVirtualMachine->processReceivedMessages (*this, PsnPvmMessage::SynchronisationMessage) ;
00185 
00186                advanceSimulatedDate() ;
00187             } 
00188       }
00189    
00190 }
00191 
00192 
00193 
00194 PsnMirrorObjectHandle * PsPvmController::createMirrorObject (PsObjectDescriptor * objectDescription) 
00195 {
00196    PsnMirrorObjectHandle * mirror =  PsDistributedController::createMirrorObject( objectDescription ) ;
00197 
00198    // Register the mirror to the reference object for regular updates of outputs
00199    mirror->registerToReferenceObject () ;
00200    
00201    return mirror ;
00202 }
00203 
00204 
00205 //------------------------------------------------------------------------------
00206 
00207 const PsName & PsPvmController::getProcessName () const 
00208 {
00209    return (_distributedVirtualMachine->getSiteName ()) ;
00210 }
00211 
00212 //------------------------------------------------------------------------------
00213 void PsPvmController::advanceSimulatedDate () 
00214 {
00215 #ifdef _DEBUGEXECPVM
00216    cerr << "PsPvmController::advanceSimulatedDate () from " <<_date<<endl;
00217 #endif
00218    //send any messages collected during init
00219    if (_date < initialSimulationDate )
00220       {
00221          _distributedVirtualMachine->sendCurrentBuffersWithTag (PsnPvmMessage::SynchronisationMessage) ;  
00222       }
00223 
00224    PsDistributedController::advanceSimulatedDate () ;
00225 
00226    // prepare buffers to receive any message generate during this simulation step
00227    _distributedVirtualMachine->timestampCurrentSendBuffers (_date) ;   
00228 }
00229 
00230 
00231 void PsPvmController::computeNextSimulationStep () {
00232 #ifdef _DEBUGEXECPVM
00233    cerr << "PsPvmController::computeNextSimulation : computing yet another simulation step for " 
00234         <<notreProcessus()<< endl;
00235 #endif
00236   
00237    // compute the simulation step
00238    PsDistributedController::computeNextSimulationStep () ;
00239 
00240    // compute the synchronisation messages
00241    makeSynchronisationMessage ( _referenceObjectsMap ) ;
00242 
00243    // send the synchronisation messages
00244    _distributedVirtualMachine->sendCurrentBuffersWithTag (PsnPvmMessage::SynchronisationMessage) ;  
00245 
00246    // proceed with a relaxed synchronisation
00247    _distributedVirtualMachine->synchroniseReceiveAndProcessMessages (*this, PsnPvmMessage::SynchronisationMessage) ; 
00248 }
00249 
00250 //------------------------------------------------------------------------------
00251 
00252 void PsPvmController::makeSynchronisationMessage (PsNameToPointerMap<PsnReferenceObjectHandle> & referenceObjects ) 
00253 {
00254    static PsName endMessage ("_OpenMASKEndOfSynchronisationMessage") ;
00255 
00256 #ifdef _DEBUGPVMMESS
00257    cerr<<"PsPvmController::makeSynchronisationMessage for "<<referenceObjects.size() <<" objects "<<endl;
00258 #endif
00259 
00260   PsNameToPointerMap<PsnReferenceObjectHandle>::iterator pTabRef ;
00261   PsDate dt ;
00262   // ask all referentials to contribute to the synchronisation message
00263   for (pTabRef = referenceObjects.begin () ;
00264        pTabRef != referenceObjects.end () ;
00265        pTabRef ++) 
00266     {
00267 #ifdef _DEBUGPVMMESS
00268       cerr<<"PsPvmController::makeSynchronisationMessage for object " <<(*pTabRef).second->getSimulatedObject().getName()<<endl;
00269 #endif
00270       
00271       PsnPvmReferenceObjectHandle * pvmObjectHandle = dynamic_cast<PsnPvmReferenceObjectHandle *> ( (*pTabRef).second ) ; 
00272       if ( pvmObjectHandle != NULL )
00273          {
00274             pvmObjectHandle->makeSynchronisationMessage ( _date ) ;
00275          }
00276       else
00277          {
00278 #ifdef _DEBUGPVMMESS
00279             cerr<<"No synchronisation message for "<<(*pTabRef).second->getSimulatedObject().getName()<<endl;
00280 #endif      
00281          }
00282 #ifdef _DEBUGPVMMESS
00283       cerr<<"PsPvmController::makeSynchronisationMessage of " <<(*pTabRef).second->getSimulatedObject().getName()<<" done"<<endl;
00284 #endif
00285     } 
00286 #ifdef _DEBUGPVMMESS
00287       cerr<<"PsPvmController::makeSynchronisationMessage of done"<<endl;
00288 #endif
00289 }
00290 
00291 
00292 //------------------------------------------------------------------------------
00293 
00294 void PsPvmController::parseSynchronisationMessage (PsnPvmIncomingMessage * message) 
00295 {
00296 
00297   PsnReferenceObjectHandle * refer ; // Referentiel de l'objet destinataire
00298   PsnMirrorObjectHandle * miroir ; // Miroir de l'objet destinataire
00299   PsName nomObj ; // Nom du miroir destinataire
00300   bool stillMessagesToParse = true ;
00301 
00302 #ifdef _DEBUGPVMMESS
00303   cerr << "PsPvmController::parseSynchronisationMessage at "<<getSimulatedDate()<<":"<< endl ;
00304 #endif
00305     
00306 
00307    while ( stillMessagesToParse ) 
00308       {
00309          // get the message recepient
00310          nomObj.unpack ( *message ) ;
00311          
00312          
00313 #ifdef _DEBUGPVMMESS
00314          cerr << "PsPvmController::parseSynchronisationMessage: message received for " << nomObj << endl;
00315 #endif
00316          if ( nomObj == PsSynchronisationMessage::endOfSynchronisationFragment )
00317             // the synchronisation message has been completely parsed
00318             {
00319                stillMessagesToParse = false ;
00320             }
00321          else 
00322             {
00323                MirrorObjectsContainerType::iterator i = _mirrorObjectsMap.find ( nomObj ) ;
00324                if (i != _mirrorObjectsMap.end ()) 
00325                   {
00326                      // On lui transmet le message
00327 #ifdef _DEBUGPVMMESS
00328                      cout << "PsPvmController::parseSynchronisationMessage: for miror" << endl ;
00329 #endif
00330                      miroir = i->second ;
00331                      miroir->unpack ( *message ) ;
00332                   } 
00333                else if (_referenceObjectsMap.find (nomObj) != _referenceObjectsMap.end ()) 
00334                   {
00335                      // On lui transmet le message
00336 #ifdef _DEBUGPVMMESS
00337                      cout << "PsPvmController::parseSynchronisationMessage : for referential : " << nomObj <<endl ;
00338 #endif
00339                      refer = dynamic_cast<PsnPvmReferenceObjectHandle *>(_referenceObjectsMap.getObjectOfIndex (nomObj) ) ;
00340                      if ( refer != NULL )
00341                         {
00342                            refer->unpack (*message)  ;
00343                         }
00344                      else
00345                         {
00346                            dynamic_cast<PsnPvmDuplicatedObjectHandle *>(_referenceObjectsMap.getObjectOfIndex (nomObj) )->unpack ( *message ) ;
00347                         }
00348                   } 
00349                else if (nomObj == "") 
00350                   {
00351 #ifdef _DEBUGPVMMESS
00352                      cout << "PsPvmController::parseSynchronisationMessage :CL : message vide d'abonnement ... pour synchro" << endl ;
00353 #endif
00354                   } 
00355                else 
00356                   {
00357 #ifdef _DEBUGPVMMESS
00358                      cerr << "PsPvmController::parseSynchronisationMessage: "<< endl ;
00359                      cerr << "for unknown object: <" << nomObj << "> (was probably destroyed)" << endl ;
00360                      error ("PsPvmController::parseSynchronisationMessage : Objet ni miroir ni referentiel") ;
00361 #endif
00362                      //probably a request for an object that was destroyed
00363                      int typeMess ;
00364                      *message >> typeMess ;
00365                      // hope it is a registration for a just destroyed referential, and interprete it
00366                      if ( typeMess == Registration )
00367                         {
00368                            PsName processName ;
00369                            *message >> processName ;    
00370                         }
00371                      else if ( typeMess == EventReceived )
00372                         {
00373                            PsEvent * event ;
00374                            PsName classToCreate ;
00375                            PsEventIdentifier eventId;
00376                            PsDate eventDate;
00377                            PsName sender, receiver ;
00378                            *message >> classToCreate >> eventId>> eventDate>>sender>>receiver ;
00379                            event = PsEventCreator::createEvent (classToCreate, eventId, eventDate, sender, receiver ) ;
00380                            event->unpack ( *message ) ;
00381                            //cerr << "PsPvmController::parseSynchronisationMessage event "<<*event<<" undelivered"<<endl;
00382                            delete event ;
00383                         }
00384                   }
00385             }
00386       }
00387 #ifdef _DEBUGPVMMESS
00388    cerr << "PsPvmController::parseSynchronisationMessage : message parsed"<< endl ;
00389 #endif
00390 }
00391 
00392 
00393 
00394 
00395 
00396 
00397 //------------------------------------------------------------------------------
00398 
00399 void PsPvmController::init () 
00400 {
00401 
00402    if ( pvm_parent() != PvmNoParent )
00403       {
00404          //on tente l'initialisation normale : pour chaque init, cette initialisation appelle initObjetReferentiel 
00405 #ifdef _DEBUGDISTRIBUTEDINIT
00406          cerr<<"PsPvmController::init preparing the outgoing message buffers "<<endl;
00407 #endif   
00408          _distributedVirtualMachine->timestampCurrentSendBuffers ( _date ) ;
00409 
00410          // try a classic initialisation
00411          PsController::init () ;
00412 
00413          //initialisation shouldn't fail
00414          assert ( tableDesNonInitialises.empty () ) ;
00415 
00416          //here, as advanceSimulatedDate has been called to restore the initial simulation date, no need to timestamp messages
00417          
00418 #ifdef _DEBUGDISTRIBUTEDINIT
00419          cerr<<"PsPvmController::init : classic initialisation tried"<<endl;
00420 #endif
00421          // send all registrations
00422          _distributedVirtualMachine->sendCurrentBuffersWithTag (PsnPvmMessage::SynchronisationMessage) ;
00423 
00424          // broadcast a empty message signalling our initialisation is finished, and wait for all processes
00425          _distributedVirtualMachine->synchronizeOn ( *this, PsnPvmMessage::LocalInitSuccessfull ) ;
00426 
00427 
00428          //restore state to the supposed state resulting of a call to the ancestor init
00429          _distributedVirtualMachine->timestampCurrentSendBuffers (_date) ;
00430       }
00431    
00432 }
00433 
00434 //------------------------------------------------------------------------------
00435 
00436 int PsPvmController::getOutputHistorySize(void) {
00437   // Taille d'une file d'une output pour un controleur local
00438   // nbMinor * 4 --> pour guarantir la recuperation d'au plus 4 valeurs dans la file
00439   // 1 ?? surete ??
00440    int nbrValeurPendantLatence = 1 ;//la latence minimal est un pas de simulation au sens controleur
00441    nbrValeurPendantLatence+=_distributedVirtualMachine->getSynchronisationLatency()/_stepPeriod;
00442    return PsDistributedController::getOutputHistorySize()+nbrValeurPendantLatence;
00443 }  
00444 
00445 
00446 
00447 //------------------------------------------------------------------------------
00448 
00449 PsnObjectHandle * 
00450 PsPvmController::removeObjectFromDataStructures(const PsName & nom) 
00451 {
00452    PsnObjectHandle * result = NULL ;
00453    if (_referenceObjectsMap.find (nom) != _referenceObjectsMap.end ()) 
00454       {
00455          result = PsController::removeObjectFromDataStructures(nom);
00456       } 
00457    else 
00458       {
00459          MirrorObjectsContainerType::iterator i = _mirrorObjectsMap.find (nom) ;
00460          if (i != _mirrorObjectsMap.end ()) 
00461             {
00462                PsnMirrorObjectHandle * miroir = i->second ;
00463                _mirrorObjectsMap.erase( i );
00464                result = miroir;
00465             }
00466          else if (_duplicatedObjectsMap.find (nom) != _duplicatedObjectsMap.end()) 
00467             {
00468                //a duplicated object is a referential present in the duplicated objects table
00469                _duplicatedObjectsMap.erase(nom);
00470             }  
00471       } 
00472    return result ; 
00473 }
00474 
00475 
00476 //------------------------------------------------------------------------------
00477 
00478 PsnMirrorObjectHandle * PsPvmController::newPsnMirrorObjectHandle (PsSimulatedObject & obj) 
00479 {
00480   return new PsnMirrorObjectHandle(obj);
00481 }
00482 
00483 
00484 PsnDuplicatedObjectHandle * PsPvmController::newPsnDuplicatedObjectHandle (PsSimulatedObject & obj) 
00485 {
00486   return new PsnPvmDuplicatedObjectHandle( obj, *this );
00487 }
00488 
00489 
00490 PsnReferenceObjectHandle * PsPvmController::newPsnReferenceObjectHandle(PsSimulatedObject & object, 
00491                                                                         PsController & controller,
00492                                                                         PsnSignalDispatcher * signalDispatcher)
00493 {
00494   return new PsnPvmReferenceObjectHandle(object, controller, signalDispatcher );
00495 }
00496 
00497 PsnSvm * PsPvmController::getDistributedVirtualMachine ()
00498 {
00499    return _distributedVirtualMachine;
00500 }
00501 
00502 //------------------------------------------------------------------------------
00503 
00504 
00505 void PsPvmController::sendInitialValuesToMirror(PsnPvmIncomingMessage & message)
00506 {
00507    if ( ! _finishing )
00508       {
00509          // first find out the name of the objects whose initial values are needed
00510          PsName referentialName ;
00511          referentialName.unpack ( message ) ;
00512          
00513          cerr<<"Looking for initial values of "<<referentialName<<endl;
00514 
00515          //then find the corresponding referential
00516          PsNameToPointerMap<PsnReferenceObjectHandle>::iterator i = _referenceObjectsMap.find ( referentialName ) ;
00517          PsnPvmReferenceObjectHandle * referential = NULL ;
00518          if ( i != _referenceObjectsMap.end() ) 
00519             {
00520                referential = dynamic_cast<PsnPvmReferenceObjectHandle *> (i->second) ;
00521             }
00522          else
00523             {
00524                //the referential might have been destroyed: look for it in the list of deleted object handles
00525                list <pair <PsDate, PsnObjectHandle *> >::iterator i = _deletedObjectHandles.begin() ;
00526                while ( i != _deletedObjectHandles.end() )
00527                   {
00528                      if ( i->second->getSimulatedObject().getName() == referentialName )
00529                         {
00530                            referential = dynamic_cast<PsnPvmReferenceObjectHandle *> ( i->second );
00531                            i = _deletedObjectHandles.end() ;
00532                         }
00533                      else
00534                         {
00535                            ++ i ;
00536                         }
00537                   }
00538             }
00539          assert ( referential != NULL ) ;
00540          
00541          //find the name of the requesting process
00542          PsName mirrorProcessName ;
00543          mirrorProcessName.unpack( message ) ;
00544          
00545          //then find the link to the corresponding process
00546          PsnSvmLink * process = getDistributedVirtualMachine()->getLinkToProcessNamed ( mirrorProcessName ) ;
00547          
00548          assert ( process != NULL ) ;
00549          
00550          //build the answer
00551          PsnPvmUnicastMessage * urgentAnswer = new PsnPvmUnicastMessage ( process->getTID() ) ;
00552          
00553          urgentAnswer->insertTimeStamp( _date ) ;
00554          
00555          referential->packInitialValues ( * urgentAnswer ) ;
00556          
00557          PsSynchronisationMessage::endOfSynchronisationFragment.pack ( * urgentAnswer ) ;  
00558          
00559          // and send it
00560          urgentAnswer->send ( PsnPvmMessage::InitialValuesForMirror ) ;
00561       }
00562 }
00563 
00564 
00565 void PsPvmController::waitForAnswerToBlockingRequest (PsnPvmMessage::MessageTag tag)
00566 {
00567  if ( ! _finishing )
00568     // avoid blocking the contyroller while terminating, because other controllers could have exited
00569     {
00570        _distributedVirtualMachine->waitForAnswerToBlockingRequest ( *this, tag ) ;      
00571     }
00572 }
00573 
00574 void PsPvmController::finish()
00575 {
00576    _finishing = true ;
00577    PsDistributedController::finish() ;
00578 }
00579 
00580 PsDate PsPvmController::getPurgeDate () 
00581 {
00582    //in the worst case we could reveive message from an object whose simulation date is current date - _latency -stepPeriod ;
00583    // make sure by doubling latency
00584    return PsDistributedController::getPurgeDate() - 2 * _distributedVirtualMachine->getSynchronisationLatency() ;
00585 }
00586 
00587 #endif
00588 
00589 
00590 
00591 
00592 
00593 
00594 

logo OpenMask

Documentation generated on Mon Nov 25 15:25:02 2002

Generated with doxygen 1.2.12 by Dimitri van Heesch ,   1997-2001