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 
45 namespace 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
50 NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorImpl");
51 
52 NS_OBJECT_ENSURE_REGISTERED (RealtimeSimulatorImpl);
53 
54 TypeId
56 {
57  static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
59  .AddConstructor<RealtimeSimulatorImpl> ()
60  .AddAttribute ("SynchronizationMode",
61  "What to do if the simulation cannot keep up with real time.",
64  MakeEnumChecker (SYNC_BEST_EFFORT, "BestEffort",
65  SYNC_HARD_LIMIT, "HardLimit"))
66  .AddAttribute ("HardLimit",
67  "Maximum acceptable real-time jitter (used in conjunction with SynchronizationMode=HardLimit)",
68  TimeValue (Seconds (0.1)),
70  MakeTimeChecker ())
71  ;
72  return tid;
73 }
74 
75 
77 {
78  NS_LOG_FUNCTION (this);
79 
80  m_stop = false;
81  m_running = false;
82  // uids are allocated from 4.
83  // uid 0 is "invalid" events
84  // uid 1 is "now" events
85  // uid 2 is "destroy" events
86  m_uid = 4;
87  // before ::Run is entered, the m_currentUid will be zero
88  m_currentUid = 0;
89  m_currentTs = 0;
90  m_currentContext = 0xffffffff;
92 
94 
95  // Be very careful not to do anything that would cause a change or assignment
96  // of the underlying reference counts of m_synchronizer or you will be sorry.
97  m_synchronizer = CreateObject<WallClockSynchronizer> ();
98 }
99 
101 {
102  NS_LOG_FUNCTION (this);
103 }
104 
105 void
107 {
108  NS_LOG_FUNCTION (this);
109  while (!m_events->IsEmpty ())
110  {
111  Scheduler::Event next = m_events->RemoveNext ();
112  next.impl->Unref ();
113  }
114  m_events = 0;
115  m_synchronizer = 0;
117 }
118 
119 void
121 {
122  NS_LOG_FUNCTION (this);
123 
124  //
125  // This function is only called with the private version "disconnected" from
126  // the main simulator functions. We rely on the user not calling
127  // Simulator::Destroy while there is a chance that a worker thread could be
128  // accessing the current instance of the private object. In practice this
129  // means shutting down the workers and doing a Join() before calling the
130  // Simulator::Destroy().
131  //
132  while (m_destroyEvents.empty () == false)
133  {
134  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
135  m_destroyEvents.pop_front ();
136  NS_LOG_LOGIC ("handle destroy " << ev);
137  if (ev->IsCancelled () == false)
138  {
139  ev->Invoke ();
140  }
141  }
142 }
143 
144 void
146 {
147  NS_LOG_FUNCTION (this << schedulerFactory);
148 
149  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
150 
151  {
153 
154  if (m_events != 0)
155  {
156  while (m_events->IsEmpty () == false)
157  {
158  Scheduler::Event next = m_events->RemoveNext ();
159  scheduler->Insert (next);
160  }
161  }
162  m_events = scheduler;
163  }
164 }
165 
166 void
168 {
169  //
170  // The idea here is to wait until the next event comes due. In the case of
171  // a realtime simulation, we want real time to be consumed between events.
172  // It is the realtime synchronizer that causes real time to be consumed by
173  // doing some kind of a wait.
174  //
175  // We need to be able to have external events (such as a packet reception event)
176  // cause us to re-evaluate our state. The way this works is that the synchronizer
177  // gets interrupted and returns. So, there is a possibility that things may change
178  // out from under us dynamically. In this case, we need to re-evaluate how long to
179  // wait in a for-loop until we have waited sucessfully (until a timeout) for the
180  // event at the head of the event list.
181  //
182  // m_synchronizer->Synchronize will return true if the wait was completed without
183  // interruption, otherwise it will return false indicating that something has changed
184  // out from under us. If we sit in the for-loop trying to synchronize until
185  // Synchronize() returns true, we will have successfully synchronized the execution
186  // time of the next event with the wall clock time of the synchronizer.
187  //
188 
189  for (;;)
190  {
191  uint64_t tsDelay = 0;
192  uint64_t tsNext = 0;
193 
194  //
195  // It is important to understand that m_currentTs is interpreted only as the
196  // timestamp of the last event we executed. Current time can a bit of a
197  // slippery concept in realtime mode. What we have here is a discrete event
198  // simulator, so the last event is, by defintion, executed entirely at a single
199  // discrete time. This is the definition of m_currentTs. It really has
200  // nothing to do with the current real time, except that we are trying to arrange
201  // that at the instant of the beginning of event execution, the current real time
202  // and m_currentTs coincide.
203  //
204  // We use tsNow as the indication of the current real time.
205  //
206  uint64_t tsNow;
207 
208  {
210  //
211  // Since we are in realtime mode, the time to delay has got to be the
212  // difference between the current realtime and the timestamp of the next
213  // event. Since m_currentTs is actually the timestamp of the last event we
214  // executed, it's not particularly meaningful for us here since real time has
215  // certainly elapsed since it was last updated.
216  //
217  // It is possible that the current realtime has drifted past the next event
218  // time so we need to be careful about that and not delay in that case.
219  //
220  NS_ASSERT_MSG (m_synchronizer->Realtime (),
221  "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()");
222 
223  //
224  // tsNow is set to the normalized current real time. When the simulation was
225  // started, the current real time was effectively set to zero; so tsNow is
226  // the current "real" simulation time.
227  //
228  // tsNext is the simulation time of the next event we want to execute.
229  //
230  tsNow = m_synchronizer->GetCurrentRealtime ();
231  tsNext = NextTs ();
232 
233  //
234  // tsDelay is therefore the real time we need to delay in order to bring the
235  // real time in sync with the simulation time. If we wait for this amount of
236  // real time, we will accomplish moving the simulation time at the same rate
237  // as the real time. This is typically called "pacing" the simulation time.
238  //
239  // We do have to be careful if we are falling behind. If so, tsDelay must be
240  // zero. If we're late, don't dawdle.
241  //
242  if (tsNext <= tsNow)
243  {
244  tsDelay = 0;
245  }
246  else
247  {
248  tsDelay = tsNext - tsNow;
249  }
250 
251  //
252  // We've figured out how long we need to delay in order to pace the
253  // simulation time with the real time. We're going to sleep, but need
254  // to work with the synchronizer to make sure we're awakened if something
255  // external happens (like a packet is received). This next line resets
256  // the synchronizer so that any future event will cause it to interrupt.
257  //
258  m_synchronizer->SetCondition (false);
259  }
260 
261  //
262  // We have a time to delay. This time may actually not be valid anymore
263  // since we released the critical section immediately above, and a real-time
264  // ScheduleReal or ScheduleRealNow may have snuck in, well, between the
265  // closing brace above and this comment so to speak. If this is the case,
266  // that schedule operation will have done a synchronizer Signal() that
267  // will set the condition variable to true and cause the Synchronize call
268  // below to return immediately.
269  //
270  // It's easiest to understand if you just consider a short tsDelay that only
271  // requires a SpinWait down in the synchronizer. What will happen is that
272  // whan Synchronize calls SpinWait, SpinWait will look directly at its
273  // condition variable. Note that we set this condition variable to false
274  // inside the critical section above.
275  //
276  // SpinWait will go into a forever loop until either the time has expired or
277  // until the condition variable becomes true. A true condition indicates that
278  // the wait should stop. The condition is set to true by one of the Schedule
279  // methods of the simulator; so if we are in a wait down in Synchronize, and
280  // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and
281  // Synchronize will return false. This means we have not actually synchronized
282  // to the event expiration time. If no real-time schedule operation is done
283  // while down in Synchronize, the wait will time out and Synchronize will return
284  // true. This indicates that we have synchronized to the event time.
285  //
286  // So we need to stay in this for loop, looking for the next event timestamp and
287  // attempting to sleep until its due. If we've slept until the timestamp is due,
288  // Synchronize returns true and we break out of the sync loop. If an external
289  // event happens that requires a re-schedule, Synchronize returns false and
290  // we re-evaluate our timing by continuing in the loop.
291  //
292  // It is expected that tsDelay become shorter as external events interrupt our
293  // waits.
294  //
295  if (m_synchronizer->Synchronize (tsNow, tsDelay))
296  {
297  NS_LOG_LOGIC ("Interrupted ...");
298  break;
299  }
300 
301  //
302  // If we get to this point, we have been interrupted during a wait by a real-time
303  // schedule operation. This means all bets are off regarding tsDelay and we need
304  // to re-evaluate what it is we want to do. We'll loop back around in the
305  // for-loop and start again from scratch.
306  //
307  }
308 
309  //
310  // If we break out of the for-loop above, we have waited until the time specified
311  // by the event that was at the head of the event list when we started the process.
312  // Since there is a bunch of code that was executed outside a critical section (the
313  // Synchronize call) we cannot be sure that the event at the head of the event list
314  // is the one we think it is. What we can be sure of is that it is time to execute
315  // whatever event is at the head of this list if the list is in time order.
316  //
317  Scheduler::Event next;
318 
319  {
321 
322  //
323  // We do know we're waiting for an event, so there had better be an event on the
324  // event queue. Let's pull it off. When we release the critical section, the
325  // event we're working on won't be on the list and so subsequent operations won't
326  // mess with us.
327  //
328  NS_ASSERT_MSG (m_events->IsEmpty () == false,
329  "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty");
330  next = m_events->RemoveNext ();
332 
333  //
334  // We cannot make any assumption that "next" is the same event we originally waited
335  // for. We can only assume that only that it must be due and cannot cause time
336  // to move backward.
337  //
338  NS_ASSERT_MSG (next.key.m_ts >= m_currentTs,
339  "RealtimeSimulatorImpl::ProcessOneEvent(): "
340  "next.GetTs() earlier than m_currentTs (list order error)");
341  NS_LOG_LOGIC ("handle " << next.key.m_ts);
342 
343  //
344  // Update the current simulation time to be the timestamp of the event we're
345  // executing. From the rest of the simulation's point of view, simulation time
346  // is frozen until the next event is executed.
347  //
348  m_currentTs = next.key.m_ts;
349  m_currentContext = next.key.m_context;
350  m_currentUid = next.key.m_uid;
351 
352  //
353  // We're about to run the event and we've done our best to synchronize this
354  // event execution time to real time. Now, if we're in SYNC_HARD_LIMIT mode
355  // we have to decide if we've done a good enough job and if we haven't, we've
356  // been asked to commit ritual suicide.
357  //
358  // We check the simulation time against the current real time to make this
359  // judgement.
360  //
362  {
363  uint64_t tsFinal = m_synchronizer->GetCurrentRealtime ();
364  uint64_t tsJitter;
365 
366  if (tsFinal >= m_currentTs)
367  {
368  tsJitter = tsFinal - m_currentTs;
369  }
370  else
371  {
372  tsJitter = m_currentTs - tsFinal;
373  }
374 
375  if (tsJitter > static_cast<uint64_t>(m_hardLimit.GetTimeStep ()))
376  {
377  NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): "
378  "Hard real-time limit exceeded (jitter = " << tsJitter << ")");
379  }
380  }
381  }
382 
383  //
384  // We have got the event we're about to execute completely disentangled from the
385  // event list so we can execute it outside a critical section without fear of someone
386  // changing things out from under us.
387 
388  EventImpl *event = next.impl;
389  m_synchronizer->EventStart ();
390  event->Invoke ();
391  m_synchronizer->EventEnd ();
392  event->Unref ();
393 }
394 
395 bool
397 {
398  bool rc;
399  {
401  rc = m_events->IsEmpty () || m_stop;
402  }
403 
404  return rc;
405 }
406 
407 //
408 // Peeks into event list. Should be called with critical section locked.
409 //
410 uint64_t
412 {
413  NS_ASSERT_MSG (m_events->IsEmpty () == false,
414  "RealtimeSimulatorImpl::NextTs(): event queue is empty");
415  Scheduler::Event ev = m_events->PeekNext ();
416  return ev.key.m_ts;
417 }
418 
419 void
421 {
422  NS_LOG_FUNCTION (this);
423 
424  NS_ASSERT_MSG (m_running == false,
425  "RealtimeSimulatorImpl::Run(): Simulator already running");
426 
427  // Set the current threadId as the main threadId
429 
430  m_stop = false;
431  m_running = true;
432  m_synchronizer->SetOrigin (m_currentTs);
433 
434  // Sleep until signalled
435  uint64_t tsNow;
436  uint64_t tsDelay = 1000000000; // wait time of 1 second (in nanoseconds)
437 
438  while (!m_stop)
439  {
440  bool process = false;
441  {
443 
444  if (!m_events->IsEmpty ())
445  {
446  process = true;
447  }
448  else
449  {
450  // Get current timestamp while holding the critical section
451  tsNow = m_synchronizer->GetCurrentRealtime ();
452  }
453  }
454 
455  if (!process)
456  {
457  // Sleep until signalled
458  tsNow = m_synchronizer->Synchronize (tsNow, tsDelay);
459 
460  // Re-check event queue
461  continue;
462  }
463 
464  ProcessOneEvent ();
465  }
466 
467  //
468  // If the simulator stopped naturally by lack of events, make a
469  // consistency test to check that we didn't lose any events along the way.
470  //
471  {
473 
474  NS_ASSERT_MSG (m_events->IsEmpty () == false || m_unscheduledEvents == 0,
475  "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events");
476  }
477 
478  m_running = false;
479 }
480 
481 bool
483 {
484  return m_running;
485 }
486 
487 bool
489 {
490  return m_synchronizer->Realtime ();
491 }
492 
493 void
495 {
496  NS_LOG_FUNCTION (this);
497  m_stop = true;
498 }
499 
500 void
502 {
503  NS_LOG_FUNCTION (this << time);
505 }
506 
507 //
508 // Schedule an event for a _relative_ time in the future.
509 //
510 EventId
512 {
513  NS_LOG_FUNCTION (this << time << impl);
514 
515  Scheduler::Event ev;
516  {
518  //
519  // This is the reason we had to bring the absolute time calcualtion in from the
520  // simulator.h into the implementation. Since the implementations may be
521  // multi-threaded, we need this calculation to be atomic. You can see it is
522  // here since we are running in a CriticalSection.
523  //
524  Time tAbsolute = Simulator::Now () + time;
525  NS_ASSERT_MSG (tAbsolute.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative time");
526  NS_ASSERT_MSG (tAbsolute >= TimeStep (m_currentTs), "RealtimeSimulatorImpl::Schedule(): time < m_currentTs");
527  ev.impl = impl;
528  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
529  ev.key.m_context = GetContext ();
530  ev.key.m_uid = m_uid;
531  m_uid++;
533  m_events->Insert (ev);
534  m_synchronizer->Signal ();
535  }
536 
537  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
538 }
539 
540 void
541 RealtimeSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *impl)
542 {
543  NS_LOG_FUNCTION (this << context << time << impl);
544 
545  {
547  uint64_t ts;
548 
550  {
551  ts = m_currentTs + time.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 += time.GetTimeStep ();
561  }
562 
563  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
564  Scheduler::Event ev;
565  ev.impl = impl;
566  ev.key.m_ts = ts;
567  ev.key.m_context = context;
568  ev.key.m_uid = m_uid;
569  m_uid++;
571  m_events->Insert (ev);
572  m_synchronizer->Signal ();
573  }
574 }
575 
576 EventId
578 {
579  NS_LOG_FUNCTION (this << impl);
580  Scheduler::Event ev;
581  {
583 
584  ev.impl = impl;
585  ev.key.m_ts = m_currentTs;
586  ev.key.m_context = GetContext ();
587  ev.key.m_uid = m_uid;
588  m_uid++;
590  m_events->Insert (ev);
591  m_synchronizer->Signal ();
592  }
593 
594  return EventId (impl, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
595 }
596 
597 Time
599 {
600  return TimeStep (m_currentTs);
601 }
602 
603 //
604 // Schedule an event for a _relative_ time in the future.
605 //
606 void
608 {
609  NS_LOG_FUNCTION (this << context << time << impl);
610 
611  {
613 
614  uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
615  NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
616  Scheduler::Event ev;
617  ev.impl = impl;
618  ev.key.m_ts = ts;
619  ev.key.m_uid = m_uid;
620  m_uid++;
622  m_events->Insert (ev);
623  m_synchronizer->Signal ();
624  }
625 }
626 
627 void
629 {
630  NS_LOG_FUNCTION (this << time << impl);
631  ScheduleRealtimeWithContext (GetContext (), time, impl);
632 }
633 
634 void
636 {
637  NS_LOG_FUNCTION (this << context << impl);
638  {
640 
641  //
642  // If the simulator is running, we're pacing and have a meaningful
643  // realtime clock. If we're not, then m_currentTs is were we stopped.
644  //
645  uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
646  NS_ASSERT_MSG (ts >= m_currentTs,
647  "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
648  Scheduler::Event ev;
649  ev.impl = impl;
650  ev.key.m_ts = ts;
651  ev.key.m_uid = m_uid;
652  ev.key.m_context = context;
653  m_uid++;
655  m_events->Insert (ev);
656  m_synchronizer->Signal ();
657  }
658 }
659 
660 void
662 {
663  NS_LOG_FUNCTION (this << impl);
665 }
666 
667 Time
669 {
670  return TimeStep (m_synchronizer->GetCurrentRealtime ());
671 }
672 
673 EventId
675 {
676  NS_LOG_FUNCTION (this << impl);
677 
678  EventId id;
679  {
681 
682  //
683  // Time doesn't really matter here (especially in realtime mode). It is
684  // overridden by the uid of 2 which identifies this as an event to be
685  // executed at Simulator::Destroy time.
686  //
687  id = EventId (Ptr<EventImpl> (impl, false), m_currentTs, 0xffffffff, 2);
688  m_destroyEvents.push_back (id);
689  m_uid++;
690  }
691 
692  return id;
693 }
694 
695 Time
697 {
698  //
699  // If the event has expired, there is no delay until it runs. It is not the
700  // case that there is a negative time until it runs.
701  //
702  if (IsExpired (id))
703  {
704  return TimeStep (0);
705  }
706 
707  return TimeStep (id.GetTs () - m_currentTs);
708 }
709 
710 void
712 {
713  if (id.GetUid () == 2)
714  {
715  // destroy events.
716  for (DestroyEvents::iterator i = m_destroyEvents.begin ();
717  i != m_destroyEvents.end ();
718  i++)
719  {
720  if (*i == id)
721  {
722  m_destroyEvents.erase (i);
723  break;
724  }
725  }
726  return;
727  }
728  if (IsExpired (id))
729  {
730  return;
731  }
732 
733  {
735 
736  Scheduler::Event event;
737  event.impl = id.PeekEventImpl ();
738  event.key.m_ts = id.GetTs ();
739  event.key.m_context = id.GetContext ();
740  event.key.m_uid = id.GetUid ();
741 
742  m_events->Remove (event);
744  event.impl->Cancel ();
745  event.impl->Unref ();
746  }
747 }
748 
749 void
751 {
752  if (IsExpired (id) == false)
753  {
754  id.PeekEventImpl ()->Cancel ();
755  }
756 }
757 
758 bool
760 {
761  if (id.GetUid () == 2)
762  {
763  if (id.PeekEventImpl () == 0 ||
764  id.PeekEventImpl ()->IsCancelled ())
765  {
766  return true;
767  }
768  // destroy events.
769  for (DestroyEvents::const_iterator i = m_destroyEvents.begin ();
770  i != m_destroyEvents.end (); i++)
771  {
772  if (*i == id)
773  {
774  return false;
775  }
776  }
777  return true;
778  }
779 
780  //
781  // If the time of the event is less than the current timestamp of the
782  // simulator, the simulator has gone past the invocation time of the
783  // event, so the statement ev.GetTs () < m_currentTs does mean that
784  // the event has been fired even in realtime mode.
785  //
786  // The same is true for the next line involving the m_currentUid.
787  //
788  if (id.PeekEventImpl () == 0 ||
789  id.GetTs () < m_currentTs ||
790  (id.GetTs () == m_currentTs && id.GetUid () <= m_currentUid) ||
791  id.PeekEventImpl ()->IsCancelled ())
792  {
793  return true;
794  }
795  else
796  {
797  return false;
798  }
799 }
800 
801 Time
803 {
806  return TimeStep (0x7fffffffffffffffLL);
807 }
808 
809 // System ID for non-distributed simulation is always zero
810 uint32_t
812 {
813  return 0;
814 }
815 
816 uint32_t
818 {
819  return m_currentContext;
820 }
821 
822 void
824 {
825  NS_LOG_FUNCTION (this << mode);
826  m_synchronizationMode = mode;
827 }
828 
831 {
832  NS_LOG_FUNCTION (this);
833  return m_synchronizationMode;
834 }
835 
836 void
838 {
839  NS_LOG_FUNCTION (this << limit);
840  m_hardLimit = limit;
841 }
842 
843 Time
845 {
846  NS_LOG_FUNCTION (this);
847  return m_hardLimit;
848 }
849 
850 } // namespace ns3
NS_FATAL_x macro definitions.
Boolean attribute value declarations.
void ScheduleRealtimeNowWithContext(uint32_t context, EventImpl *event)
void SetSynchronizationMode(RealtimeSimulatorImpl::SynchronizationMode mode)
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:95
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
bool IsPositive(void) const
Definition: nstime.h:279
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
ns3::EventImpl declarations.
virtual EventId ScheduleNow(EventImpl *event)
Schedule an event to run at the current virtual time.
Make a best effort to keep synced to real-time.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
virtual EventId Schedule(Time const &time, EventImpl *event)
Schedule a future event execution (in the same context).
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:77
Smart pointer implementation.
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:209
SynchronizationMode
Enumeration of the types of packets supported in the class.
void ScheduleRealtimeNow(EventImpl *event)
static ThreadId Self(void)
Returns the current thread Id.
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:90
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
Time m_hardLimit
The maximum allowable drift from real-time in SYNC_HARD_LIMIT mode.
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:338
#define NS_FATAL_ERROR(msg)
Fatal error handling.
Definition: fatal-error.h:100
ns3::Simulator declaration.
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:819
void ScheduleRealtimeWithContext(uint32_t context, Time const &time, EventImpl *event)
virtual void DoDispose(void)
Destructor implementation.
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 ScheduleWithContext(uint32_t context, Time const &time, EventImpl *event)
Schedule a future event execution (in a different context).
RealtimeSimulatorImpl::SynchronizationMode GetSynchronizationMode(void) const
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:439
System-independent mutex primitive, ns3::SystemMutex, and ns3::CriticalSection.
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations...
Hold variables of type enum.
Definition: enum.h:54
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:91
AttributeValue implementation for Time.
Definition: nstime.h:921
virtual Time Now(void) const
Return the current simulation virtual time.
virtual void Run(void)
Run the simulation.
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:118
uint32_t m_uid
Event unique id.
Definition: scheduler.h:78
virtual void Destroy()
Execute the events scheduled with ScheduleDestroy().
void Unref(void) const
Decrement the reference count.
Enum attribute value declarations.
ns3::WallClockSynchronizer declaration.
virtual void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
Maintain the event list.
Definition: scheduler.h:66
virtual bool IsExpired(const EventId &id) const
Check if an event has already run or been cancelled.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
Scheduler event.
Definition: scheduler.h:88
Every class exported by the ns3 library is enclosed in the ns3 namespace.
virtual void Remove(const EventId &id)
Remove an event from the event list.
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
int64_t GetTimeStep(void) const
Definition: nstime.h:357
Time TimeStep(uint64_t ts)
Definition: nstime.h:916
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:922
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:223
ns3::Synchronizer declaration.
static bool Equals(ThreadId id)
Compares an ThreadId with the current ThreadId .
#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:84
virtual void SetScheduler(ObjectFactory schedulerFactory)
Set the Scheduler to be used to manage the event list.
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)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.cc:184
Instantiate subclasses of ns3::Object.
A simulation event.
Definition: event-impl.h:44
An identifier for simulation events.
Definition: event-id.h:53
static void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:208
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:859
virtual uint32_t GetContext(void) const
Get the current simulation context.
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
void ScheduleRealtime(Time const &time, EventImpl *event)
Debug message logging.
virtual bool IsFinished(void) const
Check if the simulation should finish.
Pointer attribute value declarations and template implementations.
a unique identifier for an interface.
Definition: type-id.h:51
TypeId SetParent(TypeId tid)
Definition: type-id.cc:631
uint32_t m_context
Event context.
Definition: scheduler.h:79
The SimulatorImpl base class.