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  m_eventCount = 0;
94 
96 
97  // Be very careful not to do anything that would cause a change or assignment
98  // of the underlying reference counts of m_synchronizer or you will be sorry.
99  m_synchronizer = CreateObject<WallClockSynchronizer> ();
100 }
101 
103 {
104  NS_LOG_FUNCTION (this);
105 }
106 
107 void
109 {
110  NS_LOG_FUNCTION (this);
111  while (!m_events->IsEmpty ())
112  {
113  Scheduler::Event next = m_events->RemoveNext ();
114  next.impl->Unref ();
115  }
116  m_events = 0;
117  m_synchronizer = 0;
119 }
120 
121 void
123 {
124  NS_LOG_FUNCTION (this);
125 
126  //
127  // This function is only called with the private version "disconnected" from
128  // the main simulator functions. We rely on the user not calling
129  // Simulator::Destroy while there is a chance that a worker thread could be
130  // accessing the current instance of the private object. In practice this
131  // means shutting down the workers and doing a Join() before calling the
132  // Simulator::Destroy().
133  //
134  while (m_destroyEvents.empty () == false)
135  {
136  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
137  m_destroyEvents.pop_front ();
138  NS_LOG_LOGIC ("handle destroy " << ev);
139  if (ev->IsCancelled () == false)
140  {
141  ev->Invoke ();
142  }
143  }
144 }
145 
146 void
148 {
149  NS_LOG_FUNCTION (this << schedulerFactory);
150 
151  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
152 
153  {
155 
156  if (m_events != 0)
157  {
158  while (m_events->IsEmpty () == false)
159  {
160  Scheduler::Event next = m_events->RemoveNext ();
161  scheduler->Insert (next);
162  }
163  }
164  m_events = scheduler;
165  }
166 }
167 
168 void
170 {
171  //
172  // The idea here is to wait until the next event comes due. In the case of
173  // a realtime simulation, we want real time to be consumed between events.
174  // It is the realtime synchronizer that causes real time to be consumed by
175  // doing some kind of a wait.
176  //
177  // We need to be able to have external events (such as a packet reception event)
178  // cause us to re-evaluate our state. The way this works is that the synchronizer
179  // gets interrupted and returns. So, there is a possibility that things may change
180  // out from under us dynamically. In this case, we need to re-evaluate how long to
181  // wait in a for-loop until we have waited successfully (until a timeout) for the
182  // event at the head of the event list.
183  //
184  // m_synchronizer->Synchronize will return true if the wait was completed without
185  // interruption, otherwise it will return false indicating that something has changed
186  // out from under us. If we sit in the for-loop trying to synchronize until
187  // Synchronize() returns true, we will have successfully synchronized the execution
188  // time of the next event with the wall clock time of the synchronizer.
189  //
190 
191  for (;;)
192  {
193  uint64_t tsDelay = 0;
194  uint64_t tsNext = 0;
195 
196  //
197  // It is important to understand that m_currentTs is interpreted only as the
198  // timestamp of the last event we executed. Current time can a bit of a
199  // slippery concept in realtime mode. What we have here is a discrete event
200  // simulator, so the last event is, by definition, executed entirely at a single
201  // discrete time. This is the definition of m_currentTs. It really has
202  // nothing to do with the current real time, except that we are trying to arrange
203  // that at the instant of the beginning of event execution, the current real time
204  // and m_currentTs coincide.
205  //
206  // We use tsNow as the indication of the current real time.
207  //
208  uint64_t tsNow;
209 
210  {
212  //
213  // Since we are in realtime mode, the time to delay has got to be the
214  // difference between the current realtime and the timestamp of the next
215  // event. Since m_currentTs is actually the timestamp of the last event we
216  // executed, it's not particularly meaningful for us here since real time has
217  // certainly elapsed since it was last updated.
218  //
219  // It is possible that the current realtime has drifted past the next event
220  // time so we need to be careful about that and not delay in that case.
221  //
222  NS_ASSERT_MSG (m_synchronizer->Realtime (),
223  "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
224 
225  //
226  // tsNow is set to the normalized current real time. When the simulation was
227  // started, the current real time was effectively set to zero; so tsNow is
228  // the current "real" simulation time.
229  //
230  // tsNext is the simulation time of the next event we want to execute.
231  //
232  tsNow = m_synchronizer->GetCurrentRealtime ();
233  tsNext = NextTs ();
234 
235  //
236  // tsDelay is therefore the real time we need to delay in order to bring the
237  // real time in sync with the simulation time. If we wait for this amount of
238  // real time, we will accomplish moving the simulation time at the same rate
239  // as the real time. This is typically called "pacing" the simulation time.
240  //
241  // We do have to be careful if we are falling behind. If so, tsDelay must be
242  // zero. If we're late, don't dawdle.
243  //
244  if (tsNext <= tsNow)
245  {
246  tsDelay = 0;
247  }
248  else
249  {
250  tsDelay = tsNext - tsNow;
251  }
252 
253  //
254  // We've figured out how long we need to delay in order to pace the
255  // simulation time with the real time. We're going to sleep, but need
256  // to work with the synchronizer to make sure we're awakened if something
257  // external happens (like a packet is received). This next line resets
258  // the synchronizer so that any future event will cause it to interrupt.
259  //
260  m_synchronizer->SetCondition (false);
261  }
262 
263  //
264  // We have a time to delay. This time may actually not be valid anymore
265  // since we released the critical section immediately above, and a real-time
266  // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
267  // closing brace above and this comment so to speak. If this is the case,
268  // that schedule operation will have done a synchronizer Signal() that
269  // will set the condition variable to true and cause the Synchronize call
270  // below to return immediately.
271  //
272  // It's easiest to understand if you just consider a short tsDelay that only
273  // requires a SpinWait down in the synchronizer. What will happen is that
274  // whan Synchronize calls SpinWait, SpinWait will look directly at its
275  // condition variable. Note that we set this condition variable to false
276  // inside the critical section above.
277  //
278  // SpinWait will go into a forever loop until either the time has expired or
279  // until the condition variable becomes true. A true condition indicates that
280  // the wait should stop. The condition is set to true by one of the Schedule
281  // methods of the simulator; so if we are in a wait down in Synchronize, and
282  // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
283  // Synchronize will return false. This means we have not actually synchronized
284  // to the event expiration time. If no real-time schedule operation is done
285  // while down in Synchronize, the wait will time out and Synchronize will return
286  // true. This indicates that we have synchronized to the event time.
287  //
288  // So we need to stay in this for loop, looking for the next event timestamp and
289  // attempting to sleep until its due. If we've slept until the timestamp is due,
290  // Synchronize returns true and we break out of the sync loop. If an external
291  // event happens that requires a re-schedule, Synchronize returns false and
292  // we re-evaluate our timing by continuing in the loop.
293  //
294  // It is expected that tsDelay become shorter as external events interrupt our
295  // waits.
296  //
297  if (m_synchronizer->Synchronize (tsNow, tsDelay))
298  {
299  NS_LOG_LOGIC ("Interrupted ...");
300  break;
301  }
302 
303  //
304  // If we get to this point, we have been interrupted during a wait by a real-time
305  // schedule operation. This means all bets are off regarding tsDelay and we need
306  // to re-evaluate what it is we want to do. We'll loop back around in the
307  // for-loop and start again from scratch.
308  //
309  }
310 
311  //
312  // If we break out of the for-loop above, we have waited until the time specified
313  // by the event that was at the head of the event list when we started the process.
314  // Since there is a bunch of code that was executed outside a critical section (the
315  // Synchronize call) we cannot be sure that the event at the head of the event list
316  // is the one we think it is. What we can be sure of is that it is time to execute
317  // whatever event is at the head of this list if the list is in time order.
318  //
319  Scheduler::Event next;
320 
321  {
323 
324  //
325  // We do know we're waiting for an event, so there had better be an event on the
326  // event queue. Let's pull it off. When we release the critical section, the
327  // event we're working on won't be on the list and so subsequent operations won't
328  // mess with us.
329  //
330  NS_ASSERT_MSG (m_events->IsEmpty () == false,
331  "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
332  next = m_events->RemoveNext ();
334  m_eventCount++;
335 
336  //
337  // We cannot make any assumption that "next" is the same event we originally waited
338  // for. We can only assume that only that it must be due and cannot cause time
339  // to move backward.
340  //
341  NS_ASSERT_MSG (next.key.m_ts >= m_currentTs,
342  "RealtimeSimulatorImpl::ProcessOneEvent(): "
343  "next.GetTs() earlier than m_currentTs (list order error)");
344  NS_LOG_LOGIC ("handle " << next.key.m_ts);
345 
346  //
347  // Update the current simulation time to be the timestamp of the event we're
348  // executing. From the rest of the simulation's point of view, simulation time
349  // is frozen until the next event is executed.
350  //
351  m_currentTs = next.key.m_ts;
352  m_currentContext = next.key.m_context;
353  m_currentUid = next.key.m_uid;
354 
355  //
356  // We're about to run the event and we've done our best to synchronize this
357  // event execution time to real time. Now, if we're in SYNC_HARD_LIMIT mode
358  // we have to decide if we've done a good enough job and if we haven't, we've
359  // been asked to commit ritual suicide.
360  //
361  // We check the simulation time against the current real time to make this
362  // judgement.
363  //
365  {
366  uint64_t tsFinal = m_synchronizer->GetCurrentRealtime ();
367  uint64_t tsJitter;
368 
369  if (tsFinal >= m_currentTs)
370  {
371  tsJitter = tsFinal - m_currentTs;
372  }
373  else
374  {
375  tsJitter = m_currentTs - tsFinal;
376  }
377 
378  if (tsJitter > static_cast<uint64_t> (m_hardLimit.GetTimeStep ()))
379  {
380  NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): "
381  "Hard real-time limit exceeded (jitter = " << tsJitter << ")");
382  }
383  }
384  }
385 
386  //
387  // We have got the event we're about to execute completely disentangled from the
388  // event list so we can execute it outside a critical section without fear of someone
389  // changing things out from under us.
390 
391  EventImpl *event = next.impl;
392  m_synchronizer->EventStart ();
393  event->Invoke ();
394  m_synchronizer->EventEnd ();
395  event->Unref ();
396 }
397 
398 bool
400 {
401  bool rc;
402  {
404  rc = m_events->IsEmpty () || m_stop;
405  }
406 
407  return rc;
408 }
409 
410 //
411 // Peeks into event list. Should be called with critical section locked.
412 //
413 uint64_t
415 {
416  NS_ASSERT_MSG (m_events->IsEmpty () == false,
417  "RealtimeSimulatorImpl::NextTs(): event queue is empty");
418  Scheduler::Event ev = m_events->PeekNext ();
419  return ev.key.m_ts;
420 }
421 
422 void
424 {
425  NS_LOG_FUNCTION (this);
426 
427  NS_ASSERT_MSG (m_running == false,
428  "RealtimeSimulatorImpl::Run(): Simulator already running");
429 
430  // Set the current threadId as the main threadId
432 
433  m_stop = false;
434  m_running = true;
435  m_synchronizer->SetOrigin (m_currentTs);
436 
437  // Sleep until signalled
438  uint64_t tsNow = 0;
439  uint64_t tsDelay = 1000000000; // wait time of 1 second (in nanoseconds)
440 
441  while (!m_stop)
442  {
443  bool process = false;
444  {
446 
447  if (!m_events->IsEmpty ())
448  {
449  process = true;
450  }
451  else
452  {
453  // Get current timestamp while holding the critical section
454  tsNow = m_synchronizer->GetCurrentRealtime ();
455  }
456  }
457 
458  if (!process)
459  {
460  // Sleep until signalled
461  tsNow = m_synchronizer->Synchronize (tsNow, tsDelay);
462 
463  // Re-check event queue
464  continue;
465  }
466 
467  ProcessOneEvent ();
468  }
469 
470  //
471  // If the simulator stopped naturally by lack of events, make a
472  // consistency test to check that we didn't lose any events along the way.
473  //
474  {
476 
477  NS_ASSERT_MSG (m_events->IsEmpty () == false || m_unscheduledEvents == 0,
478  "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events");
479  }
480 
481  m_running = false;
482 }
483 
484 bool
486 {
487  return m_running;
488 }
489 
490 bool
492 {
493  return m_synchronizer->Realtime ();
494 }
495 
496 void
498 {
499  NS_LOG_FUNCTION (this);
500  m_stop = true;
501 }
502 
503 void
505 {
506  NS_LOG_FUNCTION (this << delay);
508 }
509 
510 //
511 // Schedule an event for a _relative_ time in the future.
512 //
513 EventId
515 {
516  NS_LOG_FUNCTION (this << delay << impl);
517 
518  Scheduler::Event ev;
519  {
521  //
522  // This is the reason we had to bring the absolute time calculation in from the
523  // simulator.h into the implementation. Since the implementations may be
524  // multi-threaded, we need this calculation to be atomic. You can see it is
525  // here since we are running in a CriticalSection.
526  //
527  Time tAbsolute = Simulator::Now () + delay;
528  NS_ASSERT_MSG (delay.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative delay");
529  ev.impl = impl;
530  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
531  ev.key.m_context = GetContext ();
532  ev.key.m_uid = m_uid;
533  m_uid++;
535  m_events->Insert (ev);
536  m_synchronizer->Signal ();
537  }
538 
539  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
540 }
541 
542 void
543 RealtimeSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *impl)
544 {
545  NS_LOG_FUNCTION (this << context << delay << impl);
546 
547  {
549  uint64_t ts;
550 
552  {
553  ts = m_currentTs + delay.GetTimeStep ();
554  }
555  else
556  {
557  //
558  // If the simulator is running, we're pacing and have a meaningful
559  // realtime clock. If we're not, then m_currentTs is where we stopped.
560  //
561  ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
562  ts += delay.GetTimeStep ();
563  }
564 
565  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
566  Scheduler::Event ev;
567  ev.impl = impl;
568  ev.key.m_ts = ts;
569  ev.key.m_context = context;
570  ev.key.m_uid = m_uid;
571  m_uid++;
573  m_events->Insert (ev);
574  m_synchronizer->Signal ();
575  }
576 }
577 
578 EventId
580 {
581  NS_LOG_FUNCTION (this << impl);
582  Scheduler::Event ev;
583  {
585 
586  ev.impl = impl;
587  ev.key.m_ts = m_currentTs;
588  ev.key.m_context = GetContext ();
589  ev.key.m_uid = m_uid;
590  m_uid++;
592  m_events->Insert (ev);
593  m_synchronizer->Signal ();
594  }
595 
596  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
597 }
598 
599 Time
601 {
602  return TimeStep (m_currentTs);
603 }
604 
605 //
606 // Schedule an event for a _relative_ time in the future.
607 //
608 void
610 {
611  NS_LOG_FUNCTION (this << context << time << impl);
612 
613  {
615 
616  uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
617  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
618  Scheduler::Event ev;
619  ev.impl = impl;
620  ev.key.m_ts = ts;
621  ev.key.m_uid = m_uid;
622  m_uid++;
624  m_events->Insert (ev);
625  m_synchronizer->Signal ();
626  }
627 }
628 
629 void
631 {
632  NS_LOG_FUNCTION (this << time << impl);
633  ScheduleRealtimeWithContext (GetContext (), time, impl);
634 }
635 
636 void
638 {
639  NS_LOG_FUNCTION (this << context << impl);
640  {
642 
643  //
644  // If the simulator is running, we're pacing and have a meaningful
645  // realtime clock. If we're not, then m_currentTs is were we stopped.
646  //
647  uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
648  NS_ASSERT_MSG (ts >= m_currentTs,
649  "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
650  Scheduler::Event ev;
651  ev.impl = impl;
652  ev.key.m_ts = ts;
653  ev.key.m_uid = m_uid;
654  ev.key.m_context = context;
655  m_uid++;
657  m_events->Insert (ev);
658  m_synchronizer->Signal ();
659  }
660 }
661 
662 void
664 {
665  NS_LOG_FUNCTION (this << impl);
667 }
668 
669 Time
671 {
672  return TimeStep (m_synchronizer->GetCurrentRealtime ());
673 }
674 
675 EventId
677 {
678  NS_LOG_FUNCTION (this << impl);
679 
680  EventId id;
681  {
683 
684  //
685  // Time doesn't really matter here (especially in realtime mode). It is
686  // overridden by the uid of 2 which identifies this as an event to be
687  // executed at Simulator::Destroy time.
688  //
689  id = EventId (Ptr<EventImpl> (impl, false), m_currentTs, 0xffffffff, 2);
690  m_destroyEvents.push_back (id);
691  m_uid++;
692  }
693 
694  return id;
695 }
696 
697 Time
699 {
700  //
701  // If the event has expired, there is no delay until it runs. It is not the
702  // case that there is a negative time until it runs.
703  //
704  if (IsExpired (id))
705  {
706  return TimeStep (0);
707  }
708 
709  return TimeStep (id.GetTs () - m_currentTs);
710 }
711 
712 void
714 {
715  if (id.GetUid () == 2)
716  {
717  // destroy events.
718  for (DestroyEvents::iterator i = m_destroyEvents.begin ();
719  i != m_destroyEvents.end ();
720  i++)
721  {
722  if (*i == id)
723  {
724  m_destroyEvents.erase (i);
725  break;
726  }
727  }
728  return;
729  }
730  if (IsExpired (id))
731  {
732  return;
733  }
734 
735  {
737 
738  Scheduler::Event event;
739  event.impl = id.PeekEventImpl ();
740  event.key.m_ts = id.GetTs ();
741  event.key.m_context = id.GetContext ();
742  event.key.m_uid = id.GetUid ();
743 
744  m_events->Remove (event);
746  event.impl->Cancel ();
747  event.impl->Unref ();
748  }
749 }
750 
751 void
753 {
754  if (IsExpired (id) == false)
755  {
756  id.PeekEventImpl ()->Cancel ();
757  }
758 }
759 
760 bool
762 {
763  if (id.GetUid () == 2)
764  {
765  if (id.PeekEventImpl () == 0 ||
766  id.PeekEventImpl ()->IsCancelled ())
767  {
768  return true;
769  }
770  // destroy events.
771  for (DestroyEvents::const_iterator i = m_destroyEvents.begin ();
772  i != m_destroyEvents.end (); i++)
773  {
774  if (*i == id)
775  {
776  return false;
777  }
778  }
779  return true;
780  }
781 
782  //
783  // If the time of the event is less than the current timestamp of the
784  // simulator, the simulator has gone past the invocation time of the
785  // event, so the statement ev.GetTs () < m_currentTs does mean that
786  // the event has been fired even in realtime mode.
787  //
788  // The same is true for the next line involving the m_currentUid.
789  //
790  if (id.PeekEventImpl () == 0 ||
791  id.GetTs () < m_currentTs ||
792  (id.GetTs () == m_currentTs && id.GetUid () <= m_currentUid) ||
793  id.PeekEventImpl ()->IsCancelled ())
794  {
795  return true;
796  }
797  else
798  {
799  return false;
800  }
801 }
802 
803 Time
805 {
806  return TimeStep (0x7fffffffffffffffLL);
807 }
808 
809 // System ID for non-distributed simulation is always zero
810 uint32_t
812 {
813  return 0;
814 }
815 
816 uint32_t
818 {
819  return m_currentContext;
820 }
821 
822 uint64_t
824 {
825  return m_eventCount;
826 }
827 
828 void
830 {
831  NS_LOG_FUNCTION (this << mode);
832  m_synchronizationMode = mode;
833 }
834 
837 {
838  NS_LOG_FUNCTION (this);
839  return m_synchronizationMode;
840 }
841 
842 void
844 {
845  NS_LOG_FUNCTION (this << limit);
846  m_hardLimit = limit;
847 }
848 
849 Time
851 {
852  NS_LOG_FUNCTION (this);
853  return m_hardLimit;
854 }
855 
856 } // namespace ns3
NS_FATAL_x macro definitions.
ns3::BooleanValue attribute value declarations.
void ProcessOneEvent(void)
Process the next event.
Time GetHardLimit(void) const
Get the current fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
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
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
ns3::EventImpl declarations.
void Unref(void) const
Decrement the reference count.
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:45
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
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.
ns3::Ptr smart pointer declaration and 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).
virtual Time Now(void) const
Return the current simulation virtual time.
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:204
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
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).
uint64_t m_eventCount
The event count.
virtual uint32_t GetContext(void) const
Get the current simulation 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.
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.
Keep to real time within the hard limit tolerance configured with SetHardLimit, or die trying...
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations...
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:1389
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:1124
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
virtual void Run(void)
Run the simulation.
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
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
virtual void Destroy()
Execute the events scheduled with ScheduleDestroy().
bool m_stop
Has the stopping condition been reached?
bool Running(void) const
Is the simulator running?
void ScheduleRealtime(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
ns3::EnumValue attribute value declarations.
virtual void Remove(const EventId &ev)
Remove an event from the event list.
ns3::WallClockSynchronizer declaration.
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
Realtime version of SimulatorImpl.
uint32_t m_uid
Unique id of the current event.
Maintain the event list.
Definition: scheduler.h:66
uint64_t NextTs(void) const
Get the timestep of the next event.
virtual void Cancel(const EventId &ev)
Set the cancel bit on this event: the event&#39;s associated function will not be invoked when it expires...
SynchronizationMode
What to do when we can&#39;t maintain real time synchrony.
virtual void ScheduleWithContext(uint32_t context, const Time &delay, EventImpl *event)
Schedule a future event execution (in a different context).
bool Realtime(void) const
Check that the Synchronizer is locked to the real time clock.
Scheduler event.
Definition: scheduler.h:92
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time RealtimeNow(void) const
Get the current real time from the synchronizer.
void SetHardLimit(Time limit)
Set the fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
Time TimeStep(uint64_t ts)
Definition: nstime.h:1119
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:1125
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:193
ns3::Synchronizer declaration.
NS_LOG_LOGIC("Net device "<< nd<< " is not bridged")
uint64_t m_currentTs
Execution context.
RealtimeSimulatorImpl::SynchronizationMode GetSynchronizationMode(void) const
Get the SynchronizationMode.
static bool Equals(ThreadId id)
Compares an ThreadId with the current ThreadId .
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:178
bool IsPositive(void) const
Definition: nstime.h:298
Make a best effort to keep synced to real-time.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1062
Flag for events not associated with any particular context.
Definition: simulator.h:198
virtual uint64_t GetEventCount(void) const
Get the number of events executed.
virtual bool IsFinished(void) const
Check if the simulation should finish.
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Debug message logging.
virtual bool IsExpired(const EventId &ev) const
Check if an event has already run or been cancelled.
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
ns3::PointerValue 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:915
uint32_t m_currentContext
The event list.
uint32_t m_context
Event context.
Definition: scheduler.h:83
The SimulatorImpl base class.
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:391
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.