A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
realtime-simulator-impl.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008 University of Washington
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
8
9#include "assert.h"
10#include "boolean.h"
11#include "enum.h"
12#include "event-impl.h"
13#include "fatal-error.h"
14#include "log.h"
15#include "pointer.h"
16#include "ptr.h"
17#include "scheduler.h"
18#include "simulator.h"
19#include "synchronizer.h"
21
22#include <cmath>
23#include <mutex>
24#include <thread>
25
26/**
27 * \file
28 * \ingroup realtime
29 * ns3::RealTimeSimulatorImpl implementation.
30 */
31
32namespace ns3
33{
34
35// Note: Logging in this file is largely avoided due to the
36// number of calls that are made to these functions and the possibility
37// of causing recursions leading to stack overflow
38NS_LOG_COMPONENT_DEFINE("RealtimeSimulatorImpl");
39
40NS_OBJECT_ENSURE_REGISTERED(RealtimeSimulatorImpl);
41
42TypeId
44{
45 static TypeId tid =
46 TypeId("ns3::RealtimeSimulatorImpl")
48 .SetGroupName("Core")
49 .AddConstructor<RealtimeSimulatorImpl>()
50 .AddAttribute(
51 "SynchronizationMode",
52 "What to do if the simulation cannot keep up with real time.",
56 MakeEnumChecker(SYNC_BEST_EFFORT, "BestEffort", SYNC_HARD_LIMIT, "HardLimit"))
57 .AddAttribute("HardLimit",
58 "Maximum acceptable real-time jitter (used in conjunction with "
59 "SynchronizationMode=HardLimit)",
60 TimeValue(Seconds(0.1)),
63 return tid;
64}
65
67{
68 NS_LOG_FUNCTION(this);
69
70 m_stop = false;
71 m_running = false;
74 m_currentTs = 0;
77 m_eventCount = 0;
78
79 m_main = std::this_thread::get_id();
80
81 // Be very careful not to do anything that would cause a change or assignment
82 // of the underlying reference counts of m_synchronizer or you will be sorry.
84}
85
90
91void
93{
94 NS_LOG_FUNCTION(this);
95 while (!m_events->IsEmpty())
96 {
97 Scheduler::Event next = m_events->RemoveNext();
98 next.impl->Unref();
99 }
100 m_events = nullptr;
101 m_synchronizer = nullptr;
103}
104
105void
107{
108 NS_LOG_FUNCTION(this);
109
110 //
111 // This function is only called with the private version "disconnected" from
112 // the main simulator functions. We rely on the user not calling
113 // Simulator::Destroy while there is a chance that a worker thread could be
114 // accessing the current instance of the private object. In practice this
115 // means shutting down the workers and doing a Join() before calling the
116 // Simulator::Destroy().
117 //
118 while (!m_destroyEvents.empty())
119 {
120 Ptr<EventImpl> ev = m_destroyEvents.front().PeekEventImpl();
121 m_destroyEvents.pop_front();
122 NS_LOG_LOGIC("handle destroy " << ev);
123 if (!ev->IsCancelled())
124 {
125 ev->Invoke();
126 }
127 }
128}
129
130void
132{
133 NS_LOG_FUNCTION(this << schedulerFactory);
134
135 Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler>();
136
137 {
138 std::unique_lock lock{m_mutex};
139
140 if (m_events)
141 {
142 while (!m_events->IsEmpty())
143 {
144 Scheduler::Event next = m_events->RemoveNext();
145 scheduler->Insert(next);
146 }
147 }
148 m_events = scheduler;
149 }
150}
151
152void
154{
155 //
156 // The idea here is to wait until the next event comes due. In the case of
157 // a realtime simulation, we want real time to be consumed between events.
158 // It is the realtime synchronizer that causes real time to be consumed by
159 // doing some kind of a wait.
160 //
161 // We need to be able to have external events (such as a packet reception event)
162 // cause us to re-evaluate our state. The way this works is that the synchronizer
163 // gets interrupted and returns. So, there is a possibility that things may change
164 // out from under us dynamically. In this case, we need to re-evaluate how long to
165 // wait in a for-loop until we have waited successfully (until a timeout) for the
166 // event at the head of the event list.
167 //
168 // m_synchronizer->Synchronize will return true if the wait was completed without
169 // interruption, otherwise it will return false indicating that something has changed
170 // out from under us. If we sit in the for-loop trying to synchronize until
171 // Synchronize() returns true, we will have successfully synchronized the execution
172 // time of the next event with the wall clock time of the synchronizer.
173 //
174
175 for (;;)
176 {
177 uint64_t tsDelay = 0;
178 uint64_t tsNext = 0;
179
180 //
181 // It is important to understand that m_currentTs is interpreted only as the
182 // timestamp of the last event we executed. Current time can a bit of a
183 // slippery concept in realtime mode. What we have here is a discrete event
184 // simulator, so the last event is, by definition, executed entirely at a single
185 // discrete time. This is the definition of m_currentTs. It really has
186 // nothing to do with the current real time, except that we are trying to arrange
187 // that at the instant of the beginning of event execution, the current real time
188 // and m_currentTs coincide.
189 //
190 // We use tsNow as the indication of the current real time.
191 //
192 uint64_t tsNow;
193
194 {
195 std::unique_lock lock{m_mutex};
196 //
197 // Since we are in realtime mode, the time to delay has got to be the
198 // difference between the current realtime and the timestamp of the next
199 // event. Since m_currentTs is actually the timestamp of the last event we
200 // executed, it's not particularly meaningful for us here since real time has
201 // certainly elapsed since it was last updated.
202 //
203 // It is possible that the current realtime has drifted past the next event
204 // time so we need to be careful about that and not delay in that case.
205 //
207 m_synchronizer->Realtime(),
208 "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
209
210 //
211 // tsNow is set to the normalized current real time. When the simulation was
212 // started, the current real time was effectively set to zero; so tsNow is
213 // the current "real" simulation time.
214 //
215 // tsNext is the simulation time of the next event we want to execute.
216 //
217 tsNow = m_synchronizer->GetCurrentRealtime();
218 tsNext = NextTs();
219
220 //
221 // tsDelay is therefore the real time we need to delay in order to bring the
222 // real time in sync with the simulation time. If we wait for this amount of
223 // real time, we will accomplish moving the simulation time at the same rate
224 // as the real time. This is typically called "pacing" the simulation time.
225 //
226 // We do have to be careful if we are falling behind. If so, tsDelay must be
227 // zero. If we're late, don't dawdle.
228 //
229 if (tsNext <= tsNow)
230 {
231 tsDelay = 0;
232 }
233 else
234 {
235 tsDelay = tsNext - tsNow;
236 }
237
238 //
239 // We've figured out how long we need to delay in order to pace the
240 // simulation time with the real time. We're going to sleep, but need
241 // to work with the synchronizer to make sure we're awakened if something
242 // external happens (like a packet is received). This next line resets
243 // the synchronizer so that any future event will cause it to interrupt.
244 //
245 m_synchronizer->SetCondition(false);
246 }
247
248 //
249 // We have a time to delay. This time may actually not be valid anymore
250 // since we released the critical section immediately above, and a real-time
251 // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
252 // closing brace above and this comment so to speak. If this is the case,
253 // that schedule operation will have done a synchronizer Signal() that
254 // will set the condition variable to true and cause the Synchronize call
255 // below to return immediately.
256 //
257 // It's easiest to understand if you just consider a short tsDelay that only
258 // requires a SpinWait down in the synchronizer. What will happen is that
259 // when Synchronize calls SpinWait, SpinWait will look directly at its
260 // condition variable. Note that we set this condition variable to false
261 // inside the critical section above.
262 //
263 // SpinWait will go into a forever loop until either the time has expired or
264 // until the condition variable becomes true. A true condition indicates that
265 // the wait should stop. The condition is set to true by one of the Schedule
266 // methods of the simulator; so if we are in a wait down in Synchronize, and
267 // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
268 // Synchronize will return false. This means we have not actually synchronized
269 // to the event expiration time. If no real-time schedule operation is done
270 // while down in Synchronize, the wait will time out and Synchronize will return
271 // true. This indicates that we have synchronized to the event time.
272 //
273 // So we need to stay in this for loop, looking for the next event timestamp and
274 // attempting to sleep until its due. If we've slept until the timestamp is due,
275 // Synchronize returns true and we break out of the sync loop. If an external
276 // event happens that requires a re-schedule, Synchronize returns false and
277 // we re-evaluate our timing by continuing in the loop.
278 //
279 // It is expected that tsDelay become shorter as external events interrupt our
280 // waits.
281 //
282 if (m_synchronizer->Synchronize(tsNow, tsDelay))
283 {
284 NS_LOG_LOGIC("Interrupted ...");
285 break;
286 }
287
288 //
289 // If we get to this point, we have been interrupted during a wait by a real-time
290 // schedule operation. This means all bets are off regarding tsDelay and we need
291 // to re-evaluate what it is we want to do. We'll loop back around in the
292 // for-loop and start again from scratch.
293 //
294 }
295
296 //
297 // If we break out of the for-loop above, we have waited until the time specified
298 // by the event that was at the head of the event list when we started the process.
299 // Since there is a bunch of code that was executed outside a critical section (the
300 // Synchronize call) we cannot be sure that the event at the head of the event list
301 // is the one we think it is. What we can be sure of is that it is time to execute
302 // whatever event is at the head of this list if the list is in time order.
303 //
304 Scheduler::Event next;
305
306 {
307 std::unique_lock lock{m_mutex};
308
309 //
310 // We do know we're waiting for an event, so there had better be an event on the
311 // event queue. Let's pull it off. When we release the critical section, the
312 // event we're working on won't be on the list and so subsequent operations won't
313 // mess with us.
314 //
315 NS_ASSERT_MSG(m_events->IsEmpty() == false,
316 "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
317 next = m_events->RemoveNext();
318
319 PreEventHook(EventId(next.impl, next.key.m_ts, next.key.m_context, next.key.m_uid));
320
322 m_eventCount++;
323
324 //
325 // We cannot make any assumption that "next" is the same event we originally waited
326 // for. We can only assume that only that it must be due and cannot cause time
327 // to move backward.
328 //
330 "RealtimeSimulatorImpl::ProcessOneEvent(): "
331 "next.GetTs() earlier than m_currentTs (list order error)");
332 NS_LOG_LOGIC("handle " << next.key.m_ts);
333
334 //
335 // Update the current simulation time to be the timestamp of the event we're
336 // executing. From the rest of the simulation's point of view, simulation time
337 // is frozen until the next event is executed.
338 //
339 m_currentTs = next.key.m_ts;
341 m_currentUid = next.key.m_uid;
342
343 //
344 // We're about to run the event and we've done our best to synchronize this
345 // event execution time to real time. Now, if we're in SYNC_HARD_LIMIT mode
346 // we have to decide if we've done a good enough job and if we haven't, we've
347 // been asked to commit ritual suicide.
348 //
349 // We check the simulation time against the current real time to make this
350 // judgement.
351 //
353 {
354 uint64_t tsFinal = m_synchronizer->GetCurrentRealtime();
355 uint64_t tsJitter;
356
357 if (tsFinal >= m_currentTs)
358 {
359 tsJitter = tsFinal - m_currentTs;
360 }
361 else
362 {
363 tsJitter = m_currentTs - tsFinal;
364 }
365
366 if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep()))
367 {
368 NS_FATAL_ERROR("RealtimeSimulatorImpl::ProcessOneEvent (): "
369 "Hard real-time limit exceeded (jitter = "
370 << tsJitter << ")");
371 }
372 }
373 }
374
375 //
376 // We have got the event we're about to execute completely disentangled from the
377 // event list so we can execute it outside a critical section without fear of someone
378 // changing things out from under us.
379
380 EventImpl* event = next.impl;
381 m_synchronizer->EventStart();
382 event->Invoke();
383 m_synchronizer->EventEnd();
384 event->Unref();
385}
386
387bool
389{
390 bool rc;
391 {
392 std::unique_lock lock{m_mutex};
393 rc = m_events->IsEmpty() || m_stop;
394 }
395
396 return rc;
397}
398
399//
400// Peeks into event list. Should be called with critical section locked.
401//
402uint64_t
404{
405 NS_ASSERT_MSG(m_events->IsEmpty() == false,
406 "RealtimeSimulatorImpl::NextTs(): event queue is empty");
407 Scheduler::Event ev = m_events->PeekNext();
408 return ev.key.m_ts;
409}
410
411void
413{
414 NS_LOG_FUNCTION(this);
415
416 NS_ASSERT_MSG(m_running == false, "RealtimeSimulatorImpl::Run(): Simulator already running");
417
418 // Set the current threadId as the main threadId
419 m_main = std::this_thread::get_id();
420
421 m_stop = false;
422 m_running = true;
423 m_synchronizer->SetOrigin(m_currentTs);
424
425 // Sleep until signalled
426 uint64_t tsNow = 0;
427 uint64_t tsDelay = 1000000000; // wait time of 1 second (in nanoseconds)
428
429 while (!m_stop)
430 {
431 bool process = false;
432 {
433 std::unique_lock lock{m_mutex};
434
435 if (!m_events->IsEmpty())
436 {
437 process = true;
438 }
439 else
440 {
441 // Get current timestamp while holding the critical section
442 tsNow = m_synchronizer->GetCurrentRealtime();
443 }
444 }
445
446 if (process)
447 {
449 }
450 else
451 {
452 // Sleep until signalled and re-check event queue
453 m_synchronizer->Synchronize(tsNow, tsDelay);
454 }
455 }
456
457 //
458 // If the simulator stopped naturally by lack of events, make a
459 // consistency test to check that we didn't lose any events along the way.
460 //
461 {
462 std::unique_lock lock{m_mutex};
463
464 NS_ASSERT_MSG(m_events->IsEmpty() == false || m_unscheduledEvents == 0,
465 "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events");
466 }
467
468 m_running = false;
469}
470
471bool
473{
474 return m_running;
475}
476
477bool
479{
480 return m_synchronizer->Realtime();
481}
482
483void
485{
486 NS_LOG_FUNCTION(this);
487 m_stop = true;
488}
489
492{
493 NS_LOG_FUNCTION(this << delay);
494 return Simulator::Schedule(delay, &Simulator::Stop);
495}
496
497//
498// Schedule an event for a _relative_ time in the future.
499//
502{
503 NS_LOG_FUNCTION(this << delay << impl);
504
506 {
507 std::unique_lock lock{m_mutex};
508 //
509 // This is the reason we had to bring the absolute time calculation in from the
510 // simulator.h into the implementation. Since the implementations may be
511 // multi-threaded, we need this calculation to be atomic. You can see it is
512 // here since we are running in a CriticalSection.
513 //
514 Time tAbsolute = Simulator::Now() + delay;
515 NS_ASSERT_MSG(delay.IsPositive(), "RealtimeSimulatorImpl::Schedule(): Negative delay");
516 ev.impl = impl;
517 ev.key.m_ts = (uint64_t)tAbsolute.GetTimeStep();
518 ev.key.m_context = GetContext();
519 ev.key.m_uid = m_uid;
520 m_uid++;
522 m_events->Insert(ev);
523 m_synchronizer->Signal();
524 }
525
526 return EventId(impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
527}
528
529void
531{
532 NS_LOG_FUNCTION(this << context << delay << impl);
533
534 {
535 std::unique_lock lock{m_mutex};
536 uint64_t ts;
537
538 if (m_main == std::this_thread::get_id())
539 {
540 ts = m_currentTs + delay.GetTimeStep();
541 }
542 else
543 {
544 //
545 // If the simulator is running, we're pacing and have a meaningful
546 // realtime clock. If we're not, then m_currentTs is where we stopped.
547 //
548 ts = m_running ? m_synchronizer->GetCurrentRealtime() : m_currentTs;
549 ts += delay.GetTimeStep();
550 }
551
553 "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
555 ev.impl = impl;
556 ev.key.m_ts = ts;
557 ev.key.m_context = context;
558 ev.key.m_uid = m_uid;
559 m_uid++;
561 m_events->Insert(ev);
562 m_synchronizer->Signal();
563 }
564}
565
568{
569 NS_LOG_FUNCTION(this << impl);
570 return Schedule(Time(0), impl);
571}
572
573Time
575{
576 return TimeStep(m_currentTs);
577}
578
579//
580// Schedule an event for a _relative_ time in the future.
581//
582void
584 const Time& time,
585 EventImpl* impl)
586{
587 NS_LOG_FUNCTION(this << context << time << impl);
588
589 {
590 std::unique_lock lock{m_mutex};
591
592 uint64_t ts = m_synchronizer->GetCurrentRealtime() + time.GetTimeStep();
594 "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
596 ev.impl = impl;
597 ev.key.m_ts = ts;
598 ev.key.m_uid = m_uid;
599 m_uid++;
601 m_events->Insert(ev);
602 m_synchronizer->Signal();
603 }
604}
605
606void
608{
609 NS_LOG_FUNCTION(this << time << impl);
611}
612
613void
615{
616 NS_LOG_FUNCTION(this << context << impl);
617 {
618 std::unique_lock lock{m_mutex};
619
620 //
621 // If the simulator is running, we're pacing and have a meaningful
622 // realtime clock. If we're not, then m_currentTs is were we stopped.
623 //
624 uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime() : m_currentTs;
626 "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time "
627 "< m_currentTs");
629 ev.impl = impl;
630 ev.key.m_ts = ts;
631 ev.key.m_uid = m_uid;
632 ev.key.m_context = context;
633 m_uid++;
635 m_events->Insert(ev);
636 m_synchronizer->Signal();
637 }
638}
639
640void
646
647Time
649{
650 return TimeStep(m_synchronizer->GetCurrentRealtime());
651}
652
655{
656 NS_LOG_FUNCTION(this << impl);
657
658 EventId id;
659 {
660 std::unique_lock lock{m_mutex};
661
662 //
663 // Time doesn't really matter here (especially in realtime mode). It is
664 // overridden by the uid of DESTROY which identifies this as an event to be
665 // executed at Simulator::Destroy time.
666 //
667 id = EventId(Ptr<EventImpl>(impl, false), m_currentTs, 0xffffffff, EventId::UID::DESTROY);
668 m_destroyEvents.push_back(id);
669 m_uid++;
670 }
671
672 return id;
673}
674
675Time
677{
678 //
679 // If the event has expired, there is no delay until it runs. It is not the
680 // case that there is a negative time until it runs.
681 //
682 if (IsExpired(id))
683 {
684 return TimeStep(0);
685 }
686
687 return TimeStep(id.GetTs() - m_currentTs);
688}
689
690void
692{
693 if (id.GetUid() == EventId::UID::DESTROY)
694 {
695 // destroy events.
696 for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
697 {
698 if (*i == id)
699 {
700 m_destroyEvents.erase(i);
701 break;
702 }
703 }
704 return;
705 }
706 if (IsExpired(id))
707 {
708 return;
709 }
710
711 {
712 std::unique_lock lock{m_mutex};
713
714 Scheduler::Event event;
715 event.impl = id.PeekEventImpl();
716 event.key.m_ts = id.GetTs();
717 event.key.m_context = id.GetContext();
718 event.key.m_uid = id.GetUid();
719
720 m_events->Remove(event);
722 event.impl->Cancel();
723 event.impl->Unref();
724 }
725}
726
727void
729{
730 if (!IsExpired(id))
731 {
732 id.PeekEventImpl()->Cancel();
733 }
734}
735
736bool
738{
739 if (id.GetUid() == EventId::UID::DESTROY)
740 {
741 if (id.PeekEventImpl() == nullptr || id.PeekEventImpl()->IsCancelled())
742 {
743 return true;
744 }
745 // destroy events.
746 for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
747 {
748 if (*i == id)
749 {
750 return false;
751 }
752 }
753 return true;
754 }
755
756 //
757 // If the time of the event is less than the current timestamp of the
758 // simulator, the simulator has gone past the invocation time of the
759 // event, so the statement ev.GetTs () < m_currentTs does mean that
760 // the event has been fired even in realtime mode.
761 //
762 // The same is true for the next line involving the m_currentUid.
763 //
764 return id.PeekEventImpl() == nullptr || id.GetTs() < m_currentTs ||
765 (id.GetTs() == m_currentTs && id.GetUid() <= m_currentUid) ||
766 id.PeekEventImpl()->IsCancelled();
767}
768
769Time
771{
772 return TimeStep(0x7fffffffffffffffLL);
773}
774
775// System ID for non-distributed simulation is always zero
778{
779 return 0;
780}
781
787
788uint64_t
793
794void
800
807
808void
810{
811 NS_LOG_FUNCTION(this << limit);
812 m_hardLimit = limit;
813}
814
815Time
817{
818 NS_LOG_FUNCTION(this);
819 return m_hardLimit;
820}
821
822} // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
ns3::BooleanValue attribute value declarations.
Hold variables of type enum.
Definition enum.h:52
An identifier for simulation events.
Definition event-id.h:45
@ INVALID
Invalid UID value.
Definition event-id.h:51
@ VALID
Schedule(), etc.
Definition event-id.h:59
@ DESTROY
ScheduleDestroy() events.
Definition event-id.h:55
A simulation event.
Definition event-impl.h:35
void Invoke()
Called by the simulation engine to notify the event that it is time to execute.
Definition event-impl.cc:36
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:433
Smart pointer class similar to boost::intrusive_ptr.
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:146
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:560
@ NO_CONTEXT
Flag for events not associated with any particular context.
Definition simulator.h:199
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
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:94
bool IsPositive() const
Exactly equivalent to t >= 0.
Definition nstime.h:322
int64_t GetTimeStep() const
Get the raw time value, in the current resolution unit.
Definition nstime.h:434
AttributeValue implementation for Time.
Definition nstime.h:1395
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
ns3::EnumValue attribute value declarations.
ns3::EventImpl declarations.
NS_FATAL_x macro definitions.
#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:75
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:221
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:1396
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:179
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:173
EventKey key
Key for sorting and ordering Events.
Definition scheduler.h:175
EventImpl * impl
Pointer to the event implementation.
Definition scheduler.h:174
uint32_t m_context
Event context.
Definition scheduler.h:162
uint64_t m_ts
Event time stamp.
Definition scheduler.h:160
uint32_t m_uid
Event unique id.
Definition scheduler.h:161
ns3::Synchronizer declaration.
ns3::WallClockSynchronizer declaration.