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 {
408  return TimeStep (0x7fffffffffffffffLL);
409 }
410 
411 uint32_t
413 {
414  return m_currentContext;
415 }
416 
417 } // 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:44
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
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.
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:1238
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
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.
uint32_t m_currentContext
Execution context of the current event.
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
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:952
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.
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:209
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.
Pointer 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:904
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.