src/simulator/realtime-simulator-impl.cc
author Guillaume Seguin <guillaume@segu.in>
Thu Nov 12 13:19:35 2009 +0100 (2009-11-12)
changeset 5507 915abd2b907b
parent 5302 5ed72d440db4
child 5521 37c6c83d4252
permissions -rw-r--r--
Simulator::SetScheduler now takes an ObjectFactory
     1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2008 University of Washington
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License version 2 as
     7  * published by the Free Software Foundation;
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  */
    18 
    19 #include "simulator.h"
    20 #include "realtime-simulator-impl.h"
    21 #include "wall-clock-synchronizer.h"
    22 #include "scheduler.h"
    23 #include "event-impl.h"
    24 #include "synchronizer.h"
    25 
    26 #include "ns3/ptr.h"
    27 #include "ns3/pointer.h"
    28 #include "ns3/assert.h"
    29 #include "ns3/fatal-error.h"
    30 #include "ns3/log.h"
    31 #include "ns3/system-mutex.h"
    32 #include "ns3/boolean.h"
    33 #include "ns3/enum.h"
    34 
    35 
    36 #include <math.h>
    37 
    38 NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorImpl");
    39 
    40 namespace ns3 {
    41 
    42 NS_OBJECT_ENSURE_REGISTERED (RealtimeSimulatorImpl);
    43 
    44 TypeId
    45 RealtimeSimulatorImpl::GetTypeId (void)
    46 {
    47   static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
    48     .SetParent<Object> ()
    49     .AddConstructor<RealtimeSimulatorImpl> ()
    50     .AddAttribute ("SynchronizationMode", 
    51                    "What to do if the simulation cannot keep up with real time.",
    52                    EnumValue (SYNC_BEST_EFFORT),
    53                    MakeEnumAccessor (&RealtimeSimulatorImpl::SetSynchronizationMode),
    54                    MakeEnumChecker (SYNC_BEST_EFFORT, "BestEffort",
    55                                     SYNC_HARD_LIMIT, "HardLimit"))
    56     .AddAttribute ("HardLimit", 
    57                    "Maximum acceptable real-time jitter (used in conjunction with SynchronizationMode=HardLimit)",
    58                    TimeValue (Seconds (0.1)),
    59                    MakeTimeAccessor (&RealtimeSimulatorImpl::m_hardLimit),
    60                    MakeTimeChecker ())
    61     ;
    62   return tid;
    63 }
    64 
    65 
    66 RealtimeSimulatorImpl::RealtimeSimulatorImpl ()
    67 {
    68   NS_LOG_FUNCTION_NOARGS ();
    69 
    70   m_stop = false;
    71   m_running = false;
    72   // uids are allocated from 4.
    73   // uid 0 is "invalid" events
    74   // uid 1 is "now" events
    75   // uid 2 is "destroy" events
    76   m_uid = 4; 
    77   // before ::Run is entered, the m_currentUid will be zero
    78   m_currentUid = 0;
    79   m_currentTs = 0;
    80   m_unscheduledEvents = 0;
    81 
    82   // Be very careful not to do anything that would cause a change or assignment
    83   // of the underlying reference counts of m_synchronizer or you will be sorry.
    84   m_synchronizer = CreateObject<WallClockSynchronizer> ();
    85 }
    86 
    87 RealtimeSimulatorImpl::~RealtimeSimulatorImpl ()
    88 {
    89   NS_LOG_FUNCTION_NOARGS ();
    90   while (m_events->IsEmpty () == false)
    91     {
    92       Scheduler::Event next = m_events->RemoveNext ();
    93       next.impl->Unref ();
    94     }
    95   m_events = 0;
    96   m_synchronizer = 0;
    97 }
    98 
    99 void
   100 RealtimeSimulatorImpl::Destroy ()
   101 {
   102   NS_LOG_FUNCTION_NOARGS ();
   103 
   104   //
   105   // This function is only called with the private version "disconnected" from
   106   // the main simulator functions.  We rely on the user not calling 
   107   // Simulator::Destroy while there is a chance that a worker thread could be
   108   // accessing the current instance of the private object.  In practice this
   109   // means shutting down the workers and doing a Join() before calling the
   110   // Simulator::Destroy().
   111   //
   112   while (m_destroyEvents.empty () == false) 
   113     {
   114       Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
   115       m_destroyEvents.pop_front ();
   116       NS_LOG_LOGIC ("handle destroy " << ev);
   117       if (ev->IsCancelled () == false)
   118         {
   119           ev->Invoke ();
   120         }
   121     }
   122 }
   123 
   124 void
   125 RealtimeSimulatorImpl::SetScheduler (ObjectFactory schedulerFactory)
   126 {
   127   NS_LOG_FUNCTION_NOARGS ();
   128 
   129   Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
   130 
   131   { 
   132     CriticalSection cs (m_mutex);
   133 
   134     if (m_events != 0)
   135       {
   136         while (m_events->IsEmpty () == false)
   137           {
   138             Scheduler::Event next = m_events->RemoveNext ();
   139             scheduler->Insert (next);
   140           }
   141       }
   142     m_events = scheduler;
   143   }
   144 }
   145 
   146 void
   147 RealtimeSimulatorImpl::ProcessOneEvent (void)
   148 {
   149   NS_LOG_FUNCTION_NOARGS ();
   150   //
   151   // The idea here is to wait until the next event comes due.  In the case of
   152   // a realtime simulation, we want real time to be consumed between events.  
   153   // It is the realtime synchronizer that causes real time to be consumed by
   154   // doing some kind of a wait.
   155   //
   156   // We need to be able to have external events (such as a packet reception event)
   157   // cause us to re-evaluate our state.  The way this works is that the synchronizer
   158   // gets interrupted and returs.  So, there is a possibility that things may change
   159   // out from under us dynamically.  In this case, we need to re-evaluate how long to 
   160   // wait in a for-loop until we have waited sucessfully (until a timeout) for the 
   161   // event at the head of the event list.
   162   //
   163   // m_synchronizer->Synchronize will return true if the wait was completed without 
   164   // interruption, otherwise it will return false indicating that something has changed
   165   // out from under us.  If we sit in the for-loop trying to synchronize until 
   166   // Synchronize() returns true, we will have successfully synchronized the execution 
   167   // time of the next event with the wall clock time of the synchronizer.
   168   //
   169 
   170   for (;;) 
   171     {
   172       uint64_t tsDelay = 0;
   173       uint64_t tsNext = 0;
   174 
   175       //
   176       // It is important to understand that m_currentTs is interpreted only as the 
   177       // timestamp  of the last event we executed.  Current time can a bit of a 
   178       // slippery concept in realtime mode.  What we have here is a discrete event 
   179       // simulator, so the last event is, by defintion, executed entirely at a single
   180       //  discrete time.  This is the definition of m_currentTs.  It really has 
   181       // nothing to do with the current real time, except that we are trying to arrange
   182       // that at the instant of the beginning of event execution, the current real time
   183       // and m_currentTs coincide.
   184       //
   185       // We use tsNow as the indication of the current real time.
   186       //
   187       uint64_t tsNow;
   188 
   189       { 
   190         CriticalSection cs (m_mutex);
   191         //
   192         // Since we are in realtime mode, the time to delay has got to be the 
   193         // difference between the current realtime and the timestamp of the next 
   194         // event.  Since m_currentTs is actually the timestamp of the last event we 
   195         // executed, it's not particularly meaningful for us here since real time has
   196         // certainly elapsed since it was last updated.
   197         //
   198         // It is possible that the current realtime has drifted past the next event
   199         // time so we need to be careful about that and not delay in that case.
   200         //
   201         NS_ASSERT_MSG (m_synchronizer->Realtime (), 
   202           "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
   203 
   204         //
   205         // tsNow is set to the normalized current real time.  When the simulation was
   206         // started, the current real time was effectively set to zero; so tsNow is
   207         // the current "real" simulation time.
   208         //
   209         // tsNext is the simulation time of the next event we want to execute.
   210         //
   211         tsNow = m_synchronizer->GetCurrentRealtime ();
   212         tsNext = NextTs ();
   213 
   214         //
   215         // tsDelay is therefore the real time we need to delay in order to bring the
   216         // real time in sync with the simulation time.  If we wait for this amount of
   217         // real time, we will accomplish moving the simulation time at the same rate
   218         // as the real time.  This is typically called "pacing" the simulation time.
   219         //
   220         // We do have to be careful if we are falling behind.  If so, tsDelay must be
   221         // zero.  If we're late, don't dawdle.
   222         //
   223         if (tsNext <= tsNow)
   224           {
   225             tsDelay = 0;
   226           }
   227         else
   228           {
   229             tsDelay = tsNext - tsNow;
   230           }
   231       
   232         //
   233         // We've figured out how long we need to delay in order to pace the 
   234         // simulation time with the real time.  We're going to sleep, but need
   235         // to work with the synchronizer to make sure we're awakened if something 
   236         // external happens (like a packet is received).  This next line resets
   237         // the synchronizer so that any future event will cause it to interrupt.
   238         //
   239         m_synchronizer->SetCondition (false);
   240       }
   241 
   242       //
   243       // We have a time to delay.  This time may actually not be valid anymore
   244       // since we released the critical section immediately above, and a real-time
   245       // ScheduleReal or ScheduleRealNow may have snuck in, well, between the 
   246       // closing brace above and this comment so to speak.  If this is the case, 
   247       // that schedule operation will have done a synchronizer Signal() that 
   248       // will set the condition variable to true and cause the Synchronize call 
   249       // below to return immediately.
   250       //
   251       // It's easiest to understand if you just consider a short tsDelay that only
   252       // requires a SpinWait down in the synchronizer.  What will happen is that 
   253       // whan Synchronize calls SpinWait, SpinWait will look directly at its 
   254       // condition variable.  Note that we set this condition variable to false 
   255       // inside the critical section above. 
   256       //
   257       // SpinWait will go into a forever loop until either the time has expired or
   258       // until the condition variable becomes true.  A true condition indicates that
   259       // the wait should stop.  The condition is set to true by one of the Schedule
   260       // methods of the simulator; so if we are in a wait down in Synchronize, and
   261       // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
   262       // Synchronize will return false.  This means we have not actually synchronized
   263       // to the event expiration time.  If no real-time schedule operation is done
   264       // while down in Synchronize, the wait will time out and Synchronize will return 
   265       // true.  This indicates that we have synchronized to the event time.
   266       //
   267       // So we need to stay in this for loop, looking for the next event timestamp and 
   268       // attempting to sleep until its due.  If we've slept until the timestamp is due, 
   269       // Synchronize returns true and we break out of the sync loop.  If an external
   270       // event happens that requires a re-schedule, Synchronize returns false and
   271       // we re-evaluate our timing by continuing in the loop.  
   272       //
   273       // It is expected that tsDelay become shorter as external events interrupt our
   274       // waits.
   275       //
   276       if (m_synchronizer->Synchronize (tsNow, tsDelay))
   277         {
   278           NS_LOG_LOGIC ("Interrupted ...");
   279           break;
   280         }
   281  
   282       //
   283       // If we get to this point, we have been interrupted during a wait by a real-time
   284       // schedule operation.  This means all bets are off regarding tsDelay and we need
   285       // to re-evaluate what it is we want to do.  We'll loop back around in the 
   286       // for-loop and start again from scratch.
   287       //
   288     }
   289 
   290   //
   291   // If we break out of the for-loop above, we have waited until the time specified
   292   // by the event that was at the head of the event list when we started the process.
   293   // Since there is a bunch of code that was executed outside a critical section (the
   294   // Synchronize call) we cannot be sure that the event at the head of the event list
   295   // is the one we think it is.  What we can be sure of is that it is time to execute
   296   // whatever event is at the head of this list if the list is in time order.
   297   //
   298   Scheduler::Event next;
   299 
   300   { 
   301     CriticalSection cs (m_mutex);
   302 
   303     // 
   304     // We do know we're waiting for an event, so there had better be an event on the 
   305     // event queue.  Let's pull it off.  When we release the critical section, the
   306     // event we're working on won't be on the list and so subsequent operations won't
   307     // mess with us.
   308     //
   309     NS_ASSERT_MSG (m_events->IsEmpty () == false, 
   310       "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
   311     next = m_events->RemoveNext ();
   312     --m_unscheduledEvents;
   313 
   314     //
   315     // We cannot make any assumption that "next" is the same event we originally waited 
   316     // for.  We can only assume that only that it must be due and cannot cause time 
   317     // to move backward.
   318     //
   319     NS_ASSERT_MSG (next.key.m_ts >= m_currentTs,
   320                    "RealtimeSimulatorImpl::ProcessOneEvent(): "
   321                    "next.GetTs() earlier than m_currentTs (list order error)");
   322     NS_LOG_LOGIC ("handle " << next.key.m_ts);
   323 
   324     // 
   325     // Update the current simulation time to be the timestamp of the event we're 
   326     // executing.  From the rest of the simulation's point of view, simulation time
   327     // is frozen until the next event is executed.
   328     //
   329     m_currentTs = next.key.m_ts;
   330     m_currentUid = next.key.m_uid;
   331 
   332     // 
   333     // We're about to run the event and we've done our best to synchronize this
   334     // event execution time to real time.  Now, if we're in SYNC_HARD_LIMIT mode
   335     // we have to decide if we've done a good enough job and if we haven't, we've
   336     // been asked to commit ritual suicide.
   337     //
   338     // We check the simulation time against the current real time to make this
   339     // judgement.
   340     //
   341     if (m_synchronizationMode == SYNC_HARD_LIMIT)
   342       {
   343         uint64_t tsFinal = m_synchronizer->GetCurrentRealtime ();
   344         uint64_t tsJitter;
   345 
   346         if (tsFinal >= m_currentTs)
   347           {
   348             tsJitter = tsFinal - m_currentTs;
   349           }
   350         else
   351           {
   352             tsJitter = m_currentTs - tsFinal;
   353           }
   354 
   355         if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep ()))
   356           {
   357             NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): "
   358                             "Hard real-time limit exceeded (jitter = " << tsJitter << ")");
   359           }
   360       }
   361   }
   362 
   363   //
   364   // We have got the event we're about to execute completely disentangled from the 
   365   // event list so we can execute it outside a critical section without fear of someone
   366   // changing things out from under us.
   367 
   368   EventImpl *event = next.impl;
   369   m_synchronizer->EventStart ();
   370   event->Invoke ();
   371   m_synchronizer->EventEnd ();
   372   event->Unref ();
   373 }
   374 
   375 bool 
   376 RealtimeSimulatorImpl::IsFinished (void) const
   377 {
   378   NS_LOG_FUNCTION_NOARGS ();
   379   bool rc;
   380   {
   381     CriticalSection cs (m_mutex);
   382     rc = m_events->IsEmpty () || m_stop;
   383   }
   384 
   385   return rc;
   386 }
   387 
   388 //
   389 // Peeks into event list.  Should be called with critical section locked.
   390 //
   391 uint64_t
   392 RealtimeSimulatorImpl::NextTs (void) const
   393 {
   394   NS_LOG_FUNCTION_NOARGS ();
   395   NS_ASSERT_MSG (m_events->IsEmpty () == false, 
   396     "RealtimeSimulatorImpl::NextTs(): event queue is empty");
   397   Scheduler::Event ev = m_events->PeekNext ();
   398   return ev.key.m_ts;
   399 }
   400 
   401 //
   402 // Calls NextTs().  Should be called with critical section locked.
   403 //
   404 Time
   405 RealtimeSimulatorImpl::Next (void) const
   406 {
   407   NS_LOG_FUNCTION_NOARGS ();
   408   return TimeStep (NextTs ());
   409 }
   410 
   411 void
   412 RealtimeSimulatorImpl::Run (void)
   413 {
   414   NS_LOG_FUNCTION_NOARGS ();
   415 
   416   NS_ASSERT_MSG (m_running == false, 
   417                  "RealtimeSimulatorImpl::Run(): Simulator already running");
   418 
   419   m_stop = false;
   420   m_running = true;
   421   m_synchronizer->SetOrigin (m_currentTs);
   422 
   423   for (;;) 
   424     {
   425       bool done = false;
   426 
   427       {
   428         CriticalSection cs (m_mutex);
   429         //
   430         // In all cases we stop when the event list is empty.  If you are doing a 
   431         // realtime simulation and you want it to extend out for some time, you must
   432         // call StopAt.  In the realtime case, this will stick a placeholder event out
   433         // at the end of time.
   434         //
   435         if (m_stop || m_events->IsEmpty ())
   436           {
   437             done = true;
   438           }
   439       }
   440 
   441       if (done)
   442         {
   443           break;
   444         }
   445 
   446       ProcessOneEvent ();
   447     }
   448 
   449   //
   450   // If the simulator stopped naturally by lack of events, make a
   451   // consistency test to check that we didn't lose any events along the way.
   452   //
   453   {
   454     CriticalSection cs (m_mutex);
   455 
   456     NS_ASSERT_MSG (m_events->IsEmpty () == false || m_unscheduledEvents == 0,
   457       "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events");
   458   }
   459 
   460   m_running = false;
   461 }
   462 
   463 bool
   464 RealtimeSimulatorImpl::Running (void) const
   465 {
   466   NS_LOG_FUNCTION_NOARGS ();
   467   return m_running;
   468 }
   469 
   470 bool
   471 RealtimeSimulatorImpl::Realtime (void) const
   472 {
   473   NS_LOG_FUNCTION_NOARGS ();
   474   return m_synchronizer->Realtime ();
   475 }
   476 
   477 //
   478 // This will run the first event on the queue without considering any realtime
   479 // synchronization.  It's mainly implemented to allow simulations requiring
   480 // the multithreaded ScheduleRealtimeNow() functions the possibility of driving
   481 // the simulation from their own event loop.
   482 //
   483 // It is expected that if there are any realtime requirements, the responsibility
   484 // for synchronizing with real time in an external event loop will be picked up
   485 // by that loop.  For example, they may call Simulator::Next() to find the 
   486 // execution time of the next event and wait for that time somehow -- then call
   487 // RunOneEvent to fire the event.
   488 // 
   489 void
   490 RealtimeSimulatorImpl::RunOneEvent (void)
   491 {
   492   NS_LOG_FUNCTION_NOARGS ();
   493 
   494   NS_ASSERT_MSG (m_running == false, 
   495                  "RealtimeSimulatorImpl::RunOneEvent(): An internal simulator event loop is running");
   496 
   497   EventImpl *event = 0;
   498 
   499   //
   500   // Run this in a critical section in case there's another thread around that
   501   // may be inserting things onto the event list.
   502   //
   503   {
   504     CriticalSection cs (m_mutex);
   505 
   506     Scheduler::Event next = m_events->RemoveNext ();
   507 
   508     NS_ASSERT (next.key.m_ts >= m_currentTs);
   509     --m_unscheduledEvents;
   510 
   511     NS_LOG_LOGIC ("handle " << next.key.m_ts);
   512     m_currentTs = next.key.m_ts;
   513     m_currentUid = next.key.m_ts;
   514     event = next.impl;
   515   }
   516   event->Invoke ();
   517   event->Unref ();
   518 }
   519 
   520 void 
   521 RealtimeSimulatorImpl::Stop (void)
   522 {
   523   NS_LOG_FUNCTION_NOARGS ();
   524   m_stop = true;
   525 }
   526 
   527 //
   528 // Schedule an event for a _relative_ time in the future.
   529 //
   530 EventId
   531 RealtimeSimulatorImpl::Schedule (Time const &time, EventImpl *impl)
   532 {
   533   NS_LOG_FUNCTION (time << impl);
   534 
   535   Scheduler::Event ev;
   536   {
   537     CriticalSection cs (m_mutex);
   538     //
   539     // This is the reason we had to bring the absolute time calcualtion in from the
   540     // simulator.h into the implementation.  Since the implementations may be 
   541     // multi-threaded, we need this calculation to be atomic.  You can see it is
   542     // here since we are running in a CriticalSection.
   543     //
   544     Time tAbsolute = Simulator::Now () + time;
   545     NS_ASSERT_MSG (tAbsolute.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative time");
   546     NS_ASSERT_MSG (tAbsolute >= TimeStep (m_currentTs), "RealtimeSimulatorImpl::Schedule(): time < m_currentTs");
   547     ev.impl = impl;
   548     ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
   549     ev.key.m_uid = m_uid;
   550     m_uid++;
   551     ++m_unscheduledEvents;
   552     m_events->Insert (ev);
   553     m_synchronizer->Signal ();
   554   }
   555 
   556   return EventId (impl, ev.key.m_ts, ev.key.m_uid);
   557 }
   558 
   559 EventId
   560 RealtimeSimulatorImpl::ScheduleNow (EventImpl *impl)
   561 {
   562   NS_LOG_FUNCTION_NOARGS ();
   563   Scheduler::Event ev;
   564   {
   565     CriticalSection cs (m_mutex);
   566 
   567     ev.impl = impl;
   568     ev.key.m_ts = m_currentTs;
   569     ev.key.m_uid = m_uid;
   570     m_uid++;
   571     ++m_unscheduledEvents;
   572     m_events->Insert (ev);
   573     m_synchronizer->Signal ();
   574   }
   575 
   576   return EventId (impl, ev.key.m_ts, ev.key.m_uid);
   577 }
   578 
   579 Time
   580 RealtimeSimulatorImpl::Now (void) const
   581 {
   582   return TimeStep (m_currentTs);
   583 }
   584 
   585 //
   586 // Schedule an event for a _relative_ time in the future.
   587 //
   588 void
   589 RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, EventImpl *impl)
   590 {
   591   NS_LOG_FUNCTION (time << impl);
   592 
   593   
   594   {
   595     CriticalSection cs (m_mutex);
   596 
   597     uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
   598     NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
   599     Scheduler::Event ev;
   600     ev.impl = impl;
   601     ev.key.m_ts = ts;
   602     ev.key.m_uid = m_uid;
   603     m_uid++;
   604     ++m_unscheduledEvents;
   605     m_events->Insert (ev);
   606     m_synchronizer->Signal ();
   607   }
   608 
   609 }
   610 
   611 void
   612 RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
   613 {
   614   NS_LOG_FUNCTION_NOARGS ();
   615   {
   616     CriticalSection cs (m_mutex);
   617 
   618     //
   619     // If the simulator is running, we're pacing and have a meaningful 
   620     // realtime clock.  If we're not, then m_currentTs is were we stopped.
   621     // 
   622     uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
   623     NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtimeNow(): schedule for time < m_currentTs");
   624     Scheduler::Event ev;
   625     ev.impl = impl;
   626     ev.key.m_ts = ts;
   627     ev.key.m_uid = m_uid;
   628     m_uid++;
   629     ++m_unscheduledEvents;
   630     m_events->Insert (ev);
   631     m_synchronizer->Signal ();
   632   }
   633 }
   634 
   635 Time
   636 RealtimeSimulatorImpl::RealtimeNow (void) const
   637 {
   638   return TimeStep (m_synchronizer->GetCurrentRealtime ());
   639 }
   640 
   641 EventId
   642 RealtimeSimulatorImpl::ScheduleDestroy (EventImpl *impl)
   643 {
   644   NS_LOG_FUNCTION_NOARGS ();
   645 
   646   EventId id;
   647   {
   648     CriticalSection cs (m_mutex);
   649 
   650     //
   651     // Time doesn't really matter here (especially in realtime mode).  It is 
   652     // overridden by the uid of 2 which identifies this as an event to be 
   653     // executed at Simulator::Destroy time.
   654     //
   655     id = EventId (Ptr<EventImpl> (impl, false), m_currentTs, 2);
   656     m_destroyEvents.push_back (id);
   657     m_uid++;
   658   }
   659 
   660   return id;
   661 }
   662 
   663 Time 
   664 RealtimeSimulatorImpl::GetDelayLeft (const EventId &id) const
   665 {
   666   //
   667   // If the event has expired, there is no delay until it runs.  It is not the
   668   // case that there is a negative time until it runs.
   669   //
   670   if (IsExpired (id))
   671     {
   672       return TimeStep (0);
   673     }
   674 
   675   return TimeStep (id.GetTs () - m_currentTs);
   676 }
   677 
   678 void
   679 RealtimeSimulatorImpl::Remove (const EventId &id)
   680 {
   681   if (id.GetUid () == 2)
   682     {
   683       // destroy events.
   684       for (DestroyEvents::iterator i = m_destroyEvents.begin (); 
   685            i != m_destroyEvents.end (); 
   686            i++)
   687         {
   688           if (*i == id)
   689             {
   690               m_destroyEvents.erase (i);
   691               break;
   692             }
   693          }
   694       return;
   695     }
   696   if (IsExpired (id))
   697     {
   698       return;
   699     }
   700 
   701   {
   702     CriticalSection cs (m_mutex);
   703 
   704     Scheduler::Event event;
   705     event.impl = id.PeekEventImpl ();
   706     event.key.m_ts = id.GetTs ();
   707     event.key.m_uid = id.GetUid ();
   708     
   709     m_events->Remove (event);
   710     --m_unscheduledEvents;
   711     event.impl->Cancel ();
   712     event.impl->Unref ();
   713   }
   714 }
   715 
   716 void
   717 RealtimeSimulatorImpl::Cancel (const EventId &id)
   718 {
   719   if (IsExpired (id) == false)
   720     {
   721       id.PeekEventImpl ()->Cancel ();
   722     }
   723 }
   724 
   725 bool
   726 RealtimeSimulatorImpl::IsExpired (const EventId &ev) const
   727 {
   728   if (ev.GetUid () == 2)
   729     {
   730       if (ev.PeekEventImpl () == 0 ||
   731           ev.PeekEventImpl ()->IsCancelled ())
   732         {
   733           return true;
   734         }
   735       // destroy events.
   736       for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); 
   737            i != m_destroyEvents.end (); i++)
   738         {
   739           if (*i == ev)
   740             {
   741               return false;
   742             }
   743          }
   744       return true;
   745     }
   746 
   747   //
   748   // If the time of the event is less than the current timestamp of the 
   749   // simulator, the simulator has gone past the invocation time of the 
   750   // event, so the statement ev.GetTs () < m_currentTs does mean that 
   751   // the event has been fired even in realtime mode.
   752   //
   753   // The same is true for the next line involving the m_currentUid.
   754   //
   755   if (ev.PeekEventImpl () == 0 ||
   756       ev.GetTs () < m_currentTs ||
   757       (ev.GetTs () == m_currentTs && ev.GetUid () <= m_currentUid) ||
   758       ev.PeekEventImpl ()->IsCancelled ()) 
   759     {
   760       return true;
   761     }
   762   else
   763     {
   764       return false;
   765     }
   766 }
   767 
   768 Time 
   769 RealtimeSimulatorImpl::GetMaximumSimulationTime (void) const
   770 {
   771   // XXX: I am fairly certain other compilers use other non-standard
   772   // post-fixes to indicate 64 bit constants.
   773   return TimeStep (0x7fffffffffffffffLL);
   774 }
   775 
   776 void 
   777 RealtimeSimulatorImpl::SetSynchronizationMode (enum SynchronizationMode mode)
   778 {
   779   NS_LOG_FUNCTION (mode);
   780   m_synchronizationMode = mode;
   781 }
   782 
   783 RealtimeSimulatorImpl::SynchronizationMode
   784 RealtimeSimulatorImpl::GetSynchronizationMode (void) const
   785 {
   786   NS_LOG_FUNCTION_NOARGS ();
   787   return m_synchronizationMode;
   788 }
   789   
   790 void 
   791 RealtimeSimulatorImpl::SetHardLimit (Time limit)
   792 {
   793   NS_LOG_FUNCTION (limit);
   794   m_hardLimit = limit;
   795 }
   796 
   797 Time
   798 RealtimeSimulatorImpl::GetHardLimit (void) const
   799 {
   800   NS_LOG_FUNCTION_NOARGS ();
   801   return m_hardLimit;
   802 }
   803   
   804 }; // namespace ns3