A Discrete-Event Network Simulator
API
realtime-simulator-impl.cc
Go to the documentation of this file.
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"
22 #include "scheduler.h"
23 #include "event-impl.h"
24 #include "synchronizer.h"
25 
26 #include "ptr.h"
27 #include "pointer.h"
28 #include "assert.h"
29 #include "fatal-error.h"
30 #include "log.h"
31 #include "system-mutex.h"
32 #include "boolean.h"
33 #include "enum.h"
34 
35 
36 #include <cmath>
37 
38 
45 namespace ns3 {
46 
47 // Note: Logging in this file is largely avoided due to the
48 // number of calls that are made to these functions and the possibility
49 // of causing recursions leading to stack overflow
50 NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorImpl");
51 
52 NS_OBJECT_ENSURE_REGISTERED (RealtimeSimulatorImpl);
53 
54 TypeId
56 {
57  static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
59  .SetGroupName ("Core")
60  .AddConstructor<RealtimeSimulatorImpl> ()
61  .AddAttribute ("SynchronizationMode",
62  "What to do if the simulation cannot keep up with real time.",
65  MakeEnumChecker (SYNC_BEST_EFFORT, "BestEffort",
66  SYNC_HARD_LIMIT, "HardLimit"))
67  .AddAttribute ("HardLimit",
68  "Maximum acceptable real-time jitter (used in conjunction with SynchronizationMode=HardLimit)",
69  TimeValue (Seconds (0.1)),
71  MakeTimeChecker ())
72  ;
73  return tid;
74 }
75 
76 
78 {
79  NS_LOG_FUNCTION (this);
80 
81  m_stop = false;
82  m_running = false;
83  // uids are allocated from 4.
84  // uid 0 is "invalid" events
85  // uid 1 is "now" events
86  // uid 2 is "destroy" events
87  m_uid = 4;
88  // before ::Run is entered, the m_currentUid will be zero
89  m_currentUid = 0;
90  m_currentTs = 0;
93 
95 
96  // Be very careful not to do anything that would cause a change or assignment
97  // of the underlying reference counts of m_synchronizer or you will be sorry.
98  m_synchronizer = CreateObject<WallClockSynchronizer> ();
99 }
100 
102 {
103  NS_LOG_FUNCTION (this);
104 }
105 
106 void
108 {
109  NS_LOG_FUNCTION (this);
110  while (!m_events->IsEmpty ())
111  {
112  Scheduler::Event next = m_events->RemoveNext ();
113  next.impl->Unref ();
114  }
115  m_events = 0;
116  m_synchronizer = 0;
118 }
119 
120 void
122 {
123  NS_LOG_FUNCTION (this);
124 
125  //
126  // This function is only called with the private version "disconnected" from
127  // the main simulator functions. We rely on the user not calling
128  // Simulator::Destroy while there is a chance that a worker thread could be
129  // accessing the current instance of the private object. In practice this
130  // means shutting down the workers and doing a Join() before calling the
131  // Simulator::Destroy().
132  //
133  while (m_destroyEvents.empty () == false)
134  {
135  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
136  m_destroyEvents.pop_front ();
137  NS_LOG_LOGIC ("handle destroy " << ev);
138  if (ev->IsCancelled () == false)
139  {
140  ev->Invoke ();
141  }
142  }
143 }
144 
145 void
147 {
148  NS_LOG_FUNCTION (this << schedulerFactory);
149 
150  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
151 
152  {
154 
155  if (m_events != 0)
156  {
157  while (m_events->IsEmpty () == false)
158  {
159  Scheduler::Event next = m_events->RemoveNext ();
160  scheduler->Insert (next);
161  }
162  }
163  m_events = scheduler;
164  }
165 }
166 
167 void
169 {
170  //
171  // The idea here is to wait until the next event comes due. In the case of
172  // a realtime simulation, we want real time to be consumed between events.
173  // It is the realtime synchronizer that causes real time to be consumed by
174  // doing some kind of a wait.
175  //
176  // We need to be able to have external events (such as a packet reception event)
177  // cause us to re-evaluate our state. The way this works is that the synchronizer
178  // gets interrupted and returns. So, there is a possibility that things may change
179  // out from under us dynamically. In this case, we need to re-evaluate how long to
180  // wait in a for-loop until we have waited sucessfully (until a timeout) for the
181  // event at the head of the event list.
182  //
183  // m_synchronizer->Synchronize will return true if the wait was completed without
184  // interruption, otherwise it will return false indicating that something has changed
185  // out from under us. If we sit in the for-loop trying to synchronize until
186  // Synchronize() returns true, we will have successfully synchronized the execution
187  // time of the next event with the wall clock time of the synchronizer.
188  //
189 
190  for (;;)
191  {
192  uint64_t tsDelay = 0;
193  uint64_t tsNext = 0;
194 
195  //
196  // It is important to understand that m_currentTs is interpreted only as the
197  // timestamp of the last event we executed. Current time can a bit of a
198  // slippery concept in realtime mode. What we have here is a discrete event
199  // simulator, so the last event is, by defintion, executed entirely at a single
200  // discrete time. This is the definition of m_currentTs. It really has
201  // nothing to do with the current real time, except that we are trying to arrange
202  // that at the instant of the beginning of event execution, the current real time
203  // and m_currentTs coincide.
204  //
205  // We use tsNow as the indication of the current real time.
206  //
207  uint64_t tsNow;
208 
209  {
211  //
212  // Since we are in realtime mode, the time to delay has got to be the
213  // difference between the current realtime and the timestamp of the next
214  // event. Since m_currentTs is actually the timestamp of the last event we
215  // executed, it's not particularly meaningful for us here since real time has
216  // certainly elapsed since it was last updated.
217  //
218  // It is possible that the current realtime has drifted past the next event
219  // time so we need to be careful about that and not delay in that case.
220  //
221  NS_ASSERT_MSG (m_synchronizer->Realtime (),
222  "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
223 
224  //
225  // tsNow is set to the normalized current real time. When the simulation was
226  // started, the current real time was effectively set to zero; so tsNow is
227  // the current "real" simulation time.
228  //
229  // tsNext is the simulation time of the next event we want to execute.
230  //
231  tsNow = m_synchronizer->GetCurrentRealtime ();
232  tsNext = NextTs ();
233 
234  //
235  // tsDelay is therefore the real time we need to delay in order to bring the
236  // real time in sync with the simulation time. If we wait for this amount of
237  // real time, we will accomplish moving the simulation time at the same rate
238  // as the real time. This is typically called "pacing" the simulation time.
239  //
240  // We do have to be careful if we are falling behind. If so, tsDelay must be
241  // zero. If we're late, don't dawdle.
242  //
243  if (tsNext <= tsNow)
244  {
245  tsDelay = 0;
246  }
247  else
248  {
249  tsDelay = tsNext - tsNow;
250  }
251 
252  //
253  // We've figured out how long we need to delay in order to pace the
254  // simulation time with the real time. We're going to sleep, but need
255  // to work with the synchronizer to make sure we're awakened if something
256  // external happens (like a packet is received). This next line resets
257  // the synchronizer so that any future event will cause it to interrupt.
258  //
259  m_synchronizer->SetCondition (false);
260  }
261 
262  //
263  // We have a time to delay. This time may actually not be valid anymore
264  // since we released the critical section immediately above, and a real-time
265  // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
266  // closing brace above and this comment so to speak. If this is the case,
267  // that schedule operation will have done a synchronizer Signal() that
268  // will set the condition variable to true and cause the Synchronize call
269  // below to return immediately.
270  //
271  // It's easiest to understand if you just consider a short tsDelay that only
272  // requires a SpinWait down in the synchronizer. What will happen is that
273  // whan Synchronize calls SpinWait, SpinWait will look directly at its
274  // condition variable. Note that we set this condition variable to false
275  // inside the critical section above.
276  //
277  // SpinWait will go into a forever loop until either the time has expired or
278  // until the condition variable becomes true. A true condition indicates that
279  // the wait should stop. The condition is set to true by one of the Schedule
280  // methods of the simulator; so if we are in a wait down in Synchronize, and
281  // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
282  // Synchronize will return false. This means we have not actually synchronized
283  // to the event expiration time. If no real-time schedule operation is done
284  // while down in Synchronize, the wait will time out and Synchronize will return
285  // true. This indicates that we have synchronized to the event time.
286  //
287  // So we need to stay in this for loop, looking for the next event timestamp and
288  // attempting to sleep until its due. If we've slept until the timestamp is due,
289  // Synchronize returns true and we break out of the sync loop. If an external
290  // event happens that requires a re-schedule, Synchronize returns false and
291  // we re-evaluate our timing by continuing in the loop.
292  //
293  // It is expected that tsDelay become shorter as external events interrupt our
294  // waits.
295  //
296  if (m_synchronizer->Synchronize (tsNow, tsDelay))
297  {
298  NS_LOG_LOGIC ("Interrupted ...");
299  break;
300  }
301 
302  //
303  // If we get to this point, we have been interrupted during a wait by a real-time
304  // schedule operation. This means all bets are off regarding tsDelay and we need
305  // to re-evaluate what it is we want to do. We'll loop back around in the
306  // for-loop and start again from scratch.
307  //
308  }
309 
310  //
311  // If we break out of the for-loop above, we have waited until the time specified
312  // by the event that was at the head of the event list when we started the process.
313  // Since there is a bunch of code that was executed outside a critical section (the
314  // Synchronize call) we cannot be sure that the event at the head of the event list
315  // is the one we think it is. What we can be sure of is that it is time to execute
316  // whatever event is at the head of this list if the list is in time order.
317  //
318  Scheduler::Event next;
319 
320  {
322 
323  //
324  // We do know we're waiting for an event, so there had better be an event on the
325  // event queue. Let's pull it off. When we release the critical section, the
326  // event we're working on won't be on the list and so subsequent operations won't
327  // mess with us.
328  //
329  NS_ASSERT_MSG (m_events->IsEmpty () == false,
330  "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
331  next = m_events->RemoveNext ();
333 
334  //
335  // We cannot make any assumption that "next" is the same event we originally waited
336  // for. We can only assume that only that it must be due and cannot cause time
337  // to move backward.
338  //
339  NS_ASSERT_MSG (next.key.m_ts >= m_currentTs,
340  "RealtimeSimulatorImpl::ProcessOneEvent(): "
341  "next.GetTs() earlier than m_currentTs (list order error)");
342  NS_LOG_LOGIC ("handle " << next.key.m_ts);
343 
344  //
345  // Update the current simulation time to be the timestamp of the event we're
346  // executing. From the rest of the simulation's point of view, simulation time
347  // is frozen until the next event is executed.
348  //
349  m_currentTs = next.key.m_ts;
350  m_currentContext = next.key.m_context;
351  m_currentUid = next.key.m_uid;
352 
353  //
354  // We're about to run the event and we've done our best to synchronize this
355  // event execution time to real time. Now, if we're in SYNC_HARD_LIMIT mode
356  // we have to decide if we've done a good enough job and if we haven't, we've
357  // been asked to commit ritual suicide.
358  //
359  // We check the simulation time against the current real time to make this
360  // judgement.
361  //
363  {
364  uint64_t tsFinal = m_synchronizer->GetCurrentRealtime ();
365  uint64_t tsJitter;
366 
367  if (tsFinal >= m_currentTs)
368  {
369  tsJitter = tsFinal - m_currentTs;
370  }
371  else
372  {
373  tsJitter = m_currentTs - tsFinal;
374  }
375 
376  if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep ()))
377  {
378  NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): "
379  "Hard real-time limit exceeded (jitter = " << tsJitter << ")");
380  }
381  }
382  }
383 
384  //
385  // We have got the event we're about to execute completely disentangled from the
386  // event list so we can execute it outside a critical section without fear of someone
387  // changing things out from under us.
388 
389  EventImpl *event = next.impl;
390  m_synchronizer->EventStart ();
391  event->Invoke ();
392  m_synchronizer->EventEnd ();
393  event->Unref ();
394 }
395 
396 bool
398 {
399  bool rc;
400  {
402  rc = m_events->IsEmpty () || m_stop;
403  }
404 
405  return rc;
406 }
407 
408 //
409 // Peeks into event list. Should be called with critical section locked.
410 //
411 uint64_t
413 {
414  NS_ASSERT_MSG (m_events->IsEmpty () == false,
415  "RealtimeSimulatorImpl::NextTs(): event queue is empty");
416  Scheduler::Event ev = m_events->PeekNext ();
417  return ev.key.m_ts;
418 }
419 
420 void
422 {
423  NS_LOG_FUNCTION (this);
424 
425  NS_ASSERT_MSG (m_running == false,
426  "RealtimeSimulatorImpl::Run(): Simulator already running");
427 
428  // Set the current threadId as the main threadId
430 
431  m_stop = false;
432  m_running = true;
433  m_synchronizer->SetOrigin (m_currentTs);
434 
435  // Sleep until signalled
436  uint64_t tsNow;
437  uint64_t tsDelay = 1000000000; // wait time of 1 second (in nanoseconds)
438 
439  while (!m_stop)
440  {
441  bool process = false;
442  {
444 
445  if (!m_events->IsEmpty ())
446  {
447  process = true;
448  }
449  else
450  {
451  // Get current timestamp while holding the critical section
452  tsNow = m_synchronizer->GetCurrentRealtime ();
453  }
454  }
455 
456  if (!process)
457  {
458  // Sleep until signalled
459  tsNow = m_synchronizer->Synchronize (tsNow, tsDelay);
460 
461  // Re-check event queue
462  continue;
463  }
464 
465  ProcessOneEvent ();
466  }
467 
468  //
469  // If the simulator stopped naturally by lack of events, make a
470  // consistency test to check that we didn't lose any events along the way.
471  //
472  {
474 
475  NS_ASSERT_MSG (m_events->IsEmpty () == false || m_unscheduledEvents == 0,
476  "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events");
477  }
478 
479  m_running = false;
480 }
481 
482 bool
484 {
485  return m_running;
486 }
487 
488 bool
490 {
491  return m_synchronizer->Realtime ();
492 }
493 
494 void
496 {
497  NS_LOG_FUNCTION (this);
498  m_stop = true;
499 }
500 
501 void
503 {
504  NS_LOG_FUNCTION (this << delay);
506 }
507 
508 //
509 // Schedule an event for a _relative_ time in the future.
510 //
511 EventId
513 {
514  NS_LOG_FUNCTION (this << delay << impl);
515 
516  Scheduler::Event ev;
517  {
519  //
520  // This is the reason we had to bring the absolute time calcualtion in from the
521  // simulator.h into the implementation. Since the implementations may be
522  // multi-threaded, we need this calculation to be atomic. You can see it is
523  // here since we are running in a CriticalSection.
524  //
525  Time tAbsolute = Simulator::Now () + delay;
526  NS_ASSERT_MSG (tAbsolute.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative time");
527  NS_ASSERT_MSG (tAbsolute >= TimeStep (m_currentTs), "RealtimeSimulatorImpl::Schedule(): time < m_currentTs");
528  ev.impl = impl;
529  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
530  ev.key.m_context = GetContext ();
531  ev.key.m_uid = m_uid;
532  m_uid++;
534  m_events->Insert (ev);
535  m_synchronizer->Signal ();
536  }
537 
538  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
539 }
540 
541 void
542 RealtimeSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *impl)
543 {
544  NS_LOG_FUNCTION (this << context << delay << impl);
545 
546  {
548  uint64_t ts;
549 
551  {
552  ts = m_currentTs + delay.GetTimeStep ();
553  }
554  else
555  {
556  //
557  // If the simulator is running, we're pacing and have a meaningful
558  // realtime clock. If we're not, then m_currentTs is where we stopped.
559  //
560  ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
561  ts += delay.GetTimeStep ();
562  }
563 
564  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
565  Scheduler::Event ev;
566  ev.impl = impl;
567  ev.key.m_ts = ts;
568  ev.key.m_context = context;
569  ev.key.m_uid = m_uid;
570  m_uid++;
572  m_events->Insert (ev);
573  m_synchronizer->Signal ();
574  }
575 }
576 
577 EventId
579 {
580  NS_LOG_FUNCTION (this << impl);
581  Scheduler::Event ev;
582  {
584 
585  ev.impl = impl;
586  ev.key.m_ts = m_currentTs;
587  ev.key.m_context = GetContext ();
588  ev.key.m_uid = m_uid;
589  m_uid++;
591  m_events->Insert (ev);
592  m_synchronizer->Signal ();
593  }
594 
595  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
596 }
597 
598 Time
600 {
601  return TimeStep (m_currentTs);
602 }
603 
604 //
605 // Schedule an event for a _relative_ time in the future.
606 //
607 void
609 {
610  NS_LOG_FUNCTION (this << context << time << impl);
611 
612  {
614 
615  uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
616  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
617  Scheduler::Event ev;
618  ev.impl = impl;
619  ev.key.m_ts = ts;
620  ev.key.m_uid = m_uid;
621  m_uid++;
623  m_events->Insert (ev);
624  m_synchronizer->Signal ();
625  }
626 }
627 
628 void
630 {
631  NS_LOG_FUNCTION (this << time << impl);
632  ScheduleRealtimeWithContext (GetContext (), time, impl);
633 }
634 
635 void
637 {
638  NS_LOG_FUNCTION (this << context << impl);
639  {
641 
642  //
643  // If the simulator is running, we're pacing and have a meaningful
644  // realtime clock. If we're not, then m_currentTs is were we stopped.
645  //
646  uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
647  NS_ASSERT_MSG (ts >= m_currentTs,
648  "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
649  Scheduler::Event ev;
650  ev.impl = impl;
651  ev.key.m_ts = ts;
652  ev.key.m_uid = m_uid;
653  ev.key.m_context = context;
654  m_uid++;
656  m_events->Insert (ev);
657  m_synchronizer->Signal ();
658  }
659 }
660 
661 void
663 {
664  NS_LOG_FUNCTION (this << impl);
666 }
667 
668 Time
670 {
671  return TimeStep (m_synchronizer->GetCurrentRealtime ());
672 }
673 
674 EventId
676 {
677  NS_LOG_FUNCTION (this << impl);
678 
679  EventId id;
680  {
682 
683  //
684  // Time doesn't really matter here (especially in realtime mode). It is
685  // overridden by the uid of 2 which identifies this as an event to be
686  // executed at Simulator::Destroy time.
687  //
688  id = EventId (Ptr<EventImpl> (impl, false), m_currentTs, 0xffffffff, 2);
689  m_destroyEvents.push_back (id);
690  m_uid++;
691  }
692 
693  return id;
694 }
695 
696 Time
698 {
699  //
700  // If the event has expired, there is no delay until it runs. It is not the
701  // case that there is a negative time until it runs.
702  //
703  if (IsExpired (id))
704  {
705  return TimeStep (0);
706  }
707 
708  return TimeStep (id.GetTs () - m_currentTs);
709 }
710 
711 void
713 {
714  if (id.GetUid () == 2)
715  {
716  // destroy events.
717  for (DestroyEvents::iterator i = m_destroyEvents.begin ();
718  i != m_destroyEvents.end ();
719  i++)
720  {
721  if (*i == id)
722  {
723  m_destroyEvents.erase (i);
724  break;
725  }
726  }
727  return;
728  }
729  if (IsExpired (id))
730  {
731  return;
732  }
733 
734  {
736 
737  Scheduler::Event event;
738  event.impl = id.PeekEventImpl ();
739  event.key.m_ts = id.GetTs ();
740  event.key.m_context = id.GetContext ();
741  event.key.m_uid = id.GetUid ();
742 
743  m_events->Remove (event);
745  event.impl->Cancel ();
746  event.impl->Unref ();
747  }
748 }
749 
750 void
752 {
753  if (IsExpired (id) == false)
754  {
755  id.PeekEventImpl ()->Cancel ();
756  }
757 }
758 
759 bool
761 {
762  if (id.GetUid () == 2)
763  {
764  if (id.PeekEventImpl () == 0 ||
765  id.PeekEventImpl ()->IsCancelled ())
766  {
767  return true;
768  }
769  // destroy events.
770  for (DestroyEvents::const_iterator i = m_destroyEvents.begin ();
771  i != m_destroyEvents.end (); i++)
772  {
773  if (*i == id)
774  {
775  return false;
776  }
777  }
778  return true;
779  }
780 
781  //
782  // If the time of the event is less than the current timestamp of the
783  // simulator, the simulator has gone past the invocation time of the
784  // event, so the statement ev.GetTs () < m_currentTs does mean that
785  // the event has been fired even in realtime mode.
786  //
787  // The same is true for the next line involving the m_currentUid.
788  //
789  if (id.PeekEventImpl () == 0 ||
790  id.GetTs () < m_currentTs ||
791  (id.GetTs () == m_currentTs && id.GetUid () <= m_currentUid) ||
792  id.PeekEventImpl ()->IsCancelled ())
793  {
794  return true;
795  }
796  else
797  {
798  return false;
799  }
800 }
801 
802 Time
804 {
807  return TimeStep (0x7fffffffffffffffLL);
808 }
809 
810 // System ID for non-distributed simulation is always zero
811 uint32_t
813 {
814  return 0;
815 }
816 
817 uint32_t
819 {
820  return m_currentContext;
821 }
822 
823 void
825 {
826  NS_LOG_FUNCTION (this << mode);
827  m_synchronizationMode = mode;
828 }
829 
832 {
833  NS_LOG_FUNCTION (this);
834  return m_synchronizationMode;
835 }
836 
837 void
839 {
840  NS_LOG_FUNCTION (this << limit);
841  m_hardLimit = limit;
842 }
843 
844 Time
846 {
847  NS_LOG_FUNCTION (this);
848  return m_hardLimit;
849 }
850 
851 } // namespace ns3
NS_FATAL_x macro definitions.
Boolean attribute value declarations.
void ProcessOneEvent(void)
Process the next event.
void ScheduleRealtimeNowWithContext(uint32_t context, EventImpl *event)
Schedule an event to run at the current virtual time.
void SetSynchronizationMode(RealtimeSimulatorImpl::SynchronizationMode mode)
Set the SynchronizationMode.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
Ptr< Synchronizer > m_synchronizer
The synchronizer in use to track real time.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
bool IsPositive(void) const
Definition: nstime.h:284
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
ns3::EventImpl declarations.
uint64_t NextTs(void) const
Get the timestep of the next event.
virtual EventId ScheduleNow(EventImpl *event)
Schedule an event to run at the current virtual time.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
SystemThread::ThreadId m_main
Main SystemThread.
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:81
int m_unscheduledEvents
Unique id for the next event to be scheduled.
Smart pointer implementation.
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: enum.h:209
void ScheduleRealtimeWithContext(uint32_t context, const Time &delay, EventImpl *event)
Schedule a future event execution (in a different context).
void ScheduleRealtimeNow(EventImpl *event)
Schedule an event to run at the current virtual time.
static ThreadId Self(void)
Returns the current thread Id.
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:94
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
Time RealtimeNow(void) const
Get the current real time from the synchronizer.
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
Time m_hardLimit
The maximum allowable drift from real-time in SYNC_HARD_LIMIT mode.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
ns3::Simulator declaration.
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
Time GetHardLimit(void) const
Get the current fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
SynchronizationMode m_synchronizationMode
SynchronizationMode policy.
bool m_running
Is the simulator currently running.
DestroyEvents m_destroyEvents
Container for events to be run at destroy time.
virtual EventId Schedule(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
virtual void DoDispose(void)
Destructor implementation.
virtual EventId ScheduleDestroy(EventImpl *event)
Schedule an event to run at the end of the simulation, after the Stop() time or condition has been re...
Ptr< Scheduler > m_events
The event list.
RealtimeSimulatorImpl::SynchronizationMode GetSynchronizationMode(void) const
Get the SynchronizationMode.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:446
uint32_t m_currentUid
Timestep of the current event.
System-independent mutex primitive, ns3::SystemMutex, and ns3::CriticalSection.
static TypeId GetTypeId(void)
Get the registered TypeId for this class.
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations...
SynchronizationMode
What to do when we can't maintain real time synchrony.
Hold variables of type enum.
Definition: enum.h:54
static EventId Schedule(Time const &delay, MEM mem_ptr, OBJ obj)
Schedule an event to expire after delay.
Definition: simulator.h:1238
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:95
SystemMutex m_mutex
Mutex to control access to key state.
AttributeValue implementation for Time.
Definition: nstime.h:957
virtual Time Now(void) const
Return the current simulation virtual time.
virtual void Run(void)
Run the simulation.
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:118
uint32_t m_uid
Event unique id.
Definition: scheduler.h:82
Definition of assertion macros NS_ASSERT() and NS_ASSERT_MSG().
virtual void Destroy()
Execute the events scheduled with ScheduleDestroy().
bool m_stop
Has the stopping condition been reached?
void ScheduleRealtime(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
void Unref(void) const
Decrement the reference count.
Enum attribute value declarations.
virtual void Remove(const EventId &ev)
Remove an event from the event list.
ns3::WallClockSynchronizer declaration.
Realtime version of SimulatorImpl.
uint32_t m_uid
Unique id of the current event.
Maintain the event list.
Definition: scheduler.h:66
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
virtual void Cancel(const EventId &ev)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
virtual void ScheduleWithContext(uint32_t context, const Time &delay, EventImpl *event)
Schedule a future event execution (in a different context).
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
Scheduler event.
Definition: scheduler.h:92
Every class exported by the ns3 library is enclosed in the ns3 namespace.
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
void SetHardLimit(Time limit)
Set the fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:377
Time TimeStep(uint64_t ts)
Definition: nstime.h:952
ns3::RealTimeSimulatorImpl declaration.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: nstime.h:958
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:224
ns3::Synchronizer declaration.
Flag for events not associated with any particular context.
Definition: simulator.h:192
uint64_t m_currentTs
Execution context.
static bool Equals(ThreadId id)
Compares an ThreadId with the current ThreadId .
virtual bool IsExpired(const EventId &ev) const
Check if an event has already run or been cancelled.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:90
virtual void SetScheduler(ObjectFactory schedulerFactory)
Set the Scheduler to be used to manage the event list.
Ptr< const AttributeChecker > MakeEnumChecker(int v1, std::string n1, int v2, std::string n2, int v3, std::string n3, int v4, std::string n4, int v5, std::string n5, int v6, std::string n6, int v7, std::string n7, int v8, std::string n8, int v9, std::string n9, int v10, std::string n10, int v11, std::string n11, int v12, std::string n12, int v13, std::string n13, int v14, std::string n14, int v15, std::string n15, int v16, std::string n16, int v17, std::string n17, int v18, std::string n18, int v19, std::string n19, int v20, std::string n20, int v21, std::string n21, int v22, std::string n22)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.cc:184
Instantiate subclasses of ns3::Object.
A simulation event.
Definition: event-impl.h:44
An identifier for simulation events.
Definition: event-id.h:53
static void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:209
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:895
bool Running(void) const
Is the simulator running?
bool Realtime(void) const
Check that the Synchronizer is locked to the real time clock.
virtual uint32_t GetContext(void) const
Get the current simulation context.
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Debug message logging.
virtual bool IsFinished(void) const
Check if the simulation should finish.
Pointer attribute value declarations and template implementations.
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904
Make a best effort to keep synced to real-time.
uint32_t m_currentContext
The event list.
uint32_t m_context
Event context.
Definition: scheduler.h:83
Keep to real time within the hard limit tolerance configured with SetHardLimit, or die trying...
The SimulatorImpl base class.