A Discrete-Event Network Simulator
API
realtime-simulator-impl.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 University of Washington
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17 
19 
20 #include "assert.h"
21 #include "boolean.h"
22 #include "enum.h"
23 #include "event-impl.h"
24 #include "fatal-error.h"
25 #include "log.h"
26 #include "pointer.h"
27 #include "ptr.h"
28 #include "scheduler.h"
29 #include "simulator.h"
30 #include "synchronizer.h"
32 
33 #include <cmath>
34 #include <mutex>
35 #include <thread>
36 
43 namespace ns3
44 {
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 =
57  TypeId("ns3::RealtimeSimulatorImpl")
59  .SetGroupName("Core")
60  .AddConstructor<RealtimeSimulatorImpl>()
61  .AddAttribute(
62  "SynchronizationMode",
63  "What to do if the simulation cannot keep up with real time.",
65  MakeEnumAccessor<SynchronizationMode>(
67  MakeEnumChecker(SYNC_BEST_EFFORT, "BestEffort", SYNC_HARD_LIMIT, "HardLimit"))
68  .AddAttribute("HardLimit",
69  "Maximum acceptable real-time jitter (used in conjunction with "
70  "SynchronizationMode=HardLimit)",
71  TimeValue(Seconds(0.1)),
73  MakeTimeChecker());
74  return tid;
75 }
76 
78 {
79  NS_LOG_FUNCTION(this);
80 
81  m_stop = false;
82  m_running = false;
85  m_currentTs = 0;
88  m_eventCount = 0;
89 
90  m_main = std::this_thread::get_id();
91 
92  // Be very careful not to do anything that would cause a change or assignment
93  // of the underlying reference counts of m_synchronizer or you will be sorry.
94  m_synchronizer = CreateObject<WallClockSynchronizer>();
95 }
96 
98 {
99  NS_LOG_FUNCTION(this);
100 }
101 
102 void
104 {
105  NS_LOG_FUNCTION(this);
106  while (!m_events->IsEmpty())
107  {
108  Scheduler::Event next = m_events->RemoveNext();
109  next.impl->Unref();
110  }
111  m_events = nullptr;
112  m_synchronizer = nullptr;
114 }
115 
116 void
118 {
119  NS_LOG_FUNCTION(this);
120 
121  //
122  // This function is only called with the private version "disconnected" from
123  // the main simulator functions. We rely on the user not calling
124  // Simulator::Destroy while there is a chance that a worker thread could be
125  // accessing the current instance of the private object. In practice this
126  // means shutting down the workers and doing a Join() before calling the
127  // Simulator::Destroy().
128  //
129  while (!m_destroyEvents.empty())
130  {
131  Ptr<EventImpl> ev = m_destroyEvents.front().PeekEventImpl();
132  m_destroyEvents.pop_front();
133  NS_LOG_LOGIC("handle destroy " << ev);
134  if (!ev->IsCancelled())
135  {
136  ev->Invoke();
137  }
138  }
139 }
140 
141 void
143 {
144  NS_LOG_FUNCTION(this << schedulerFactory);
145 
146  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler>();
147 
148  {
149  std::unique_lock lock{m_mutex};
150 
151  if (m_events)
152  {
153  while (!m_events->IsEmpty())
154  {
155  Scheduler::Event next = m_events->RemoveNext();
156  scheduler->Insert(next);
157  }
158  }
159  m_events = scheduler;
160  }
161 }
162 
163 void
165 {
166  //
167  // The idea here is to wait until the next event comes due. In the case of
168  // a realtime simulation, we want real time to be consumed between events.
169  // It is the realtime synchronizer that causes real time to be consumed by
170  // doing some kind of a wait.
171  //
172  // We need to be able to have external events (such as a packet reception event)
173  // cause us to re-evaluate our state. The way this works is that the synchronizer
174  // gets interrupted and returns. So, there is a possibility that things may change
175  // out from under us dynamically. In this case, we need to re-evaluate how long to
176  // wait in a for-loop until we have waited successfully (until a timeout) for the
177  // event at the head of the event list.
178  //
179  // m_synchronizer->Synchronize will return true if the wait was completed without
180  // interruption, otherwise it will return false indicating that something has changed
181  // out from under us. If we sit in the for-loop trying to synchronize until
182  // Synchronize() returns true, we will have successfully synchronized the execution
183  // time of the next event with the wall clock time of the synchronizer.
184  //
185 
186  for (;;)
187  {
188  uint64_t tsDelay = 0;
189  uint64_t tsNext = 0;
190 
191  //
192  // It is important to understand that m_currentTs is interpreted only as the
193  // timestamp of the last event we executed. Current time can a bit of a
194  // slippery concept in realtime mode. What we have here is a discrete event
195  // simulator, so the last event is, by definition, executed entirely at a single
196  // discrete time. This is the definition of m_currentTs. It really has
197  // nothing to do with the current real time, except that we are trying to arrange
198  // that at the instant of the beginning of event execution, the current real time
199  // and m_currentTs coincide.
200  //
201  // We use tsNow as the indication of the current real time.
202  //
203  uint64_t tsNow;
204 
205  {
206  std::unique_lock lock{m_mutex};
207  //
208  // Since we are in realtime mode, the time to delay has got to be the
209  // difference between the current realtime and the timestamp of the next
210  // event. Since m_currentTs is actually the timestamp of the last event we
211  // executed, it's not particularly meaningful for us here since real time has
212  // certainly elapsed since it was last updated.
213  //
214  // It is possible that the current realtime has drifted past the next event
215  // time so we need to be careful about that and not delay in that case.
216  //
218  m_synchronizer->Realtime(),
219  "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
220 
221  //
222  // tsNow is set to the normalized current real time. When the simulation was
223  // started, the current real time was effectively set to zero; so tsNow is
224  // the current "real" simulation time.
225  //
226  // tsNext is the simulation time of the next event we want to execute.
227  //
228  tsNow = m_synchronizer->GetCurrentRealtime();
229  tsNext = NextTs();
230 
231  //
232  // tsDelay is therefore the real time we need to delay in order to bring the
233  // real time in sync with the simulation time. If we wait for this amount of
234  // real time, we will accomplish moving the simulation time at the same rate
235  // as the real time. This is typically called "pacing" the simulation time.
236  //
237  // We do have to be careful if we are falling behind. If so, tsDelay must be
238  // zero. If we're late, don't dawdle.
239  //
240  if (tsNext <= tsNow)
241  {
242  tsDelay = 0;
243  }
244  else
245  {
246  tsDelay = tsNext - tsNow;
247  }
248 
249  //
250  // We've figured out how long we need to delay in order to pace the
251  // simulation time with the real time. We're going to sleep, but need
252  // to work with the synchronizer to make sure we're awakened if something
253  // external happens (like a packet is received). This next line resets
254  // the synchronizer so that any future event will cause it to interrupt.
255  //
256  m_synchronizer->SetCondition(false);
257  }
258 
259  //
260  // We have a time to delay. This time may actually not be valid anymore
261  // since we released the critical section immediately above, and a real-time
262  // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
263  // closing brace above and this comment so to speak. If this is the case,
264  // that schedule operation will have done a synchronizer Signal() that
265  // will set the condition variable to true and cause the Synchronize call
266  // below to return immediately.
267  //
268  // It's easiest to understand if you just consider a short tsDelay that only
269  // requires a SpinWait down in the synchronizer. What will happen is that
270  // when Synchronize calls SpinWait, SpinWait will look directly at its
271  // condition variable. Note that we set this condition variable to false
272  // inside the critical section above.
273  //
274  // SpinWait will go into a forever loop until either the time has expired or
275  // until the condition variable becomes true. A true condition indicates that
276  // the wait should stop. The condition is set to true by one of the Schedule
277  // methods of the simulator; so if we are in a wait down in Synchronize, and
278  // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
279  // Synchronize will return false. This means we have not actually synchronized
280  // to the event expiration time. If no real-time schedule operation is done
281  // while down in Synchronize, the wait will time out and Synchronize will return
282  // true. This indicates that we have synchronized to the event time.
283  //
284  // So we need to stay in this for loop, looking for the next event timestamp and
285  // attempting to sleep until its due. If we've slept until the timestamp is due,
286  // Synchronize returns true and we break out of the sync loop. If an external
287  // event happens that requires a re-schedule, Synchronize returns false and
288  // we re-evaluate our timing by continuing in the loop.
289  //
290  // It is expected that tsDelay become shorter as external events interrupt our
291  // waits.
292  //
293  if (m_synchronizer->Synchronize(tsNow, tsDelay))
294  {
295  NS_LOG_LOGIC("Interrupted ...");
296  break;
297  }
298 
299  //
300  // If we get to this point, we have been interrupted during a wait by a real-time
301  // schedule operation. This means all bets are off regarding tsDelay and we need
302  // to re-evaluate what it is we want to do. We'll loop back around in the
303  // for-loop and start again from scratch.
304  //
305  }
306 
307  //
308  // If we break out of the for-loop above, we have waited until the time specified
309  // by the event that was at the head of the event list when we started the process.
310  // Since there is a bunch of code that was executed outside a critical section (the
311  // Synchronize call) we cannot be sure that the event at the head of the event list
312  // is the one we think it is. What we can be sure of is that it is time to execute
313  // whatever event is at the head of this list if the list is in time order.
314  //
315  Scheduler::Event next;
316 
317  {
318  std::unique_lock lock{m_mutex};
319 
320  //
321  // We do know we're waiting for an event, so there had better be an event on the
322  // event queue. Let's pull it off. When we release the critical section, the
323  // event we're working on won't be on the list and so subsequent operations won't
324  // mess with us.
325  //
326  NS_ASSERT_MSG(m_events->IsEmpty() == false,
327  "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
328  next = m_events->RemoveNext();
329 
330  PreEventHook(EventId(next.impl, next.key.m_ts, next.key.m_context, next.key.m_uid));
331 
333  m_eventCount++;
334 
335  //
336  // We cannot make any assumption that "next" is the same event we originally waited
337  // for. We can only assume that only that it must be due and cannot cause time
338  // to move backward.
339  //
341  "RealtimeSimulatorImpl::ProcessOneEvent(): "
342  "next.GetTs() earlier than m_currentTs (list order error)");
343  NS_LOG_LOGIC("handle " << next.key.m_ts);
344 
345  //
346  // Update the current simulation time to be the timestamp of the event we're
347  // executing. From the rest of the simulation's point of view, simulation time
348  // is frozen until the next event is executed.
349  //
350  m_currentTs = next.key.m_ts;
352  m_currentUid = next.key.m_uid;
353 
354  //
355  // We're about to run the event and we've done our best to synchronize this
356  // event execution time to real time. Now, if we're in SYNC_HARD_LIMIT mode
357  // we have to decide if we've done a good enough job and if we haven't, we've
358  // been asked to commit ritual suicide.
359  //
360  // We check the simulation time against the current real time to make this
361  // judgement.
362  //
364  {
365  uint64_t tsFinal = m_synchronizer->GetCurrentRealtime();
366  uint64_t tsJitter;
367 
368  if (tsFinal >= m_currentTs)
369  {
370  tsJitter = tsFinal - m_currentTs;
371  }
372  else
373  {
374  tsJitter = m_currentTs - tsFinal;
375  }
376 
377  if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep()))
378  {
379  NS_FATAL_ERROR("RealtimeSimulatorImpl::ProcessOneEvent (): "
380  "Hard real-time limit exceeded (jitter = "
381  << 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  {
403  std::unique_lock lock{m_mutex};
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, "RealtimeSimulatorImpl::Run(): Simulator already running");
428 
429  // Set the current threadId as the main threadId
430  m_main = std::this_thread::get_id();
431 
432  m_stop = false;
433  m_running = true;
434  m_synchronizer->SetOrigin(m_currentTs);
435 
436  // Sleep until signalled
437  uint64_t tsNow = 0;
438  uint64_t tsDelay = 1000000000; // wait time of 1 second (in nanoseconds)
439 
440  while (!m_stop)
441  {
442  bool process = false;
443  {
444  std::unique_lock lock{m_mutex};
445 
446  if (!m_events->IsEmpty())
447  {
448  process = true;
449  }
450  else
451  {
452  // Get current timestamp while holding the critical section
453  tsNow = m_synchronizer->GetCurrentRealtime();
454  }
455  }
456 
457  if (process)
458  {
459  ProcessOneEvent();
460  }
461  else
462  {
463  // Sleep until signalled and re-check event queue
464  m_synchronizer->Synchronize(tsNow, tsDelay);
465  }
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 EventId
503 {
504  NS_LOG_FUNCTION(this << delay);
505  return Simulator::Schedule(delay, &Simulator::Stop);
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, const Time& 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 
564  "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  return Schedule(Time(0), impl);
582 }
583 
584 Time
586 {
587  return TimeStep(m_currentTs);
588 }
589 
590 //
591 // Schedule an event for a _relative_ time in the future.
592 //
593 void
595  const Time& time,
596  EventImpl* impl)
597 {
598  NS_LOG_FUNCTION(this << context << time << impl);
599 
600  {
601  std::unique_lock lock{m_mutex};
602 
603  uint64_t ts = m_synchronizer->GetCurrentRealtime() + time.GetTimeStep();
605  "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
606  Scheduler::Event ev;
607  ev.impl = impl;
608  ev.key.m_ts = ts;
609  ev.key.m_uid = m_uid;
610  m_uid++;
612  m_events->Insert(ev);
613  m_synchronizer->Signal();
614  }
615 }
616 
617 void
619 {
620  NS_LOG_FUNCTION(this << time << impl);
622 }
623 
624 void
626 {
627  NS_LOG_FUNCTION(this << context << impl);
628  {
629  std::unique_lock lock{m_mutex};
630 
631  //
632  // If the simulator is running, we're pacing and have a meaningful
633  // realtime clock. If we're not, then m_currentTs is were we stopped.
634  //
635  uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime() : m_currentTs;
637  "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time "
638  "< m_currentTs");
639  Scheduler::Event ev;
640  ev.impl = impl;
641  ev.key.m_ts = ts;
642  ev.key.m_uid = m_uid;
643  ev.key.m_context = context;
644  m_uid++;
646  m_events->Insert(ev);
647  m_synchronizer->Signal();
648  }
649 }
650 
651 void
653 {
654  NS_LOG_FUNCTION(this << impl);
656 }
657 
658 Time
660 {
661  return TimeStep(m_synchronizer->GetCurrentRealtime());
662 }
663 
664 EventId
666 {
667  NS_LOG_FUNCTION(this << impl);
668 
669  EventId id;
670  {
671  std::unique_lock lock{m_mutex};
672 
673  //
674  // Time doesn't really matter here (especially in realtime mode). It is
675  // overridden by the uid of DESTROY which identifies this as an event to be
676  // executed at Simulator::Destroy time.
677  //
678  id = EventId(Ptr<EventImpl>(impl, false), m_currentTs, 0xffffffff, EventId::UID::DESTROY);
679  m_destroyEvents.push_back(id);
680  m_uid++;
681  }
682 
683  return id;
684 }
685 
686 Time
688 {
689  //
690  // If the event has expired, there is no delay until it runs. It is not the
691  // case that there is a negative time until it runs.
692  //
693  if (IsExpired(id))
694  {
695  return TimeStep(0);
696  }
697 
698  return TimeStep(id.GetTs() - m_currentTs);
699 }
700 
701 void
703 {
704  if (id.GetUid() == EventId::UID::DESTROY)
705  {
706  // destroy events.
707  for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
708  {
709  if (*i == id)
710  {
711  m_destroyEvents.erase(i);
712  break;
713  }
714  }
715  return;
716  }
717  if (IsExpired(id))
718  {
719  return;
720  }
721 
722  {
723  std::unique_lock lock{m_mutex};
724 
725  Scheduler::Event event;
726  event.impl = id.PeekEventImpl();
727  event.key.m_ts = id.GetTs();
728  event.key.m_context = id.GetContext();
729  event.key.m_uid = id.GetUid();
730 
731  m_events->Remove(event);
733  event.impl->Cancel();
734  event.impl->Unref();
735  }
736 }
737 
738 void
740 {
741  if (!IsExpired(id))
742  {
743  id.PeekEventImpl()->Cancel();
744  }
745 }
746 
747 bool
749 {
750  if (id.GetUid() == EventId::UID::DESTROY)
751  {
752  if (id.PeekEventImpl() == nullptr || id.PeekEventImpl()->IsCancelled())
753  {
754  return true;
755  }
756  // destroy events.
757  for (auto i = m_destroyEvents.begin(); 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  return id.PeekEventImpl() == nullptr || id.GetTs() < m_currentTs ||
776  (id.GetTs() == m_currentTs && id.GetUid() <= m_currentUid) ||
777  id.PeekEventImpl()->IsCancelled();
778 }
779 
780 Time
782 {
783  return TimeStep(0x7fffffffffffffffLL);
784 }
785 
786 // System ID for non-distributed simulation is always zero
787 uint32_t
789 {
790  return 0;
791 }
792 
793 uint32_t
795 {
796  return m_currentContext;
797 }
798 
799 uint64_t
801 {
802  return m_eventCount;
803 }
804 
805 void
807 {
808  NS_LOG_FUNCTION(this << mode);
809  m_synchronizationMode = mode;
810 }
811 
814 {
815  NS_LOG_FUNCTION(this);
816  return m_synchronizationMode;
817 }
818 
819 void
821 {
822  NS_LOG_FUNCTION(this << limit);
823  m_hardLimit = limit;
824 }
825 
826 Time
828 {
829  NS_LOG_FUNCTION(this);
830  return m_hardLimit;
831 }
832 
833 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
ns3::BooleanValue attribute value declarations.
Hold variables of type enum.
Definition: enum.h:62
An identifier for simulation events.
Definition: event-id.h:55
A simulation event.
Definition: event-impl.h:46
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:352
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Realtime version of SimulatorImpl.
Time RealtimeNow() const
Get the current real time from the synchronizer.
void ScheduleRealtime(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
uint64_t GetEventCount() const override
Get the number of events executed.
Ptr< Scheduler > m_events
The event list.
uint32_t GetContext() const override
Get the current simulation context.
DestroyEvents m_destroyEvents
Container for events to be run at destroy time.
uint32_t GetSystemId() const override
Get the system id of this simulator.
int m_unscheduledEvents
Unique id for the next event to be scheduled.
void Stop() override
Tell the Simulator the calling event should be the last one executed.
EventId ScheduleDestroy(EventImpl *event) override
Schedule an event to run at the end of the simulation, after the Stop() time or condition has been re...
Time GetHardLimit() const
Get the current fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
void ScheduleRealtimeNow(EventImpl *event)
Schedule an event to run at the current virtual time.
void Run() override
Run the simulation.
bool m_running
Is the simulator currently running.
uint32_t m_currentContext
The event list.
bool IsExpired(const EventId &ev) const override
Check if an event has already run or been cancelled.
std::mutex m_mutex
Mutex to control access to key state.
SynchronizationMode m_synchronizationMode
SynchronizationMode policy.
void DoDispose() override
Destructor implementation.
uint64_t m_currentTs
Execution context.
void Cancel(const EventId &ev) override
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
EventId Schedule(const Time &delay, EventImpl *event) override
Schedule a future event execution (in the same context).
void SetHardLimit(Time limit)
Set the fatal error threshold for SynchronizationMode SYNC_HARD_LIMIT.
~RealtimeSimulatorImpl() override
Destructor.
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.
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.
bool IsFinished() const override
Check if the simulation should finish.
bool Realtime() const
Check that the Synchronizer is locked to the real time clock.
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()
Get the registered TypeId for this class.
void ScheduleRealtimeWithContext(uint32_t context, const Time &delay, EventImpl *event)
Schedule a future event execution (in a different context).
Time GetDelayLeft(const EventId &id) const override
Get the remaining time until this event will execute.
void SetScheduler(ObjectFactory schedulerFactory) override
Set the Scheduler to be used to manage the event list.
void ScheduleWithContext(uint32_t context, const Time &delay, EventImpl *event) override
Schedule a future event execution (in a different context).
EventId ScheduleNow(EventImpl *event) override
Schedule an event to run at the current virtual time.
bool Running() const
Is the simulator running?
std::thread::id m_main
Main thread.
void ProcessOneEvent()
Process the next event.
Time Now() const override
Return the current simulation virtual time.
void Remove(const EventId &ev) override
Remove an event from the event list.
void Destroy() override
Execute the events scheduled with ScheduleDestroy().
void SetSynchronizationMode(RealtimeSimulatorImpl::SynchronizationMode mode)
Set the SynchronizationMode.
uint64_t NextTs() const
Get the timestep of the next event.
RealtimeSimulatorImpl::SynchronizationMode GetSynchronizationMode() const
Get the SynchronizationMode.
Time GetMaximumSimulationTime() const override
Get the maximum representable simulation time.
Maintain the event list.
Definition: scheduler.h:157
void Unref() const
Decrement the reference count.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
@ NO_CONTEXT
Flag for events not associated with any particular context.
Definition: simulator.h:210
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
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:105
bool IsPositive() const
Exactly equivalent to t >= 0.
Definition: nstime.h:333
int64_t GetTimeStep() const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:445
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
ns3::EnumValue attribute value declarations.
ns3::EventImpl declarations.
NS_FATAL_x macro definitions.
@ INVALID
INVALID.
Definition: aodv-rtable.h:53
@ VALID
VALID.
Definition: aodv-rtable.h:52
#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:86
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Debug message logging.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:839
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:194
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
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:184
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:186
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:185
uint32_t m_context
Event context.
Definition: scheduler.h:173
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:171
uint32_t m_uid
Event unique id.
Definition: scheduler.h:172
ns3::Synchronizer declaration.
ns3::WallClockSynchronizer declaration.