A Discrete-Event Network Simulator
API
default-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) 2005,2006 INRIA
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  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
21 #include "simulator.h"
22 #include "default-simulator-impl.h"
23 
24 #include "scheduler.h"
25 #include "assert.h"
26 #include "log.h"
27 
28 #include <cmath>
29 
30 
37 namespace ns3 {
38 
39 // Note: Logging in this file is largely avoided due to the
40 // number of calls that are made to these functions and the possibility
41 // of causing recursions leading to stack overflow
42 NS_LOG_COMPONENT_DEFINE ("DefaultSimulatorImpl");
43 
44 NS_OBJECT_ENSURE_REGISTERED (DefaultSimulatorImpl);
45 
46 TypeId
48 {
49  static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl")
51  .SetGroupName ("Core")
52  .AddConstructor<DefaultSimulatorImpl> ()
53  ;
54  return tid;
55 }
56 
58 {
59  NS_LOG_FUNCTION (this);
60  m_stop = false;
63  m_currentTs = 0;
66  m_eventCount = 0;
68  m_mainThreadId = std::this_thread::get_id ();
69 }
70 
72 {
73  NS_LOG_FUNCTION (this);
74 }
75 
76 void
78 {
79  NS_LOG_FUNCTION (this);
81 
82  while (!m_events->IsEmpty ())
83  {
84  Scheduler::Event next = m_events->RemoveNext ();
85  next.impl->Unref ();
86  }
87  m_events = 0;
89 }
90 void
92 {
93  NS_LOG_FUNCTION (this);
94  while (!m_destroyEvents.empty ())
95  {
96  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
97  m_destroyEvents.pop_front ();
98  NS_LOG_LOGIC ("handle destroy " << ev);
99  if (!ev->IsCancelled ())
100  {
101  ev->Invoke ();
102  }
103  }
104 }
105 
106 void
108 {
109  NS_LOG_FUNCTION (this << schedulerFactory);
110  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
111 
112  if (m_events != 0)
113  {
114  while (!m_events->IsEmpty ())
115  {
116  Scheduler::Event next = m_events->RemoveNext ();
117  scheduler->Insert (next);
118  }
119  }
120  m_events = scheduler;
121 }
122 
123 // System ID for non-distributed simulation is always zero
124 uint32_t
126 {
127  return 0;
128 }
129 
130 void
132 {
133  Scheduler::Event next = m_events->RemoveNext ();
134 
135  PreEventHook (EventId (next.impl, next.key.m_ts,
136  next.key.m_context, next.key.m_uid));
137 
138  NS_ASSERT (next.key.m_ts >= m_currentTs);
140  m_eventCount++;
141 
142  NS_LOG_LOGIC ("handle " << next.key.m_ts);
143  m_currentTs = next.key.m_ts;
145  m_currentUid = next.key.m_uid;
146  next.impl->Invoke ();
147  next.impl->Unref ();
148 
150 }
151 
152 bool
154 {
155  return m_events->IsEmpty () || m_stop;
156 }
157 
158 void
160 {
162  {
163  return;
164  }
165 
166  // swap queues
167  EventsWithContext eventsWithContext;
168  {
169  std::unique_lock lock {m_eventsWithContextMutex};
170  m_eventsWithContext.swap (eventsWithContext);
172  }
173  while (!eventsWithContext.empty ())
174  {
175  EventWithContext event = eventsWithContext.front ();
176  eventsWithContext.pop_front ();
177  Scheduler::Event ev;
178  ev.impl = event.event;
179  ev.key.m_ts = m_currentTs + event.timestamp;
180  ev.key.m_context = event.context;
181  ev.key.m_uid = m_uid;
182  m_uid++;
184  m_events->Insert (ev);
185  }
186 }
187 
188 void
190 {
191  NS_LOG_FUNCTION (this);
192  // Set the current threadId as the main threadId
193  m_mainThreadId = std::this_thread::get_id ();
195  m_stop = false;
196 
197  while (!m_events->IsEmpty () && !m_stop)
198  {
199  ProcessOneEvent ();
200  }
201 
202  // If the simulator stopped naturally by lack of events, make a
203  // consistency test to check that we didn't lose any events along the way.
204  NS_ASSERT (!m_events->IsEmpty () || m_unscheduledEvents == 0);
205 }
206 
207 void
209 {
210  NS_LOG_FUNCTION (this);
211  m_stop = true;
212 }
213 
214 void
216 {
217  NS_LOG_FUNCTION (this << delay.GetTimeStep ());
219 }
220 
221 //
222 // Schedule an event for a _relative_ time in the future.
223 //
224 EventId
226 {
227  NS_LOG_FUNCTION (this << delay.GetTimeStep () << event);
228  NS_ASSERT_MSG (m_mainThreadId == std::this_thread::get_id (),
229  "Simulator::Schedule Thread-unsafe invocation!");
230 
231  NS_ASSERT_MSG (delay.IsPositive (), "DefaultSimulatorImpl::Schedule(): Negative delay");
232  Time tAbsolute = delay + TimeStep (m_currentTs);
233 
234  Scheduler::Event ev;
235  ev.impl = event;
236  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
237  ev.key.m_context = GetContext ();
238  ev.key.m_uid = m_uid;
239  m_uid++;
241  m_events->Insert (ev);
242  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
243 }
244 
245 void
246 DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *event)
247 {
248  NS_LOG_FUNCTION (this << context << delay.GetTimeStep () << event);
249 
250  if (m_mainThreadId == std::this_thread::get_id ())
251  {
252  Time tAbsolute = delay + TimeStep (m_currentTs);
253  Scheduler::Event ev;
254  ev.impl = event;
255  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
256  ev.key.m_context = context;
257  ev.key.m_uid = m_uid;
258  m_uid++;
260  m_events->Insert (ev);
261  }
262  else
263  {
264  EventWithContext ev;
265  ev.context = context;
266  // Current time added in ProcessEventsWithContext()
267  ev.timestamp = delay.GetTimeStep ();
268  ev.event = event;
269  {
270  std::unique_lock lock {m_eventsWithContextMutex};
271  m_eventsWithContext.push_back (ev);
272  m_eventsWithContextEmpty = false;
273  }
274  }
275 }
276 
277 EventId
279 {
280  NS_ASSERT_MSG (m_mainThreadId == std::this_thread::get_id (),
281  "Simulator::ScheduleNow Thread-unsafe invocation!");
282 
283  return Schedule (Time (0), event);
284 }
285 
286 EventId
288 {
289  NS_ASSERT_MSG (m_mainThreadId == std::this_thread::get_id (),
290  "Simulator::ScheduleDestroy Thread-unsafe invocation!");
291 
292  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
293  m_destroyEvents.push_back (id);
294  m_uid++;
295  return id;
296 }
297 
298 Time
300 {
301  // Do not add function logging here, to avoid stack overflow
302  return TimeStep (m_currentTs);
303 }
304 
305 Time
307 {
308  if (IsExpired (id))
309  {
310  return TimeStep (0);
311  }
312  else
313  {
314  return TimeStep (id.GetTs () - m_currentTs);
315  }
316 }
317 
318 void
320 {
321  if (id.GetUid () == EventId::UID::DESTROY)
322  {
323  // destroy events.
324  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
325  {
326  if (*i == id)
327  {
328  m_destroyEvents.erase (i);
329  break;
330  }
331  }
332  return;
333  }
334  if (IsExpired (id))
335  {
336  return;
337  }
338  Scheduler::Event event;
339  event.impl = id.PeekEventImpl ();
340  event.key.m_ts = id.GetTs ();
341  event.key.m_context = id.GetContext ();
342  event.key.m_uid = id.GetUid ();
343  m_events->Remove (event);
344  event.impl->Cancel ();
345  // whenever we remove an event from the event list, we have to unref it.
346  event.impl->Unref ();
347 
349 }
350 
351 void
353 {
354  if (!IsExpired (id))
355  {
356  id.PeekEventImpl ()->Cancel ();
357  }
358 }
359 
360 bool
362 {
363  if (id.GetUid () == EventId::UID::DESTROY)
364  {
365  if (id.PeekEventImpl () == 0
366  || id.PeekEventImpl ()->IsCancelled ())
367  {
368  return true;
369  }
370  // destroy events.
371  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
372  {
373  if (*i == id)
374  {
375  return false;
376  }
377  }
378  return true;
379  }
380  if (id.PeekEventImpl () == 0
381  || id.GetTs () < m_currentTs
382  || (id.GetTs () == m_currentTs && id.GetUid () <= m_currentUid)
383  || id.PeekEventImpl ()->IsCancelled ())
384  {
385  return true;
386  }
387  else
388  {
389  return false;
390  }
391 }
392 
393 Time
395 {
396  return TimeStep (0x7fffffffffffffffLL);
397 }
398 
399 uint32_t
401 {
402  return m_currentContext;
403 }
404 
405 uint64_t
407 {
408  return m_eventCount;
409 }
410 
411 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
The default single process simulator implementation.
bool m_stop
Flag calling for the end of the simulation.
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...
bool m_eventsWithContextEmpty
Flag true if all events with context have been moved to the primary event queue.
void ProcessEventsWithContext(void)
Move events from a different context into the main event queue.
uint32_t m_currentContext
Execution context of the current event.
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
virtual void Remove(const EventId &id)
Remove an event from the event list.
virtual EventId ScheduleNow(EventImpl *event)
Schedule an event to run at the current virtual time.
virtual bool IsExpired(const EventId &id) const
Check if an event has already run or been cancelled.
DestroyEvents m_destroyEvents
The container of events to run at Destroy.
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...
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
virtual uint32_t GetContext(void) const
Get the current simulation context.
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
Ptr< Scheduler > m_events
The event priority queue.
std::list< struct EventWithContext > EventsWithContext
Container type for the events from a different context.
void ProcessOneEvent(void)
Process the next event.
virtual void Run(void)
Run the simulation.
virtual uint64_t GetEventCount(void) const
Get the number of events executed.
uint64_t m_currentTs
Timestamp of the current event.
virtual void ScheduleWithContext(uint32_t context, const Time &delay, EventImpl *event)
Schedule a future event execution (in a different context).
virtual void SetScheduler(ObjectFactory schedulerFactory)
Set the Scheduler to be used to manage the event list.
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
uint64_t m_eventCount
The event count.
int m_unscheduledEvents
Number of events that have been inserted but not yet scheduled, not counting the Destroy events; this...
virtual void Destroy()
Execute the events scheduled with ScheduleDestroy().
std::mutex m_eventsWithContextMutex
Mutex to control access to the list of events with context.
static TypeId GetTypeId(void)
Register this type.
virtual EventId Schedule(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
virtual Time Now(void) const
Return the current simulation virtual time.
uint32_t m_uid
Next event unique id.
uint32_t m_currentUid
Unique id of the current event.
virtual bool IsFinished(void) const
Check if the simulation should finish.
virtual void DoDispose(void)
Destructor implementation.
std::thread::id m_mainThreadId
Main execution thread.
EventsWithContext m_eventsWithContext
The container of events from a different context.
An identifier for simulation events.
Definition: event-id.h:54
A simulation event.
Definition: event-impl.h:45
void Invoke(void)
Called by the simulation engine to notify the event that it is time to execute.
Definition: event-impl.cc:46
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
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
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: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
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::DefaultSimulatorImpl declaration.
@ INVALID
INVALID.
Definition: aodv-rtable.h:51
@ VALID
VALID.
Definition: aodv-rtable.h:50
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
#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
#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
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations.
ns3::Simulator declaration.
Wrap an event with its execution context.
EventImpl * event
The event implementation.
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