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 "boolean.h"
32 #include "enum.h"
33 
34 #include <cmath>
35 #include <mutex>
36 #include <thread>
37 
44 namespace ns3 {
45 
46 // Note: Logging in this file is largely avoided due to the
47 // number of calls that are made to these functions and the possibility
48 // of causing recursions leading to stack overflow
49 NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorImpl");
50 
51 NS_OBJECT_ENSURE_REGISTERED (RealtimeSimulatorImpl);
52 
53 TypeId
55 {
56  static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
58  .SetGroupName ("Core")
59  .AddConstructor<RealtimeSimulatorImpl> ()
60  .AddAttribute ("SynchronizationMode",
61  "What to do if the simulation cannot keep up with real time.",
64  MakeEnumChecker (SYNC_BEST_EFFORT, "BestEffort",
65  SYNC_HARD_LIMIT, "HardLimit"))
66  .AddAttribute ("HardLimit",
67  "Maximum acceptable real-time jitter (used in conjunction with SynchronizationMode=HardLimit)",
68  TimeValue (Seconds (0.1)),
70  MakeTimeChecker ())
71  ;
72  return tid;
73 }
74 
75 
77 {
78  NS_LOG_FUNCTION (this);
79 
80  m_stop = false;
81  m_running = false;
84  m_currentTs = 0;
87  m_eventCount = 0;
88 
89  m_main = std::this_thread::get_id ();
90 
91  // Be very careful not to do anything that would cause a change or assignment
92  // of the underlying reference counts of m_synchronizer or you will be sorry.
93  m_synchronizer = CreateObject<WallClockSynchronizer> ();
94 }
95 
97 {
98  NS_LOG_FUNCTION (this);
99 }
100 
101 void
103 {
104  NS_LOG_FUNCTION (this);
105  while (!m_events->IsEmpty ())
106  {
107  Scheduler::Event next = m_events->RemoveNext ();
108  next.impl->Unref ();
109  }
110  m_events = 0;
111  m_synchronizer = 0;
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION (this);
119 
120  //
121  // This function is only called with the private version "disconnected" from
122  // the main simulator functions. We rely on the user not calling
123  // Simulator::Destroy while there is a chance that a worker thread could be
124  // accessing the current instance of the private object. In practice this
125  // means shutting down the workers and doing a Join() before calling the
126  // Simulator::Destroy().
127  //
128  while (m_destroyEvents.empty () == false)
129  {
130  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
131  m_destroyEvents.pop_front ();
132  NS_LOG_LOGIC ("handle destroy " << ev);
133  if (ev->IsCancelled () == false)
134  {
135  ev->Invoke ();
136  }
137  }
138 }
139 
140 void
142 {
143  NS_LOG_FUNCTION (this << schedulerFactory);
144 
145  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
146 
147  {
148  std::unique_lock lock {m_mutex};
149 
150  if (m_events != 0)
151  {
152  while (m_events->IsEmpty () == false)
153  {
154  Scheduler::Event next = m_events->RemoveNext ();
155  scheduler->Insert (next);
156  }
157  }
158  m_events = scheduler;
159  }
160 }
161 
162 void
164 {
165  //
166  // The idea here is to wait until the next event comes due. In the case of
167  // a realtime simulation, we want real time to be consumed between events.
168  // It is the realtime synchronizer that causes real time to be consumed by
169  // doing some kind of a wait.
170  //
171  // We need to be able to have external events (such as a packet reception event)
172  // cause us to re-evaluate our state. The way this works is that the synchronizer
173  // gets interrupted and returns. So, there is a possibility that things may change
174  // out from under us dynamically. In this case, we need to re-evaluate how long to
175  // wait in a for-loop until we have waited successfully (until a timeout) for the
176  // event at the head of the event list.
177  //
178  // m_synchronizer->Synchronize will return true if the wait was completed without
179  // interruption, otherwise it will return false indicating that something has changed
180  // out from under us. If we sit in the for-loop trying to synchronize until
181  // Synchronize() returns true, we will have successfully synchronized the execution
182  // time of the next event with the wall clock time of the synchronizer.
183  //
184 
185  for (;;)
186  {
187  uint64_t tsDelay = 0;
188  uint64_t tsNext = 0;
189 
190  //
191  // It is important to understand that m_currentTs is interpreted only as the
192  // timestamp of the last event we executed. Current time can a bit of a
193  // slippery concept in realtime mode. What we have here is a discrete event
194  // simulator, so the last event is, by definition, executed entirely at a single
195  // discrete time. This is the definition of m_currentTs. It really has
196  // nothing to do with the current real time, except that we are trying to arrange
197  // that at the instant of the beginning of event execution, the current real time
198  // and m_currentTs coincide.
199  //
200  // We use tsNow as the indication of the current real time.
201  //
202  uint64_t tsNow;
203 
204  {
205  std::unique_lock lock {m_mutex};
206  //
207  // Since we are in realtime mode, the time to delay has got to be the
208  // difference between the current realtime and the timestamp of the next
209  // event. Since m_currentTs is actually the timestamp of the last event we
210  // executed, it's not particularly meaningful for us here since real time has
211  // certainly elapsed since it was last updated.
212  //
213  // It is possible that the current realtime has drifted past the next event
214  // time so we need to be careful about that and not delay in that case.
215  //
216  NS_ASSERT_MSG (m_synchronizer->Realtime (),
217  "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
218 
219  //
220  // tsNow is set to the normalized current real time. When the simulation was
221  // started, the current real time was effectively set to zero; so tsNow is
222  // the current "real" simulation time.
223  //
224  // tsNext is the simulation time of the next event we want to execute.
225  //
226  tsNow = m_synchronizer->GetCurrentRealtime ();
227  tsNext = NextTs ();
228 
229  //
230  // tsDelay is therefore the real time we need to delay in order to bring the
231  // real time in sync with the simulation time. If we wait for this amount of
232  // real time, we will accomplish moving the simulation time at the same rate
233  // as the real time. This is typically called "pacing" the simulation time.
234  //
235  // We do have to be careful if we are falling behind. If so, tsDelay must be
236  // zero. If we're late, don't dawdle.
237  //
238  if (tsNext <= tsNow)
239  {
240  tsDelay = 0;
241  }
242  else
243  {
244  tsDelay = tsNext - tsNow;
245  }
246 
247  //
248  // We've figured out how long we need to delay in order to pace the
249  // simulation time with the real time. We're going to sleep, but need
250  // to work with the synchronizer to make sure we're awakened if something
251  // external happens (like a packet is received). This next line resets
252  // the synchronizer so that any future event will cause it to interrupt.
253  //
254  m_synchronizer->SetCondition (false);
255  }
256 
257  //
258  // We have a time to delay. This time may actually not be valid anymore
259  // since we released the critical section immediately above, and a real-time
260  // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
261  // closing brace above and this comment so to speak. If this is the case,
262  // that schedule operation will have done a synchronizer Signal() that
263  // will set the condition variable to true and cause the Synchronize call
264  // below to return immediately.
265  //
266  // It's easiest to understand if you just consider a short tsDelay that only
267  // requires a SpinWait down in the synchronizer. What will happen is that
268  // whan Synchronize calls SpinWait, SpinWait will look directly at its
269  // condition variable. Note that we set this condition variable to false
270  // inside the critical section above.
271  //
272  // SpinWait will go into a forever loop until either the time has expired or
273  // until the condition variable becomes true. A true condition indicates that
274  // the wait should stop. The condition is set to true by one of the Schedule
275  // methods of the simulator; so if we are in a wait down in Synchronize, and
276  // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
277  // Synchronize will return false. This means we have not actually synchronized
278  // to the event expiration time. If no real-time schedule operation is done
279  // while down in Synchronize, the wait will time out and Synchronize will return
280  // true. This indicates that we have synchronized to the event time.
281  //
282  // So we need to stay in this for loop, looking for the next event timestamp and
283  // attempting to sleep until its due. If we've slept until the timestamp is due,
284  // Synchronize returns true and we break out of the sync loop. If an external
285  // event happens that requires a re-schedule, Synchronize returns false and
286  // we re-evaluate our timing by continuing in the loop.
287  //
288  // It is expected that tsDelay become shorter as external events interrupt our
289  // waits.
290  //
291  if (m_synchronizer->Synchronize (tsNow, tsDelay))
292  {
293  NS_LOG_LOGIC ("Interrupted ...");
294  break;
295  }
296 
297  //
298  // If we get to this point, we have been interrupted during a wait by a real-time
299  // schedule operation. This means all bets are off regarding tsDelay and we need
300  // to re-evaluate what it is we want to do. We'll loop back around in the
301  // for-loop and start again from scratch.
302  //
303  }
304 
305  //
306  // If we break out of the for-loop above, we have waited until the time specified
307  // by the event that was at the head of the event list when we started the process.
308  // Since there is a bunch of code that was executed outside a critical section (the
309  // Synchronize call) we cannot be sure that the event at the head of the event list
310  // is the one we think it is. What we can be sure of is that it is time to execute
311  // whatever event is at the head of this list if the list is in time order.
312  //
313  Scheduler::Event next;
314 
315  {
316  std::unique_lock lock {m_mutex};
317 
318  //
319  // We do know we're waiting for an event, so there had better be an event on the
320  // event queue. Let's pull it off. When we release the critical section, the
321  // event we're working on won't be on the list and so subsequent operations won't
322  // mess with us.
323  //
324  NS_ASSERT_MSG (m_events->IsEmpty () == false,
325  "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
326  next = m_events->RemoveNext ();
327 
328  PreEventHook (EventId (next.impl, next.key.m_ts,
329  next.key.m_context, next.key.m_uid));
330 
332  m_eventCount++;
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  //
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;
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  {
401  std::unique_lock lock {m_mutex};
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
429  m_main = std::this_thread::get_id ();
430 
431  m_stop = false;
432  m_running = true;
433  m_synchronizer->SetOrigin (m_currentTs);
434 
435  // Sleep until signalled
436  uint64_t tsNow = 0;
437  uint64_t tsDelay = 1000000000; // wait time of 1 second (in nanoseconds)
438 
439  while (!m_stop)
440  {
441  bool process = false;
442  {
443  std::unique_lock lock {m_mutex};
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  {
473  std::unique_lock lock {m_mutex};
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  {
518  std::unique_lock lock {m_mutex};
519  //
520  // This is the reason we had to bring the absolute time calculation 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 (delay.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative delay");
527  ev.impl = impl;
528  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
529  ev.key.m_context = GetContext ();
530  ev.key.m_uid = m_uid;
531  m_uid++;
533  m_events->Insert (ev);
534  m_synchronizer->Signal ();
535  }
536 
537  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
538 }
539 
540 void
541 RealtimeSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *impl)
542 {
543  NS_LOG_FUNCTION (this << context << delay << impl);
544 
545  {
546  std::unique_lock lock {m_mutex};
547  uint64_t ts;
548 
549  if (m_main == std::this_thread::get_id ())
550  {
551  ts = m_currentTs + delay.GetTimeStep ();
552  }
553  else
554  {
555  //
556  // If the simulator is running, we're pacing and have a meaningful
557  // realtime clock. If we're not, then m_currentTs is where we stopped.
558  //
559  ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
560  ts += delay.GetTimeStep ();
561  }
562 
563  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
564  Scheduler::Event ev;
565  ev.impl = impl;
566  ev.key.m_ts = ts;
567  ev.key.m_context = context;
568  ev.key.m_uid = m_uid;
569  m_uid++;
571  m_events->Insert (ev);
572  m_synchronizer->Signal ();
573  }
574 }
575 
576 EventId
578 {
579  NS_LOG_FUNCTION (this << impl);
580  return Schedule (Time (0), impl);
581 }
582 
583 Time
585 {
586  return TimeStep (m_currentTs);
587 }
588 
589 //
590 // Schedule an event for a _relative_ time in the future.
591 //
592 void
594 {
595  NS_LOG_FUNCTION (this << context << time << impl);
596 
597  {
598  std::unique_lock lock {m_mutex};
599 
600  uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
601  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
602  Scheduler::Event ev;
603  ev.impl = impl;
604  ev.key.m_ts = ts;
605  ev.key.m_uid = m_uid;
606  m_uid++;
608  m_events->Insert (ev);
609  m_synchronizer->Signal ();
610  }
611 }
612 
613 void
615 {
616  NS_LOG_FUNCTION (this << time << impl);
617  ScheduleRealtimeWithContext (GetContext (), time, impl);
618 }
619 
620 void
622 {
623  NS_LOG_FUNCTION (this << context << impl);
624  {
625  std::unique_lock lock {m_mutex};
626 
627  //
628  // If the simulator is running, we're pacing and have a meaningful
629  // realtime clock. If we're not, then m_currentTs is were we stopped.
630  //
631  uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
632  NS_ASSERT_MSG (ts >= m_currentTs,
633  "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
634  Scheduler::Event ev;
635  ev.impl = impl;
636  ev.key.m_ts = ts;
637  ev.key.m_uid = m_uid;
638  ev.key.m_context = context;
639  m_uid++;
641  m_events->Insert (ev);
642  m_synchronizer->Signal ();
643  }
644 }
645 
646 void
648 {
649  NS_LOG_FUNCTION (this << impl);
651 }
652 
653 Time
655 {
656  return TimeStep (m_synchronizer->GetCurrentRealtime ());
657 }
658 
659 EventId
661 {
662  NS_LOG_FUNCTION (this << impl);
663 
664  EventId id;
665  {
666  std::unique_lock lock {m_mutex};
667 
668  //
669  // Time doesn't really matter here (especially in realtime mode). It is
670  // overridden by the uid of DESTROY which identifies this as an event to be
671  // executed at Simulator::Destroy time.
672  //
673  id = EventId (Ptr<EventImpl> (impl, false), m_currentTs, 0xffffffff,
674  EventId::UID::DESTROY);
675  m_destroyEvents.push_back (id);
676  m_uid++;
677  }
678 
679  return id;
680 }
681 
682 Time
684 {
685  //
686  // If the event has expired, there is no delay until it runs. It is not the
687  // case that there is a negative time until it runs.
688  //
689  if (IsExpired (id))
690  {
691  return TimeStep (0);
692  }
693 
694  return TimeStep (id.GetTs () - m_currentTs);
695 }
696 
697 void
699 {
700  if (id.GetUid () == EventId::UID::DESTROY)
701  {
702  // destroy events.
703  for (DestroyEvents::iterator i = m_destroyEvents.begin ();
704  i != m_destroyEvents.end ();
705  i++)
706  {
707  if (*i == id)
708  {
709  m_destroyEvents.erase (i);
710  break;
711  }
712  }
713  return;
714  }
715  if (IsExpired (id))
716  {
717  return;
718  }
719 
720  {
721  std::unique_lock lock {m_mutex};
722 
723  Scheduler::Event event;
724  event.impl = id.PeekEventImpl ();
725  event.key.m_ts = id.GetTs ();
726  event.key.m_context = id.GetContext ();
727  event.key.m_uid = id.GetUid ();
728 
729  m_events->Remove (event);
731  event.impl->Cancel ();
732  event.impl->Unref ();
733  }
734 }
735 
736 void
738 {
739  if (IsExpired (id) == false)
740  {
741  id.PeekEventImpl ()->Cancel ();
742  }
743 }
744 
745 bool
747 {
748  if (id.GetUid () == EventId::UID::DESTROY)
749  {
750  if (id.PeekEventImpl () == 0
751  || id.PeekEventImpl ()->IsCancelled ())
752  {
753  return true;
754  }
755  // destroy events.
756  for (DestroyEvents::const_iterator i = m_destroyEvents.begin ();
757  i != m_destroyEvents.end (); i++)
758  {
759  if (*i == id)
760  {
761  return false;
762  }
763  }
764  return true;
765  }
766 
767  //
768  // If the time of the event is less than the current timestamp of the
769  // simulator, the simulator has gone past the invocation time of the
770  // event, so the statement ev.GetTs () < m_currentTs does mean that
771  // the event has been fired even in realtime mode.
772  //
773  // The same is true for the next line involving the m_currentUid.
774  //
775  if (id.PeekEventImpl () == 0
776  || id.GetTs () < m_currentTs
777  || (id.GetTs () == m_currentTs && id.GetUid () <= m_currentUid)
778  || id.PeekEventImpl ()->IsCancelled ())
779  {
780  return true;
781  }
782  else
783  {
784  return false;
785  }
786 }
787 
788 Time
790 {
791  return TimeStep (0x7fffffffffffffffLL);
792 }
793 
794 // System ID for non-distributed simulation is always zero
795 uint32_t
797 {
798  return 0;
799 }
800 
801 uint32_t
803 {
804  return m_currentContext;
805 }
806 
807 uint64_t
809 {
810  return m_eventCount;
811 }
812 
813 void
815 {
816  NS_LOG_FUNCTION (this << mode);
817  m_synchronizationMode = mode;
818 }
819 
822 {
823  NS_LOG_FUNCTION (this);
824  return m_synchronizationMode;
825 }
826 
827 void
829 {
830  NS_LOG_FUNCTION (this << limit);
831  m_hardLimit = limit;
832 }
833 
834 Time
836 {
837  NS_LOG_FUNCTION (this);
838  return m_hardLimit;
839 }
840 
841 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
ns3::BooleanValue attribute value declarations.
Hold variables of type enum.
Definition: enum.h:55
An identifier for simulation events.
Definition: event-id.h:54
A simulation event.
Definition: event-impl.h:45
Instantiate subclasses of ns3::Object.
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
Realtime version of SimulatorImpl.
void ScheduleRealtime(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Ptr< Scheduler > m_events
The event list.
virtual void ScheduleWithContext(uint32_t context, const Time &delay, 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 ScheduleNow(EventImpl *event)
Schedule an event to run at the current virtual time.
int m_unscheduledEvents
Unique id for the next event to be scheduled.
virtual EventId Schedule(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
bool Realtime(void) const
Check that the Synchronizer is locked to the real time clock.
void ScheduleRealtimeNow(EventImpl *event)
Schedule an event to run at the current virtual time.
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
bool m_running
Is the simulator currently running.
uint32_t m_currentContext
The event list.
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 Remove(const EventId &ev)
Remove an event from the event list.
Time GetHardLimit(void) const
Get the current fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
std::mutex m_mutex
Mutex to control access to key state.
SynchronizationMode m_synchronizationMode
SynchronizationMode policy.
uint64_t NextTs(void) const
Get the timestep of the next event.
virtual void Run(void)
Run the simulation.
uint64_t m_currentTs
Execution context.
void SetHardLimit(Time limit)
Set the fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
uint32_t m_uid
Unique id of the current event.
uint64_t m_eventCount
The event count.
uint32_t m_currentUid
Timestep of the current event.
virtual void SetScheduler(ObjectFactory schedulerFactory)
Set the Scheduler to be used to manage the event list.
void ScheduleRealtimeNowWithContext(uint32_t context, EventImpl *event)
Schedule an event to run at the current virtual time.
bool m_stop
Has the stopping condition been reached?
Ptr< Synchronizer > m_synchronizer
The synchronizer in use to track real time.
SynchronizationMode
What to do when we can't maintain real time synchrony.
@ SYNC_BEST_EFFORT
Make a best effort to keep synced to real-time.
@ SYNC_HARD_LIMIT
Keep to real time within the hard limit tolerance configured with SetHardLimit, or die trying.
Time m_hardLimit
The maximum allowable drift from real-time in SYNC_HARD_LIMIT mode.
static TypeId GetTypeId(void)
Get the registered TypeId for this class.
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
void ScheduleRealtimeWithContext(uint32_t context, const Time &delay, EventImpl *event)
Schedule a future event execution (in a different context).
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
virtual bool IsFinished(void) const
Check if the simulation should finish.
virtual Time Now(void) const
Return the current simulation virtual time.
virtual uint32_t GetContext(void) const
Get the current simulation context.
bool Running(void) const
Is the simulator running?
virtual uint64_t GetEventCount(void) const
Get the number of events executed.
void ProcessOneEvent(void)
Process the next event.
std::thread::id m_main
Main thread.
RealtimeSimulatorImpl::SynchronizationMode GetSynchronizationMode(void) const
Get the SynchronizationMode.
void SetSynchronizationMode(RealtimeSimulatorImpl::SynchronizationMode mode)
Set the SynchronizationMode.
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 Destroy()
Execute the events scheduled with ScheduleDestroy().
Time RealtimeNow(void) const
Get the current real time from the synchronizer.
virtual bool IsExpired(const EventId &ev) const
Check if an event has already run or been cancelled.
Maintain the event list.
Definition: scheduler.h:156
void Unref(void) const
Decrement the reference count.
static void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:180
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:556
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
@ NO_CONTEXT
Flag for events not associated with any particular context.
Definition: simulator.h:199
The SimulatorImpl base class.
virtual void PreEventHook(const EventId &id)
Hook called before processing each event.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:415
bool IsPositive(void) const
Exactly equivalent to t >= 0.
Definition: nstime.h:316
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
ns3::EnumValue attribute value declarations.
ns3::EventImpl declarations.
NS_FATAL_x macro definitions.
@ INVALID
INVALID.
Definition: aodv-rtable.h:51
@ VALID
VALID.
Definition: aodv-rtable.h:50
#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:88
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:205
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:1309
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:162
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:522
ns3::PointerValue attribute value declarations and template implementations.
ns3::Ptr smart pointer declaration and implementation.
ns3::RealtimeSimulatorImpl declaration.
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations.
ns3::Simulator declaration.
Scheduler event.
Definition: scheduler.h:182
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:184
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:183
uint32_t m_context
Event context.
Definition: scheduler.h:172
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:170
uint32_t m_uid
Event unique id.
Definition: scheduler.h:171
ns3::Synchronizer declaration.
ns3::WallClockSynchronizer declaration.