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 #include "scheduler.h"
24 #include "event-impl.h"
25 
26 #include "ptr.h"
27 #include "pointer.h"
28 #include "assert.h"
29 #include "log.h"
30 
31 #include <cmath>
32 
33 
40 namespace ns3 {
41 
42 // Note: Logging in this file is largely avoided due to the
43 // number of calls that are made to these functions and the possibility
44 // of causing recursions leading to stack overflow
45 NS_LOG_COMPONENT_DEFINE ("DefaultSimulatorImpl");
46 
47 NS_OBJECT_ENSURE_REGISTERED (DefaultSimulatorImpl);
48 
49 TypeId
51 {
52  static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl")
54  .SetGroupName ("Core")
55  .AddConstructor<DefaultSimulatorImpl> ()
56  ;
57  return tid;
58 }
59 
61 {
62  NS_LOG_FUNCTION (this);
63  m_stop = false;
64  // uids are allocated from 4.
65  // uid 0 is "invalid" events
66  // uid 1 is "now" events
67  // uid 2 is "destroy" events
68  m_uid = 4;
69  // before ::Run is entered, the m_currentUid will be zero
70  m_currentUid = 0;
71  m_currentTs = 0;
72  m_currentContext = 0xffffffff;
76 }
77 
79 {
80  NS_LOG_FUNCTION (this);
81 }
82 
83 void
85 {
86  NS_LOG_FUNCTION (this);
87  while (!m_events->IsEmpty ())
88  {
89  Scheduler::Event next = m_events->RemoveNext ();
90  next.impl->Unref ();
91  }
92  m_events = 0;
94 }
95 void
97 {
98  NS_LOG_FUNCTION (this);
99  while (!m_destroyEvents.empty ())
100  {
101  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
102  m_destroyEvents.pop_front ();
103  NS_LOG_LOGIC ("handle destroy " << ev);
104  if (!ev->IsCancelled ())
105  {
106  ev->Invoke ();
107  }
108  }
109 }
110 
111 void
113 {
114  NS_LOG_FUNCTION (this << schedulerFactory);
115  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
116 
117  if (m_events != 0)
118  {
119  while (!m_events->IsEmpty ())
120  {
121  Scheduler::Event next = m_events->RemoveNext ();
122  scheduler->Insert (next);
123  }
124  }
125  m_events = scheduler;
126 }
127 
128 // System ID for non-distributed simulation is always zero
129 uint32_t
131 {
132  return 0;
133 }
134 
135 void
137 {
138  Scheduler::Event next = m_events->RemoveNext ();
139 
140  NS_ASSERT (next.key.m_ts >= m_currentTs);
142 
143  NS_LOG_LOGIC ("handle " << next.key.m_ts);
144  m_currentTs = next.key.m_ts;
146  m_currentUid = next.key.m_uid;
147  next.impl->Invoke ();
148  next.impl->Unref ();
149 
151 }
152 
153 bool
155 {
156  return m_events->IsEmpty () || m_stop;
157 }
158 
159 void
161 {
163  {
164  return;
165  }
166 
167  // swap queues
168  EventsWithContext eventsWithContext;
169  {
171  m_eventsWithContext.swap(eventsWithContext);
173  }
174  while (!eventsWithContext.empty ())
175  {
176  EventWithContext event = eventsWithContext.front ();
177  eventsWithContext.pop_front ();
178  Scheduler::Event ev;
179  ev.impl = event.event;
180  ev.key.m_ts = m_currentTs + event.timestamp;
181  ev.key.m_context = event.context;
182  ev.key.m_uid = m_uid;
183  m_uid++;
185  m_events->Insert (ev);
186  }
187 }
188 
189 void
191 {
192  NS_LOG_FUNCTION (this);
193  // Set the current threadId as the main threadId
196  m_stop = false;
197 
198  while (!m_events->IsEmpty () && !m_stop)
199  {
200  ProcessOneEvent ();
201  }
202 
203  // If the simulator stopped naturally by lack of events, make a
204  // consistency test to check that we didn't lose any events along the way.
205  NS_ASSERT (!m_events->IsEmpty () || m_unscheduledEvents == 0);
206 }
207 
208 void
210 {
211  NS_LOG_FUNCTION (this);
212  m_stop = true;
213 }
214 
215 void
217 {
218  NS_LOG_FUNCTION (this << time.GetTimeStep ());
220 }
221 
222 //
223 // Schedule an event for a _relative_ time in the future.
224 //
225 EventId
227 {
228  NS_LOG_FUNCTION (this << time.GetTimeStep () << event);
229  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::Schedule Thread-unsafe invocation!");
230 
231  Time tAbsolute = time + TimeStep (m_currentTs);
232 
233  NS_ASSERT (tAbsolute.IsPositive ());
234  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
235  Scheduler::Event ev;
236  ev.impl = event;
237  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
238  ev.key.m_context = GetContext ();
239  ev.key.m_uid = m_uid;
240  m_uid++;
242  m_events->Insert (ev);
243  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
244 }
245 
246 void
247 DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event)
248 {
249  NS_LOG_FUNCTION (this << context << time.GetTimeStep () << event);
250 
252  {
253  Time tAbsolute = time + TimeStep (m_currentTs);
254  Scheduler::Event ev;
255  ev.impl = event;
256  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
257  ev.key.m_context = context;
258  ev.key.m_uid = m_uid;
259  m_uid++;
261  m_events->Insert (ev);
262  }
263  else
264  {
265  EventWithContext ev;
266  ev.context = context;
267  ev.timestamp = time.GetTimeStep ();
268  ev.event = event;
269  {
271  m_eventsWithContext.push_back(ev);
272  m_eventsWithContextEmpty = false;
273  }
274  }
275 }
276 
277 EventId
279 {
280  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleNow Thread-unsafe invocation!");
281 
282  Scheduler::Event ev;
283  ev.impl = event;
284  ev.key.m_ts = m_currentTs;
285  ev.key.m_context = GetContext ();
286  ev.key.m_uid = m_uid;
287  m_uid++;
289  m_events->Insert (ev);
290  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
291 }
292 
293 EventId
295 {
296  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleDestroy Thread-unsafe invocation!");
297 
298  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
299  m_destroyEvents.push_back (id);
300  m_uid++;
301  return id;
302 }
303 
304 Time
306 {
307  // Do not add function logging here, to avoid stack overflow
308  return TimeStep (m_currentTs);
309 }
310 
311 Time
313 {
314  if (IsExpired (id))
315  {
316  return TimeStep (0);
317  }
318  else
319  {
320  return TimeStep (id.GetTs () - m_currentTs);
321  }
322 }
323 
324 void
326 {
327  if (id.GetUid () == 2)
328  {
329  // destroy events.
330  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
331  {
332  if (*i == id)
333  {
334  m_destroyEvents.erase (i);
335  break;
336  }
337  }
338  return;
339  }
340  if (IsExpired (id))
341  {
342  return;
343  }
344  Scheduler::Event event;
345  event.impl = id.PeekEventImpl ();
346  event.key.m_ts = id.GetTs ();
347  event.key.m_context = id.GetContext ();
348  event.key.m_uid = id.GetUid ();
349  m_events->Remove (event);
350  event.impl->Cancel ();
351  // whenever we remove an event from the event list, we have to unref it.
352  event.impl->Unref ();
353 
355 }
356 
357 void
359 {
360  if (!IsExpired (id))
361  {
362  id.PeekEventImpl ()->Cancel ();
363  }
364 }
365 
366 bool
368 {
369  if (id.GetUid () == 2)
370  {
371  if (id.PeekEventImpl () == 0 ||
372  id.PeekEventImpl ()->IsCancelled ())
373  {
374  return true;
375  }
376  // destroy events.
377  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
378  {
379  if (*i == id)
380  {
381  return false;
382  }
383  }
384  return true;
385  }
386  if (id.PeekEventImpl () == 0 ||
387  id.GetTs () < m_currentTs ||
388  (id.GetTs () == m_currentTs &&
389  id.GetUid () <= m_currentUid) ||
390  id.PeekEventImpl ()->IsCancelled ())
391  {
392  return true;
393  }
394  else
395  {
396  return false;
397  }
398 }
399 
400 Time
402 {
405  return TimeStep (0x7fffffffffffffffLL);
406 }
407 
408 uint32_t
410 {
411  return m_currentContext;
412 }
413 
414 } // namespace ns3
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
EventsWithContext m_eventsWithContext
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
bool IsPositive(void) const
Definition: nstime.h:286
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
ns3::EventImpl declarations.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
virtual void DoDispose(void)
Destructor implementation.
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:77
Smart pointer implementation.
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
virtual void SetScheduler(ObjectFactory schedulerFactory)
Set the Scheduler to be used to manage the event list.
static ThreadId Self(void)
Returns the current thread Id.
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:90
#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_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:339
ns3::Simulator declaration.
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
virtual EventId ScheduleNow(EventImpl *event)
Schedule an event to run at the current virtual time.
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
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...
void Invoke(void)
Called by the simulation engine to notify the event that it is time to execute.
Definition: event-impl.cc:46
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations...
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:91
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
Definition of assertion macros NS_ASSERT() and NS_ASSERT_MSG().
virtual Time Now(void) const
Return the current simulation virtual time.
Declaration of class ns3::DefaultSimulatorImpl.
void Unref(void) const
Decrement the reference count.
Maintain the event list.
Definition: scheduler.h:66
#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.
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...
std::list< struct EventWithContext > EventsWithContext
Scheduler event.
Definition: scheduler.h:88
Every class exported by the ns3 library is enclosed in the ns3 namespace.
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
virtual uint32_t GetContext(void) const
Get the current simulation context.
int64_t GetTimeStep(void) const
Definition: nstime.h:364
Time TimeStep(uint64_t ts)
Definition: nstime.h:923
virtual void Remove(const EventId &id)
Remove an event from the event list.
The default single process simulator implementation.
virtual void ScheduleWithContext(uint32_t context, Time const &time, EventImpl *event)
Schedule a future event execution (in a different context).
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:90
virtual EventId Schedule(Time const &time, EventImpl *event)
Schedule a future event execution (in the same context).
Instantiate subclasses of ns3::Object.
A simulation event.
Definition: event-impl.h:44
virtual bool IsFinished(void) const
Check if the simulation should finish.
virtual void Run(void)
Run the simulation.
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
virtual void Destroy()
Execute the events scheduled with ScheduleDestroy().
virtual bool IsExpired(const EventId &id) const
Check if an event has already run or been cancelled.
SystemThread::ThreadId m_main
Debug message logging.
Pointer attribute value declarations and template implementations.
a unique identifier for an interface.
Definition: type-id.h:57
TypeId SetParent(TypeId tid)
Definition: type-id.cc:638
uint32_t m_context
Event context.
Definition: scheduler.h:79
The SimulatorImpl base class.