A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 // Note: Logging in this file is largely avoided due to the
39 // number of calls that are made to these functions and the possibility
40 // of causing recursions leading to stack overflow
41 
42 NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorImpl");
43 
44 namespace ns3 {
45 
46 NS_OBJECT_ENSURE_REGISTERED (RealtimeSimulatorImpl)
47  ;
48 
49 TypeId
51 {
52  static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
54  .AddConstructor<RealtimeSimulatorImpl> ()
55  .AddAttribute ("SynchronizationMode",
56  "What to do if the simulation cannot keep up with real time.",
59  MakeEnumChecker (SYNC_BEST_EFFORT, "BestEffort",
60  SYNC_HARD_LIMIT, "HardLimit"))
61  .AddAttribute ("HardLimit",
62  "Maximum acceptable real-time jitter (used in conjunction with SynchronizationMode=HardLimit)",
63  TimeValue (Seconds (0.1)),
64  MakeTimeAccessor (&RealtimeSimulatorImpl::m_hardLimit),
65  MakeTimeChecker ())
66  ;
67  return tid;
68 }
69 
70 
72 {
73  NS_LOG_FUNCTION (this);
74 
75  m_stop = false;
76  m_running = false;
77  // uids are allocated from 4.
78  // uid 0 is "invalid" events
79  // uid 1 is "now" events
80  // uid 2 is "destroy" events
81  m_uid = 4;
82  // before ::Run is entered, the m_currentUid will be zero
83  m_currentUid = 0;
84  m_currentTs = 0;
85  m_currentContext = 0xffffffff;
87 
89 
90  // Be very careful not to do anything that would cause a change or assignment
91  // of the underlying reference counts of m_synchronizer or you will be sorry.
92  m_synchronizer = CreateObject<WallClockSynchronizer> ();
93 }
94 
96 {
97  NS_LOG_FUNCTION (this);
98 }
99 
100 void
102 {
103  NS_LOG_FUNCTION (this);
104  while (!m_events->IsEmpty ())
105  {
106  Scheduler::Event next = m_events->RemoveNext ();
107  next.impl->Unref ();
108  }
109  m_events = 0;
110  m_synchronizer = 0;
112 }
113 
114 void
116 {
117  NS_LOG_FUNCTION (this);
118 
119  //
120  // This function is only called with the private version "disconnected" from
121  // the main simulator functions. We rely on the user not calling
122  // Simulator::Destroy while there is a chance that a worker thread could be
123  // accessing the current instance of the private object. In practice this
124  // means shutting down the workers and doing a Join() before calling the
125  // Simulator::Destroy().
126  //
127  while (m_destroyEvents.empty () == false)
128  {
129  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
130  m_destroyEvents.pop_front ();
131  NS_LOG_LOGIC ("handle destroy " << ev);
132  if (ev->IsCancelled () == false)
133  {
134  ev->Invoke ();
135  }
136  }
137 }
138 
139 void
141 {
142  NS_LOG_FUNCTION (this << schedulerFactory);
143 
144  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
145 
146  {
148 
149  if (m_events != 0)
150  {
151  while (m_events->IsEmpty () == false)
152  {
153  Scheduler::Event next = m_events->RemoveNext ();
154  scheduler->Insert (next);
155  }
156  }
157  m_events = scheduler;
158  }
159 }
160 
161 void
163 {
164  //
165  // The idea here is to wait until the next event comes due. In the case of
166  // a realtime simulation, we want real time to be consumed between events.
167  // It is the realtime synchronizer that causes real time to be consumed by
168  // doing some kind of a wait.
169  //
170  // We need to be able to have external events (such as a packet reception event)
171  // cause us to re-evaluate our state. The way this works is that the synchronizer
172  // gets interrupted and returns. So, there is a possibility that things may change
173  // out from under us dynamically. In this case, we need to re-evaluate how long to
174  // wait in a for-loop until we have waited sucessfully (until a timeout) for the
175  // event at the head of the event list.
176  //
177  // m_synchronizer->Synchronize will return true if the wait was completed without
178  // interruption, otherwise it will return false indicating that something has changed
179  // out from under us. If we sit in the for-loop trying to synchronize until
180  // Synchronize() returns true, we will have successfully synchronized the execution
181  // time of the next event with the wall clock time of the synchronizer.
182  //
183 
184  for (;;)
185  {
186  uint64_t tsDelay = 0;
187  uint64_t tsNext = 0;
188 
189  //
190  // It is important to understand that m_currentTs is interpreted only as the
191  // timestamp of the last event we executed. Current time can a bit of a
192  // slippery concept in realtime mode. What we have here is a discrete event
193  // simulator, so the last event is, by defintion, executed entirely at a single
194  // discrete time. This is the definition of m_currentTs. It really has
195  // nothing to do with the current real time, except that we are trying to arrange
196  // that at the instant of the beginning of event execution, the current real time
197  // and m_currentTs coincide.
198  //
199  // We use tsNow as the indication of the current real time.
200  //
201  uint64_t tsNow;
202 
203  {
205  //
206  // Since we are in realtime mode, the time to delay has got to be the
207  // difference between the current realtime and the timestamp of the next
208  // event. Since m_currentTs is actually the timestamp of the last event we
209  // executed, it's not particularly meaningful for us here since real time has
210  // certainly elapsed since it was last updated.
211  //
212  // It is possible that the current realtime has drifted past the next event
213  // time so we need to be careful about that and not delay in that case.
214  //
215  NS_ASSERT_MSG (m_synchronizer->Realtime (),
216  "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
217 
218  //
219  // tsNow is set to the normalized current real time. When the simulation was
220  // started, the current real time was effectively set to zero; so tsNow is
221  // the current "real" simulation time.
222  //
223  // tsNext is the simulation time of the next event we want to execute.
224  //
225  tsNow = m_synchronizer->GetCurrentRealtime ();
226  tsNext = NextTs ();
227 
228  //
229  // tsDelay is therefore the real time we need to delay in order to bring the
230  // real time in sync with the simulation time. If we wait for this amount of
231  // real time, we will accomplish moving the simulation time at the same rate
232  // as the real time. This is typically called "pacing" the simulation time.
233  //
234  // We do have to be careful if we are falling behind. If so, tsDelay must be
235  // zero. If we're late, don't dawdle.
236  //
237  if (tsNext <= tsNow)
238  {
239  tsDelay = 0;
240  }
241  else
242  {
243  tsDelay = tsNext - tsNow;
244  }
245 
246  //
247  // We've figured out how long we need to delay in order to pace the
248  // simulation time with the real time. We're going to sleep, but need
249  // to work with the synchronizer to make sure we're awakened if something
250  // external happens (like a packet is received). This next line resets
251  // the synchronizer so that any future event will cause it to interrupt.
252  //
253  m_synchronizer->SetCondition (false);
254  }
255 
256  //
257  // We have a time to delay. This time may actually not be valid anymore
258  // since we released the critical section immediately above, and a real-time
259  // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
260  // closing brace above and this comment so to speak. If this is the case,
261  // that schedule operation will have done a synchronizer Signal() that
262  // will set the condition variable to true and cause the Synchronize call
263  // below to return immediately.
264  //
265  // It's easiest to understand if you just consider a short tsDelay that only
266  // requires a SpinWait down in the synchronizer. What will happen is that
267  // whan Synchronize calls SpinWait, SpinWait will look directly at its
268  // condition variable. Note that we set this condition variable to false
269  // inside the critical section above.
270  //
271  // SpinWait will go into a forever loop until either the time has expired or
272  // until the condition variable becomes true. A true condition indicates that
273  // the wait should stop. The condition is set to true by one of the Schedule
274  // methods of the simulator; so if we are in a wait down in Synchronize, and
275  // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
276  // Synchronize will return false. This means we have not actually synchronized
277  // to the event expiration time. If no real-time schedule operation is done
278  // while down in Synchronize, the wait will time out and Synchronize will return
279  // true. This indicates that we have synchronized to the event time.
280  //
281  // So we need to stay in this for loop, looking for the next event timestamp and
282  // attempting to sleep until its due. If we've slept until the timestamp is due,
283  // Synchronize returns true and we break out of the sync loop. If an external
284  // event happens that requires a re-schedule, Synchronize returns false and
285  // we re-evaluate our timing by continuing in the loop.
286  //
287  // It is expected that tsDelay become shorter as external events interrupt our
288  // waits.
289  //
290  if (m_synchronizer->Synchronize (tsNow, tsDelay))
291  {
292  NS_LOG_LOGIC ("Interrupted ...");
293  break;
294  }
295 
296  //
297  // If we get to this point, we have been interrupted during a wait by a real-time
298  // schedule operation. This means all bets are off regarding tsDelay and we need
299  // to re-evaluate what it is we want to do. We'll loop back around in the
300  // for-loop and start again from scratch.
301  //
302  }
303 
304  //
305  // If we break out of the for-loop above, we have waited until the time specified
306  // by the event that was at the head of the event list when we started the process.
307  // Since there is a bunch of code that was executed outside a critical section (the
308  // Synchronize call) we cannot be sure that the event at the head of the event list
309  // is the one we think it is. What we can be sure of is that it is time to execute
310  // whatever event is at the head of this list if the list is in time order.
311  //
312  Scheduler::Event next;
313 
314  {
316 
317  //
318  // We do know we're waiting for an event, so there had better be an event on the
319  // event queue. Let's pull it off. When we release the critical section, the
320  // event we're working on won't be on the list and so subsequent operations won't
321  // mess with us.
322  //
323  NS_ASSERT_MSG (m_events->IsEmpty () == false,
324  "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
325  next = m_events->RemoveNext ();
327 
328  //
329  // We cannot make any assumption that "next" is the same event we originally waited
330  // for. We can only assume that only that it must be due and cannot cause time
331  // to move backward.
332  //
333  NS_ASSERT_MSG (next.key.m_ts >= m_currentTs,
334  "RealtimeSimulatorImpl::ProcessOneEvent(): "
335  "next.GetTs() earlier than m_currentTs (list order error)");
336  NS_LOG_LOGIC ("handle " << next.key.m_ts);
337 
338  //
339  // Update the current simulation time to be the timestamp of the event we're
340  // executing. From the rest of the simulation's point of view, simulation time
341  // is frozen until the next event is executed.
342  //
343  m_currentTs = next.key.m_ts;
344  m_currentContext = next.key.m_context;
345  m_currentUid = next.key.m_uid;
346 
347  //
348  // We're about to run the event and we've done our best to synchronize this
349  // event execution time to real time. Now, if we're in SYNC_HARD_LIMIT mode
350  // we have to decide if we've done a good enough job and if we haven't, we've
351  // been asked to commit ritual suicide.
352  //
353  // We check the simulation time against the current real time to make this
354  // judgement.
355  //
357  {
358  uint64_t tsFinal = m_synchronizer->GetCurrentRealtime ();
359  uint64_t tsJitter;
360 
361  if (tsFinal >= m_currentTs)
362  {
363  tsJitter = tsFinal - m_currentTs;
364  }
365  else
366  {
367  tsJitter = m_currentTs - tsFinal;
368  }
369 
370  if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep ()))
371  {
372  NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): "
373  "Hard real-time limit exceeded (jitter = " << tsJitter << ")");
374  }
375  }
376  }
377 
378  //
379  // We have got the event we're about to execute completely disentangled from the
380  // event list so we can execute it outside a critical section without fear of someone
381  // changing things out from under us.
382 
383  EventImpl *event = next.impl;
384  m_synchronizer->EventStart ();
385  event->Invoke ();
386  m_synchronizer->EventEnd ();
387  event->Unref ();
388 }
389 
390 bool
392 {
393  bool rc;
394  {
396  rc = m_events->IsEmpty () || m_stop;
397  }
398 
399  return rc;
400 }
401 
402 //
403 // Peeks into event list. Should be called with critical section locked.
404 //
405 uint64_t
407 {
408  NS_ASSERT_MSG (m_events->IsEmpty () == false,
409  "RealtimeSimulatorImpl::NextTs(): event queue is empty");
410  Scheduler::Event ev = m_events->PeekNext ();
411  return ev.key.m_ts;
412 }
413 
414 void
416 {
417  NS_LOG_FUNCTION (this);
418 
419  NS_ASSERT_MSG (m_running == false,
420  "RealtimeSimulatorImpl::Run(): Simulator already running");
421 
422  // Set the current threadId as the main threadId
424 
425  m_stop = false;
426  m_running = true;
427  m_synchronizer->SetOrigin (m_currentTs);
428 
429  // Sleep until signalled
430  uint64_t tsNow;
431  uint64_t tsDelay = 1000000000; // wait time of 1 second (in nanoseconds)
432 
433  while (!m_stop)
434  {
435  bool process = false;
436  {
438 
439  if (!m_events->IsEmpty ())
440  {
441  process = true;
442  }
443  else
444  {
445  // Get current timestamp while holding the critical section
446  tsNow = m_synchronizer->GetCurrentRealtime ();
447  }
448  }
449 
450  if (!process)
451  {
452  // Sleep until signalled
453  tsNow = m_synchronizer->Synchronize (tsNow, tsDelay);
454 
455  // Re-check event queue
456  continue;
457  }
458 
459  ProcessOneEvent ();
460  }
461 
462  //
463  // If the simulator stopped naturally by lack of events, make a
464  // consistency test to check that we didn't lose any events along the way.
465  //
466  {
468 
469  NS_ASSERT_MSG (m_events->IsEmpty () == false || m_unscheduledEvents == 0,
470  "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events");
471  }
472 
473  m_running = false;
474 }
475 
476 bool
478 {
479  return m_running;
480 }
481 
482 bool
484 {
485  return m_synchronizer->Realtime ();
486 }
487 
488 void
490 {
491  NS_LOG_FUNCTION (this);
492  m_stop = true;
493 }
494 
495 void
497 {
498  NS_LOG_FUNCTION (this << time);
500 }
501 
502 //
503 // Schedule an event for a _relative_ time in the future.
504 //
505 EventId
507 {
508  NS_LOG_FUNCTION (this << time << impl);
509 
510  Scheduler::Event ev;
511  {
513  //
514  // This is the reason we had to bring the absolute time calcualtion in from the
515  // simulator.h into the implementation. Since the implementations may be
516  // multi-threaded, we need this calculation to be atomic. You can see it is
517  // here since we are running in a CriticalSection.
518  //
519  Time tAbsolute = Simulator::Now () + time;
520  NS_ASSERT_MSG (tAbsolute.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative time");
521  NS_ASSERT_MSG (tAbsolute >= TimeStep (m_currentTs), "RealtimeSimulatorImpl::Schedule(): time < m_currentTs");
522  ev.impl = impl;
523  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
524  ev.key.m_context = GetContext ();
525  ev.key.m_uid = m_uid;
526  m_uid++;
528  m_events->Insert (ev);
529  m_synchronizer->Signal ();
530  }
531 
532  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
533 }
534 
535 void
536 RealtimeSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *impl)
537 {
538  NS_LOG_FUNCTION (this << context << time << impl);
539 
540  {
542  uint64_t ts;
543 
545  {
546  ts = m_currentTs + time.GetTimeStep ();
547  }
548  else
549  {
550  //
551  // If the simulator is running, we're pacing and have a meaningful
552  // realtime clock. If we're not, then m_currentTs is where we stopped.
553  //
554  ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
555  ts += time.GetTimeStep ();
556  }
557 
558  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
559  Scheduler::Event ev;
560  ev.impl = impl;
561  ev.key.m_ts = ts;
562  ev.key.m_context = context;
563  ev.key.m_uid = m_uid;
564  m_uid++;
566  m_events->Insert (ev);
567  m_synchronizer->Signal ();
568  }
569 }
570 
571 EventId
573 {
574  NS_LOG_FUNCTION (this << impl);
575  Scheduler::Event ev;
576  {
578 
579  ev.impl = impl;
580  ev.key.m_ts = m_currentTs;
581  ev.key.m_context = GetContext ();
582  ev.key.m_uid = m_uid;
583  m_uid++;
585  m_events->Insert (ev);
586  m_synchronizer->Signal ();
587  }
588 
589  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
590 }
591 
592 Time
594 {
595  return TimeStep (m_currentTs);
596 }
597 
598 //
599 // Schedule an event for a _relative_ time in the future.
600 //
601 void
603 {
604  NS_LOG_FUNCTION (this << context << time << impl);
605 
606  {
608 
609  uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
610  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
611  Scheduler::Event ev;
612  ev.impl = impl;
613  ev.key.m_ts = ts;
614  ev.key.m_uid = m_uid;
615  m_uid++;
617  m_events->Insert (ev);
618  m_synchronizer->Signal ();
619  }
620 }
621 
622 void
624 {
625  NS_LOG_FUNCTION (this << time << impl);
626  ScheduleRealtimeWithContext (GetContext (), time, impl);
627 }
628 
629 void
631 {
632  NS_LOG_FUNCTION (this << context << impl);
633  {
635 
636  //
637  // If the simulator is running, we're pacing and have a meaningful
638  // realtime clock. If we're not, then m_currentTs is were we stopped.
639  //
640  uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
641  NS_ASSERT_MSG (ts >= m_currentTs,
642  "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
643  Scheduler::Event ev;
644  ev.impl = impl;
645  ev.key.m_ts = ts;
646  ev.key.m_uid = m_uid;
647  ev.key.m_context = context;
648  m_uid++;
650  m_events->Insert (ev);
651  m_synchronizer->Signal ();
652  }
653 }
654 
655 void
657 {
658  NS_LOG_FUNCTION (this << impl);
660 }
661 
662 Time
664 {
665  return TimeStep (m_synchronizer->GetCurrentRealtime ());
666 }
667 
668 EventId
670 {
671  NS_LOG_FUNCTION (this << impl);
672 
673  EventId id;
674  {
676 
677  //
678  // Time doesn't really matter here (especially in realtime mode). It is
679  // overridden by the uid of 2 which identifies this as an event to be
680  // executed at Simulator::Destroy time.
681  //
682  id = EventId (Ptr<EventImpl> (impl, false), m_currentTs, 0xffffffff, 2);
683  m_destroyEvents.push_back (id);
684  m_uid++;
685  }
686 
687  return id;
688 }
689 
690 Time
692 {
693  //
694  // If the event has expired, there is no delay until it runs. It is not the
695  // case that there is a negative time until it runs.
696  //
697  if (IsExpired (id))
698  {
699  return TimeStep (0);
700  }
701 
702  return TimeStep (id.GetTs () - m_currentTs);
703 }
704 
705 void
707 {
708  if (id.GetUid () == 2)
709  {
710  // destroy events.
711  for (DestroyEvents::iterator i = m_destroyEvents.begin ();
712  i != m_destroyEvents.end ();
713  i++)
714  {
715  if (*i == id)
716  {
717  m_destroyEvents.erase (i);
718  break;
719  }
720  }
721  return;
722  }
723  if (IsExpired (id))
724  {
725  return;
726  }
727 
728  {
730 
731  Scheduler::Event event;
732  event.impl = id.PeekEventImpl ();
733  event.key.m_ts = id.GetTs ();
734  event.key.m_context = id.GetContext ();
735  event.key.m_uid = id.GetUid ();
736 
737  m_events->Remove (event);
739  event.impl->Cancel ();
740  event.impl->Unref ();
741  }
742 }
743 
744 void
746 {
747  if (IsExpired (id) == false)
748  {
749  id.PeekEventImpl ()->Cancel ();
750  }
751 }
752 
753 bool
755 {
756  if (ev.GetUid () == 2)
757  {
758  if (ev.PeekEventImpl () == 0 ||
759  ev.PeekEventImpl ()->IsCancelled ())
760  {
761  return true;
762  }
763  // destroy events.
764  for (DestroyEvents::const_iterator i = m_destroyEvents.begin ();
765  i != m_destroyEvents.end (); i++)
766  {
767  if (*i == ev)
768  {
769  return false;
770  }
771  }
772  return true;
773  }
774 
775  //
776  // If the time of the event is less than the current timestamp of the
777  // simulator, the simulator has gone past the invocation time of the
778  // event, so the statement ev.GetTs () < m_currentTs does mean that
779  // the event has been fired even in realtime mode.
780  //
781  // The same is true for the next line involving the m_currentUid.
782  //
783  if (ev.PeekEventImpl () == 0 ||
784  ev.GetTs () < m_currentTs ||
785  (ev.GetTs () == m_currentTs && ev.GetUid () <= m_currentUid) ||
786  ev.PeekEventImpl ()->IsCancelled ())
787  {
788  return true;
789  }
790  else
791  {
792  return false;
793  }
794 }
795 
796 Time
798 {
801  return TimeStep (0x7fffffffffffffffLL);
802 }
803 
804 // System ID for non-distributed simulation is always zero
805 uint32_t
807 {
808  return 0;
809 }
810 
811 uint32_t
813 {
814  return m_currentContext;
815 }
816 
817 void
819 {
820  NS_LOG_FUNCTION (this << mode);
821  m_synchronizationMode = mode;
822 }
823 
826 {
827  NS_LOG_FUNCTION (this);
828  return m_synchronizationMode;
829 }
830 
831 void
833 {
834  NS_LOG_FUNCTION (this << limit);
835  m_hardLimit = limit;
836 }
837 
838 Time
840 {
841  NS_LOG_FUNCTION (this);
842  return m_hardLimit;
843 }
844 
845 } // namespace ns3
void ScheduleRealtimeNowWithContext(uint32_t context, EventImpl *event)
void SetSynchronizationMode(RealtimeSimulatorImpl::SynchronizationMode mode)
keep track of time values and allow control of global simulation resolution
Definition: nstime.h:81
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:59
bool IsPositive(void) const
Definition: nstime.h:244
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
Ptr< const AttributeChecker > MakeEnumChecker(int v1, std::string n1, int v2, std::string n2, int v3, std::string n3, int v4, std::string n4, int v5, std::string n5, int v6, std::string n6, int v7, std::string n7, int v8, std::string n8, int v9, std::string n9, int v10, std::string n10, int v11, std::string n11, int v12, std::string n12, int v13, std::string n13, int v14, std::string n14, int v15, std::string n15, int v16, std::string n16, int v17, std::string n17, int v18, std::string n18, int v19, std::string n19, int v20, std::string n20, int v21, std::string n21, int v22, std::string n22)
Definition: enum.cc:178
virtual EventId ScheduleNow(EventImpl *event)
virtual EventId Schedule(Time const &time, EventImpl *event)
Time TimeStep(uint64_t ts)
Definition: nstime.h:950
void ScheduleRealtimeNow(EventImpl *event)
EventImpl * impl
Definition: scheduler.h:72
NS_OBJECT_ENSURE_REGISTERED(NullMessageSimulatorImpl)
virtual Time GetMaximumSimulationTime(void) const
Time m_hardLimit
The maximum allowable drift from real-time in SYNC_HARD_LIMIT mode.
bool IsCancelled(void)
Definition: event-impl.cc:57
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
Definition: object.cc:336
SynchronizationMode m_synchronizationMode
The policy to use if the simulation cannot keep synchronized to real-time.
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Schedule an event to expire at the relative time "time" is reached.
Definition: simulator.h:824
EventImpl * PeekEventImpl(void) const
Definition: event-id.cc:65
void ScheduleRealtimeWithContext(uint32_t context, Time const &time, EventImpl *event)
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
virtual EventId ScheduleDestroy(EventImpl *event)
virtual void ScheduleWithContext(uint32_t context, Time const &time, EventImpl *event)
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
RealtimeSimulatorImpl::SynchronizationMode GetSynchronizationMode(void) const
Make a best effort to keep synced to real-time.
hold variables of type 'enum'
Definition: enum.h:37
hold objects of type ns3::Time
Definition: nstime.h:961
virtual Time Now(void) const
Return the "current simulation time".
virtual void Run(void)
Run the simulation until one of:
Ptr< Object > Create(void) const
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:109
virtual void Destroy()
This method is typically invoked at the end of a simulation to avoid false-positive reports by a leak...
void Unref(void) const
Decrement the reference count.
virtual void Remove(const EventId &ev)
Remove an event from the event list.
uint32_t GetUid(void) const
Definition: event-id.cc:83
Maintain the event list.
Definition: scheduler.h:57
#define NS_LOG_LOGIC(msg)
Definition: log.h:368
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...
SynchronizationMode
Enumeration of the types of packets supported in the class.
static bool Equals(ThreadId id)
Compares an TharedId with the current ThreadId .
virtual Time GetDelayLeft(const EventId &id) const
virtual uint32_t GetSystemId(void) const
int64_t GetTimeStep(void) const
Definition: nstime.h:356
static Time Now(void)
Return the "current simulation time".
Definition: simulator.cc:180
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition: enum.h:118
virtual bool IsExpired(const EventId &ev) const
This method has O(1) complexity.
#define NS_ASSERT_MSG(condition, message)
Definition: assert.h:86
virtual void SetScheduler(ObjectFactory schedulerFactory)
instantiate subclasses of ns3::Object.
a simulation event
Definition: event-impl.h:39
an identifier for simulation events.
Definition: event-id.h:46
static void Stop(void)
If an event invokes this method, it will be the last event scheduled by the Simulator::run method bef...
Definition: simulator.cc:165
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:452
virtual uint32_t GetContext(void) const
virtual void Stop(void)
If an event invokes this method, it will be the last event scheduled by the Simulator::Run method bef...
NS_LOG_COMPONENT_DEFINE("RealtimeSimulatorImpl")
void ScheduleRealtime(Time const &time, EventImpl *event)
static ThreadId Self(void)
Returns the current thread Id.
virtual bool IsFinished(void) const
If there are no more events lefts to be scheduled, or if simulation time has already reached the "sto...
a unique identifier for an interface.
Definition: type-id.h:49
TypeId SetParent(TypeId tid)
Definition: type-id.cc:611
uint64_t GetTs(void) const
Definition: event-id.cc:71
Doxygen introspection did not find any typical Config paths.