A Discrete-Event Network Simulator
API
realtime-simulator-impl.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2008 University of Washington
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include "simulator.h"
22#include "scheduler.h"
23#include "event-impl.h"
24#include "synchronizer.h"
25
26#include "ptr.h"
27#include "pointer.h"
28#include "assert.h"
29#include "fatal-error.h"
30#include "log.h"
31#include "system-mutex.h"
32#include "boolean.h"
33#include "enum.h"
34
35
36#include <cmath>
37
38
45namespace ns3 {
46
47// Note: Logging in this file is largely avoided due to the
48// number of calls that are made to these functions and the possibility
49// of causing recursions leading to stack overflow
50NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorImpl");
51
52NS_OBJECT_ENSURE_REGISTERED (RealtimeSimulatorImpl);
53
54TypeId
56{
57 static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
59 .SetGroupName ("Core")
60 .AddConstructor<RealtimeSimulatorImpl> ()
61 .AddAttribute ("SynchronizationMode",
62 "What to do if the simulation cannot keep up with real time.",
65 MakeEnumChecker (SYNC_BEST_EFFORT, "BestEffort",
66 SYNC_HARD_LIMIT, "HardLimit"))
67 .AddAttribute ("HardLimit",
68 "Maximum acceptable real-time jitter (used in conjunction with SynchronizationMode=HardLimit)",
69 TimeValue (Seconds (0.1)),
72 ;
73 return tid;
74}
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
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
102void
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 = 0;
112 m_synchronizer = 0;
114}
115
116void
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 () == false)
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 () == false)
135 {
136 ev->Invoke ();
137 }
138 }
139}
140
141void
143{
144 NS_LOG_FUNCTION (this << schedulerFactory);
145
146 Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
147
148 {
150
151 if (m_events != 0)
152 {
153 while (m_events->IsEmpty () == false)
154 {
155 Scheduler::Event next = m_events->RemoveNext ();
156 scheduler->Insert (next);
157 }
158 }
159 m_events = scheduler;
160 }
161}
162
163void
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 {
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 //
217 NS_ASSERT_MSG (m_synchronizer->Realtime (),
218 "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
219
220 //
221 // tsNow is set to the normalized current real time. When the simulation was
222 // started, the current real time was effectively set to zero; so tsNow is
223 // the current "real" simulation time.
224 //
225 // tsNext is the simulation time of the next event we want to execute.
226 //
227 tsNow = m_synchronizer->GetCurrentRealtime ();
228 tsNext = NextTs ();
229
230 //
231 // tsDelay is therefore the real time we need to delay in order to bring the
232 // real time in sync with the simulation time. If we wait for this amount of
233 // real time, we will accomplish moving the simulation time at the same rate
234 // as the real time. This is typically called "pacing" the simulation time.
235 //
236 // We do have to be careful if we are falling behind. If so, tsDelay must be
237 // zero. If we're late, don't dawdle.
238 //
239 if (tsNext <= tsNow)
240 {
241 tsDelay = 0;
242 }
243 else
244 {
245 tsDelay = tsNext - tsNow;
246 }
247
248 //
249 // We've figured out how long we need to delay in order to pace the
250 // simulation time with the real time. We're going to sleep, but need
251 // to work with the synchronizer to make sure we're awakened if something
252 // external happens (like a packet is received). This next line resets
253 // the synchronizer so that any future event will cause it to interrupt.
254 //
255 m_synchronizer->SetCondition (false);
256 }
257
258 //
259 // We have a time to delay. This time may actually not be valid anymore
260 // since we released the critical section immediately above, and a real-time
261 // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
262 // closing brace above and this comment so to speak. If this is the case,
263 // that schedule operation will have done a synchronizer Signal() that
264 // will set the condition variable to true and cause the Synchronize call
265 // below to return immediately.
266 //
267 // It's easiest to understand if you just consider a short tsDelay that only
268 // requires a SpinWait down in the synchronizer. What will happen is that
269 // whan Synchronize calls SpinWait, SpinWait will look directly at its
270 // condition variable. Note that we set this condition variable to false
271 // inside the critical section above.
272 //
273 // SpinWait will go into a forever loop until either the time has expired or
274 // until the condition variable becomes true. A true condition indicates that
275 // the wait should stop. The condition is set to true by one of the Schedule
276 // methods of the simulator; so if we are in a wait down in Synchronize, and
277 // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
278 // Synchronize will return false. This means we have not actually synchronized
279 // to the event expiration time. If no real-time schedule operation is done
280 // while down in Synchronize, the wait will time out and Synchronize will return
281 // true. This indicates that we have synchronized to the event time.
282 //
283 // So we need to stay in this for loop, looking for the next event timestamp and
284 // attempting to sleep until its due. If we've slept until the timestamp is due,
285 // Synchronize returns true and we break out of the sync loop. If an external
286 // event happens that requires a re-schedule, Synchronize returns false and
287 // we re-evaluate our timing by continuing in the loop.
288 //
289 // It is expected that tsDelay become shorter as external events interrupt our
290 // waits.
291 //
292 if (m_synchronizer->Synchronize (tsNow, tsDelay))
293 {
294 NS_LOG_LOGIC ("Interrupted ...");
295 break;
296 }
297
298 //
299 // If we get to this point, we have been interrupted during a wait by a real-time
300 // schedule operation. This means all bets are off regarding tsDelay and we need
301 // to re-evaluate what it is we want to do. We'll loop back around in the
302 // for-loop and start again from scratch.
303 //
304 }
305
306 //
307 // If we break out of the for-loop above, we have waited until the time specified
308 // by the event that was at the head of the event list when we started the process.
309 // Since there is a bunch of code that was executed outside a critical section (the
310 // Synchronize call) we cannot be sure that the event at the head of the event list
311 // is the one we think it is. What we can be sure of is that it is time to execute
312 // whatever event is at the head of this list if the list is in time order.
313 //
314 Scheduler::Event next;
315
316 {
318
319 //
320 // We do know we're waiting for an event, so there had better be an event on the
321 // event queue. Let's pull it off. When we release the critical section, the
322 // event we're working on won't be on the list and so subsequent operations won't
323 // mess with us.
324 //
325 NS_ASSERT_MSG (m_events->IsEmpty () == false,
326 "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
327 next = m_events->RemoveNext ();
328
329 PreEventHook (EventId (next.impl, next.key.m_ts,
330 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 = " << tsJitter << ")");
381 }
382 }
383 }
384
385 //
386 // We have got the event we're about to execute completely disentangled from the
387 // event list so we can execute it outside a critical section without fear of someone
388 // changing things out from under us.
389
390 EventImpl *event = next.impl;
391 m_synchronizer->EventStart ();
392 event->Invoke ();
393 m_synchronizer->EventEnd ();
394 event->Unref ();
395}
396
397bool
399{
400 bool rc;
401 {
403 rc = m_events->IsEmpty () || m_stop;
404 }
405
406 return rc;
407}
408
409//
410// Peeks into event list. Should be called with critical section locked.
411//
412uint64_t
414{
415 NS_ASSERT_MSG (m_events->IsEmpty () == false,
416 "RealtimeSimulatorImpl::NextTs(): event queue is empty");
417 Scheduler::Event ev = m_events->PeekNext ();
418 return ev.key.m_ts;
419}
420
421void
423{
424 NS_LOG_FUNCTION (this);
425
426 NS_ASSERT_MSG (m_running == false,
427 "RealtimeSimulatorImpl::Run(): Simulator already running");
428
429 // Set the current threadId as the main threadId
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 {
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 // Sleep until signalled
460 tsNow = m_synchronizer->Synchronize (tsNow, tsDelay);
461
462 // Re-check event queue
463 continue;
464 }
465
467 }
468
469 //
470 // If the simulator stopped naturally by lack of events, make a
471 // consistency test to check that we didn't lose any events along the way.
472 //
473 {
475
476 NS_ASSERT_MSG (m_events->IsEmpty () == false || m_unscheduledEvents == 0,
477 "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events");
478 }
479
480 m_running = false;
481}
482
483bool
485{
486 return m_running;
487}
488
489bool
491{
492 return m_synchronizer->Realtime ();
493}
494
495void
497{
498 NS_LOG_FUNCTION (this);
499 m_stop = true;
500}
501
502void
504{
505 NS_LOG_FUNCTION (this << delay);
507}
508
509//
510// Schedule an event for a _relative_ time in the future.
511//
514{
515 NS_LOG_FUNCTION (this << delay << impl);
516
518 {
520 //
521 // This is the reason we had to bring the absolute time calculation in from the
522 // simulator.h into the implementation. Since the implementations may be
523 // multi-threaded, we need this calculation to be atomic. You can see it is
524 // here since we are running in a CriticalSection.
525 //
526 Time tAbsolute = Simulator::Now () + delay;
527 NS_ASSERT_MSG (delay.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative delay");
528 ev.impl = impl;
529 ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
530 ev.key.m_context = GetContext ();
531 ev.key.m_uid = m_uid;
532 m_uid++;
534 m_events->Insert (ev);
535 m_synchronizer->Signal ();
536 }
537
538 return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
539}
540
541void
543{
544 NS_LOG_FUNCTION (this << context << delay << impl);
545
546 {
548 uint64_t ts;
549
551 {
552 ts = m_currentTs + delay.GetTimeStep ();
553 }
554 else
555 {
556 //
557 // If the simulator is running, we're pacing and have a meaningful
558 // realtime clock. If we're not, then m_currentTs is where we stopped.
559 //
560 ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
561 ts += delay.GetTimeStep ();
562 }
563
564 NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
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
579{
580 NS_LOG_FUNCTION (this << impl);
581 return Schedule (Time (0), impl);
582}
583
584Time
586{
587 return TimeStep (m_currentTs);
588}
589
590//
591// Schedule an event for a _relative_ time in the future.
592//
593void
595{
596 NS_LOG_FUNCTION (this << context << time << impl);
597
598 {
600
601 uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
602 NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
604 ev.impl = impl;
605 ev.key.m_ts = ts;
606 ev.key.m_uid = m_uid;
607 m_uid++;
609 m_events->Insert (ev);
610 m_synchronizer->Signal ();
611 }
612}
613
614void
616{
617 NS_LOG_FUNCTION (this << time << impl);
619}
620
621void
623{
624 NS_LOG_FUNCTION (this << context << impl);
625 {
627
628 //
629 // If the simulator is running, we're pacing and have a meaningful
630 // realtime clock. If we're not, then m_currentTs is were we stopped.
631 //
632 uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
634 "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
636 ev.impl = impl;
637 ev.key.m_ts = ts;
638 ev.key.m_uid = m_uid;
639 ev.key.m_context = context;
640 m_uid++;
642 m_events->Insert (ev);
643 m_synchronizer->Signal ();
644 }
645}
646
647void
649{
650 NS_LOG_FUNCTION (this << impl);
652}
653
654Time
656{
657 return TimeStep (m_synchronizer->GetCurrentRealtime ());
658}
659
662{
663 NS_LOG_FUNCTION (this << impl);
664
665 EventId id;
666 {
668
669 //
670 // Time doesn't really matter here (especially in realtime mode). It is
671 // overridden by the uid of DESTROY which identifies this as an event to be
672 // executed at Simulator::Destroy time.
673 //
674 id = EventId (Ptr<EventImpl> (impl, false), m_currentTs, 0xffffffff,
675 EventId::UID::DESTROY);
676 m_destroyEvents.push_back (id);
677 m_uid++;
678 }
679
680 return id;
681}
682
683Time
685{
686 //
687 // If the event has expired, there is no delay until it runs. It is not the
688 // case that there is a negative time until it runs.
689 //
690 if (IsExpired (id))
691 {
692 return TimeStep (0);
693 }
694
695 return TimeStep (id.GetTs () - m_currentTs);
696}
697
698void
700{
701 if (id.GetUid () == EventId::UID::DESTROY)
702 {
703 // destroy events.
704 for (DestroyEvents::iterator i = m_destroyEvents.begin ();
705 i != m_destroyEvents.end ();
706 i++)
707 {
708 if (*i == id)
709 {
710 m_destroyEvents.erase (i);
711 break;
712 }
713 }
714 return;
715 }
716 if (IsExpired (id))
717 {
718 return;
719 }
720
721 {
723
724 Scheduler::Event event;
725 event.impl = id.PeekEventImpl ();
726 event.key.m_ts = id.GetTs ();
727 event.key.m_context = id.GetContext ();
728 event.key.m_uid = id.GetUid ();
729
730 m_events->Remove (event);
732 event.impl->Cancel ();
733 event.impl->Unref ();
734 }
735}
736
737void
739{
740 if (IsExpired (id) == false)
741 {
742 id.PeekEventImpl ()->Cancel ();
743 }
744}
745
746bool
748{
749 if (id.GetUid () == EventId::UID::DESTROY)
750 {
751 if (id.PeekEventImpl () == 0
752 || id.PeekEventImpl ()->IsCancelled ())
753 {
754 return true;
755 }
756 // destroy events.
757 for (DestroyEvents::const_iterator i = m_destroyEvents.begin ();
758 i != m_destroyEvents.end (); i++)
759 {
760 if (*i == id)
761 {
762 return false;
763 }
764 }
765 return true;
766 }
767
768 //
769 // If the time of the event is less than the current timestamp of the
770 // simulator, the simulator has gone past the invocation time of the
771 // event, so the statement ev.GetTs () < m_currentTs does mean that
772 // the event has been fired even in realtime mode.
773 //
774 // The same is true for the next line involving the m_currentUid.
775 //
776 if (id.PeekEventImpl () == 0
777 || id.GetTs () < m_currentTs
778 || (id.GetTs () == m_currentTs && id.GetUid () <= m_currentUid)
779 || id.PeekEventImpl ()->IsCancelled ())
780 {
781 return true;
782 }
783 else
784 {
785 return false;
786 }
787}
788
789Time
791{
792 return TimeStep (0x7fffffffffffffffLL);
793}
794
795// System ID for non-distributed simulation is always zero
798{
799 return 0;
800}
801
804{
805 return m_currentContext;
806}
807
808uint64_t
810{
811 return m_eventCount;
812}
813
814void
816{
817 NS_LOG_FUNCTION (this << mode);
819}
820
823{
824 NS_LOG_FUNCTION (this);
826}
827
828void
830{
831 NS_LOG_FUNCTION (this << limit);
832 m_hardLimit = limit;
833}
834
835Time
837{
838 NS_LOG_FUNCTION (this);
839 return m_hardLimit;
840}
841
842} // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
ns3::BooleanValue attribute value declarations.
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:119
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.
SystemMutex m_mutex
Mutex to control access to key state.
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.
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).
SystemThread::ThreadId m_main
Main SystemThread.
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.
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
@ NO_CONTEXT
Flag for events not associated with any particular context.
Definition: simulator.h:199
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
The SimulatorImpl base class.
virtual void PreEventHook(const EventId &id)
Hook called before processing each event.
static ThreadId Self(void)
Returns the current thread Id.
static bool Equals(ThreadId id)
Compares an ThreadId with the current ThreadId .
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)
Definition: enum.h:205
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
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 > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:536
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
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.
System-independent mutex primitive, ns3::SystemMutex, and ns3::CriticalSection.
ns3::WallClockSynchronizer declaration.