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;
91  m_currentContext = 0xffffffff;
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 << time);
506 }
507 
508 //
509 // Schedule an event for a _relative_ time in the future.
510 //
511 EventId
513 {
514  NS_LOG_FUNCTION (this << time << 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 () + time;
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 &time, EventImpl *impl)
543 {
544  NS_LOG_FUNCTION (this << context << time << impl);
545 
546  {
548  uint64_t ts;
549 
551  {
552  ts = m_currentTs + time.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 += time.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:286
#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
virtual EventId Schedule(Time const &time, EventImpl *event)
Schedule a future event execution (in the same context).
SystemThread::ThreadId m_main
Main SystemThread.
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:77
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 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:90
#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.
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:339
#define NS_FATAL_ERROR(msg)
Fatal error handling.
Definition: fatal-error.h:100
ns3::Simulator declaration.
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.
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Schedule an event to expire at the relative time "time" is reached.
Definition: simulator.h:819
void ScheduleRealtimeWithContext(uint32_t context, Time const &time, EventImpl *event)
Schedule a future event execution (in a different context).
DestroyEvents m_destroyEvents
Container for events to be run at destroy time.
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...
virtual void ScheduleWithContext(uint32_t context, Time const &time, EventImpl *event)
Schedule a future event execution (in a different context).
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
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:91
SystemMutex m_mutex
Mutex to control access to key state.
AttributeValue implementation for Time.
Definition: nstime.h:928
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:78
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 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 Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
Scheduler event.
Definition: scheduler.h:88
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
Definition: nstime.h:364
Time TimeStep(uint64_t ts)
Definition: nstime.h:923
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:929
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:223
ns3::Synchronizer declaration.
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:208
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:866
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.
void ScheduleRealtime(Time const &time, EventImpl *event)
Schedule a future event execution (in the same context).
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:57
TypeId SetParent(TypeId tid)
Definition: type-id.cc:638
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:79
Keep to real time within the hard limit tolerance configured with SetHardLimit, or die trying...
The SimulatorImpl base class.