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;
76 }
77 
79 {
80  NS_LOG_FUNCTION (this);
81 }
82 
83 void
85 {
86  NS_LOG_FUNCTION (this);
88 
89  while (!m_events->IsEmpty ())
90  {
91  Scheduler::Event next = m_events->RemoveNext ();
92  next.impl->Unref ();
93  }
94  m_events = 0;
96 }
97 void
99 {
100  NS_LOG_FUNCTION (this);
101  while (!m_destroyEvents.empty ())
102  {
103  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
104  m_destroyEvents.pop_front ();
105  NS_LOG_LOGIC ("handle destroy " << ev);
106  if (!ev->IsCancelled ())
107  {
108  ev->Invoke ();
109  }
110  }
111 }
112 
113 void
115 {
116  NS_LOG_FUNCTION (this << schedulerFactory);
117  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
118 
119  if (m_events != 0)
120  {
121  while (!m_events->IsEmpty ())
122  {
123  Scheduler::Event next = m_events->RemoveNext ();
124  scheduler->Insert (next);
125  }
126  }
127  m_events = scheduler;
128 }
129 
130 // System ID for non-distributed simulation is always zero
131 uint32_t
133 {
134  return 0;
135 }
136 
137 void
139 {
140  Scheduler::Event next = m_events->RemoveNext ();
141 
142  NS_ASSERT (next.key.m_ts >= m_currentTs);
144 
145  NS_LOG_LOGIC ("handle " << next.key.m_ts);
146  m_currentTs = next.key.m_ts;
148  m_currentUid = next.key.m_uid;
149  next.impl->Invoke ();
150  next.impl->Unref ();
151 
153 }
154 
155 bool
157 {
158  return m_events->IsEmpty () || m_stop;
159 }
160 
161 void
163 {
165  {
166  return;
167  }
168 
169  // swap queues
170  EventsWithContext eventsWithContext;
171  {
173  m_eventsWithContext.swap(eventsWithContext);
175  }
176  while (!eventsWithContext.empty ())
177  {
178  EventWithContext event = eventsWithContext.front ();
179  eventsWithContext.pop_front ();
180  Scheduler::Event ev;
181  ev.impl = event.event;
182  ev.key.m_ts = m_currentTs + event.timestamp;
183  ev.key.m_context = event.context;
184  ev.key.m_uid = m_uid;
185  m_uid++;
187  m_events->Insert (ev);
188  }
189 }
190 
191 void
193 {
194  NS_LOG_FUNCTION (this);
195  // Set the current threadId as the main threadId
198  m_stop = false;
199 
200  while (!m_events->IsEmpty () && !m_stop)
201  {
202  ProcessOneEvent ();
203  }
204 
205  // If the simulator stopped naturally by lack of events, make a
206  // consistency test to check that we didn't lose any events along the way.
207  NS_ASSERT (!m_events->IsEmpty () || m_unscheduledEvents == 0);
208 }
209 
210 void
212 {
213  NS_LOG_FUNCTION (this);
214  m_stop = true;
215 }
216 
217 void
219 {
220  NS_LOG_FUNCTION (this << delay.GetTimeStep ());
222 }
223 
224 //
225 // Schedule an event for a _relative_ time in the future.
226 //
227 EventId
229 {
230  NS_LOG_FUNCTION (this << delay.GetTimeStep () << event);
231  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::Schedule Thread-unsafe invocation!");
232 
233  Time tAbsolute = delay + TimeStep (m_currentTs);
234 
235  NS_ASSERT (tAbsolute.IsPositive ());
236  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
237  Scheduler::Event ev;
238  ev.impl = event;
239  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
240  ev.key.m_context = GetContext ();
241  ev.key.m_uid = m_uid;
242  m_uid++;
244  m_events->Insert (ev);
245  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
246 }
247 
248 void
249 DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *event)
250 {
251  NS_LOG_FUNCTION (this << context << delay.GetTimeStep () << event);
252 
254  {
255  Time tAbsolute = delay + TimeStep (m_currentTs);
256  Scheduler::Event ev;
257  ev.impl = event;
258  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
259  ev.key.m_context = context;
260  ev.key.m_uid = m_uid;
261  m_uid++;
263  m_events->Insert (ev);
264  }
265  else
266  {
267  EventWithContext ev;
268  ev.context = context;
269  // Current time added in ProcessEventsWithContext()
270  ev.timestamp = delay.GetTimeStep ();
271  ev.event = event;
272  {
274  m_eventsWithContext.push_back(ev);
275  m_eventsWithContextEmpty = false;
276  }
277  }
278 }
279 
280 EventId
282 {
283  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleNow Thread-unsafe invocation!");
284 
285  Scheduler::Event ev;
286  ev.impl = event;
287  ev.key.m_ts = m_currentTs;
288  ev.key.m_context = GetContext ();
289  ev.key.m_uid = m_uid;
290  m_uid++;
292  m_events->Insert (ev);
293  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
294 }
295 
296 EventId
298 {
299  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleDestroy Thread-unsafe invocation!");
300 
301  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
302  m_destroyEvents.push_back (id);
303  m_uid++;
304  return id;
305 }
306 
307 Time
309 {
310  // Do not add function logging here, to avoid stack overflow
311  return TimeStep (m_currentTs);
312 }
313 
314 Time
316 {
317  if (IsExpired (id))
318  {
319  return TimeStep (0);
320  }
321  else
322  {
323  return TimeStep (id.GetTs () - m_currentTs);
324  }
325 }
326 
327 void
329 {
330  if (id.GetUid () == 2)
331  {
332  // destroy events.
333  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
334  {
335  if (*i == id)
336  {
337  m_destroyEvents.erase (i);
338  break;
339  }
340  }
341  return;
342  }
343  if (IsExpired (id))
344  {
345  return;
346  }
347  Scheduler::Event event;
348  event.impl = id.PeekEventImpl ();
349  event.key.m_ts = id.GetTs ();
350  event.key.m_context = id.GetContext ();
351  event.key.m_uid = id.GetUid ();
352  m_events->Remove (event);
353  event.impl->Cancel ();
354  // whenever we remove an event from the event list, we have to unref it.
355  event.impl->Unref ();
356 
358 }
359 
360 void
362 {
363  if (!IsExpired (id))
364  {
365  id.PeekEventImpl ()->Cancel ();
366  }
367 }
368 
369 bool
371 {
372  if (id.GetUid () == 2)
373  {
374  if (id.PeekEventImpl () == 0 ||
375  id.PeekEventImpl ()->IsCancelled ())
376  {
377  return true;
378  }
379  // destroy events.
380  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
381  {
382  if (*i == id)
383  {
384  return false;
385  }
386  }
387  return true;
388  }
389  if (id.PeekEventImpl () == 0 ||
390  id.GetTs () < m_currentTs ||
391  (id.GetTs () == m_currentTs &&
392  id.GetUid () <= m_currentUid) ||
393  id.PeekEventImpl ()->IsCancelled ())
394  {
395  return true;
396  }
397  else
398  {
399  return false;
400  }
401 }
402 
403 Time
405 {
406  return TimeStep (0x7fffffffffffffffLL);
407 }
408 
409 uint32_t
411 {
412  return m_currentContext;
413 }
414 
415 } // namespace ns3
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
EventsWithContext m_eventsWithContext
The container of events from a different context.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
bool IsPositive(void) const
Definition: nstime.h:284
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
uint32_t m_currentUid
Unique id of the current event.
ns3::EventImpl declarations.
Ptr< Scheduler > m_events
The event priority queue.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
int m_unscheduledEvents
Number of events that have been inserted but not yet scheduled, not counting the Destroy events; this...
virtual void DoDispose(void)
Destructor implementation.
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:81
ns3::Ptr smart pointer declaration and 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.
uint32_t m_uid
Next event unique id.
Wrap an event with its execution context.
static ThreadId Self(void)
Returns the current thread Id.
DestroyEvents m_destroyEvents
The container of events to run at Destroy.
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:94
#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
SystemMutex m_eventsWithContextMutex
Mutex to control access to the list of events with context.
ns3::Simulator declaration.
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
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
EventImpl * event
The event implementation.
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations...
bool m_stop
Flag calling for the end of the simulation.
static EventId Schedule(Time const &delay, MEM mem_ptr, OBJ obj)
Schedule an event to expire after delay.
Definition: simulator.h:1375
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:95
static TypeId GetTypeId(void)
Register this type.
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:82
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
virtual Time Now(void) const
Return the current simulation virtual time.
ns3::DefaultSimulatorImpl declaration.
void Unref(void) const
Decrement the reference count.
uint32_t m_currentContext
Execution context of the current event.
Maintain the event list.
Definition: scheduler.h:66
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
Container type for the events from a different context.
Scheduler event.
Definition: scheduler.h:92
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
Get the raw time value, in the current resolution unit.
Definition: nstime.h:377
Time TimeStep(uint64_t ts)
Definition: nstime.h:1050
virtual void Remove(const EventId &id)
Remove an event from the event list.
The default single process simulator implementation.
Flag for events not associated with any particular context.
Definition: simulator.h:192
uint64_t m_currentTs
Timestamp of the current event.
NS_LOG_LOGIC("Net device "<< nd<< " is not bridged")
static bool Equals(ThreadId id)
Compares an ThreadId with the current ThreadId .
virtual EventId Schedule(const Time &delay, EventImpl *event)
Schedule a future event execution (in the same context).
#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
Instantiate subclasses of ns3::Object.
A simulation event.
Definition: event-impl.h:44
virtual void ScheduleWithContext(uint32_t context, const Time &delay, EventImpl *event)
Schedule a future event execution (in a different context).
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:234
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
Main execution thread.
Debug message logging.
void ProcessOneEvent(void)
Process the next event.
bool m_eventsWithContextEmpty
Flag true if all events with context have been moved to the primary event queue.
ns3::PointerValue attribute value declarations and template implementations.
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:914
uint32_t m_context
Event context.
Definition: scheduler.h:83
The SimulatorImpl base class.
void ProcessEventsWithContext(void)
Move events from a different context into the main event queue.