A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
default-simulator-impl.cc
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 // Note: Logging in this file is largely avoided due to the
34 // number of calls that are made to these functions and the possibility
35 // of causing recursions leading to stack overflow
36 
37 NS_LOG_COMPONENT_DEFINE ("DefaultSimulatorImpl");
38 
39 namespace ns3 {
40 
41 NS_OBJECT_ENSURE_REGISTERED (DefaultSimulatorImpl);
42 
43 TypeId
44 DefaultSimulatorImpl::GetTypeId (void)
45 {
46  static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl")
47  .SetParent<SimulatorImpl> ()
48  .AddConstructor<DefaultSimulatorImpl> ()
49  ;
50  return tid;
51 }
52 
53 DefaultSimulatorImpl::DefaultSimulatorImpl ()
54 {
55  NS_LOG_FUNCTION (this);
56  m_stop = false;
57  // uids are allocated from 4.
58  // uid 0 is "invalid" events
59  // uid 1 is "now" events
60  // uid 2 is "destroy" events
61  m_uid = 4;
62  // before ::Run is entered, the m_currentUid will be zero
63  m_currentUid = 0;
64  m_currentTs = 0;
65  m_currentContext = 0xffffffff;
66  m_unscheduledEvents = 0;
67  m_eventsWithContextEmpty = true;
68  m_main = SystemThread::Self();
69 }
70 
71 DefaultSimulatorImpl::~DefaultSimulatorImpl ()
72 {
73  NS_LOG_FUNCTION (this);
74 }
75 
76 void
78 {
79  NS_LOG_FUNCTION (this);
80  while (!m_events->IsEmpty ())
81  {
82  Scheduler::Event next = m_events->RemoveNext ();
83  next.impl->Unref ();
84  }
85  m_events = 0;
87 }
88 void
90 {
91  NS_LOG_FUNCTION (this);
92  while (!m_destroyEvents.empty ())
93  {
94  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
95  m_destroyEvents.pop_front ();
96  NS_LOG_LOGIC ("handle destroy " << ev);
97  if (!ev->IsCancelled ())
98  {
99  ev->Invoke ();
100  }
101  }
102 }
103 
104 void
106 {
107  NS_LOG_FUNCTION (this << schedulerFactory);
108  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
109 
110  if (m_events != 0)
111  {
112  while (!m_events->IsEmpty ())
113  {
114  Scheduler::Event next = m_events->RemoveNext ();
115  scheduler->Insert (next);
116  }
117  }
118  m_events = scheduler;
119 }
120 
121 // System ID for non-distributed simulation is always zero
122 uint32_t
124 {
125  return 0;
126 }
127 
128 void
129 DefaultSimulatorImpl::ProcessOneEvent (void)
130 {
131  Scheduler::Event next = m_events->RemoveNext ();
132 
133  NS_ASSERT (next.key.m_ts >= m_currentTs);
134  m_unscheduledEvents--;
135 
136  NS_LOG_LOGIC ("handle " << next.key.m_ts);
137  m_currentTs = next.key.m_ts;
138  m_currentContext = next.key.m_context;
139  m_currentUid = next.key.m_uid;
140  next.impl->Invoke ();
141  next.impl->Unref ();
142 
143  ProcessEventsWithContext ();
144 }
145 
146 bool
148 {
149  return m_events->IsEmpty () || m_stop;
150 }
151 
152 void
153 DefaultSimulatorImpl::ProcessEventsWithContext (void)
154 {
155  if (m_eventsWithContextEmpty)
156  {
157  return;
158  }
159 
160  // swap queues
161  EventsWithContext eventsWithContext;
162  {
163  CriticalSection cs (m_eventsWithContextMutex);
164  m_eventsWithContext.swap(eventsWithContext);
165  m_eventsWithContextEmpty = true;
166  }
167  while (!eventsWithContext.empty ())
168  {
169  EventWithContext event = eventsWithContext.front ();
170  eventsWithContext.pop_front ();
171  Scheduler::Event ev;
172  ev.impl = event.event;
173  ev.key.m_ts = m_currentTs + event.timestamp;
174  ev.key.m_context = event.context;
175  ev.key.m_uid = m_uid;
176  m_uid++;
177  m_unscheduledEvents++;
178  m_events->Insert (ev);
179  }
180 }
181 
182 void
184 {
185  NS_LOG_FUNCTION (this);
186  // Set the current threadId as the main threadId
187  m_main = SystemThread::Self();
188  ProcessEventsWithContext ();
189  m_stop = false;
190 
191  while (!m_events->IsEmpty () && !m_stop)
192  {
193  ProcessOneEvent ();
194  }
195 
196  // If the simulator stopped naturally by lack of events, make a
197  // consistency test to check that we didn't lose any events along the way.
198  NS_ASSERT (!m_events->IsEmpty () || m_unscheduledEvents == 0);
199 }
200 
201 void
203 {
204  NS_LOG_FUNCTION (this);
205  m_stop = true;
206 }
207 
208 void
210 {
211  NS_LOG_FUNCTION (this << time.GetTimeStep ());
213 }
214 
215 //
216 // Schedule an event for a _relative_ time in the future.
217 //
218 EventId
220 {
221  NS_LOG_FUNCTION (this << time.GetTimeStep () << event);
222  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::Schedule Thread-unsafe invocation!");
223 
224  Time tAbsolute = time + TimeStep (m_currentTs);
225 
226  NS_ASSERT (tAbsolute.IsPositive ());
227  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
228  Scheduler::Event ev;
229  ev.impl = event;
230  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
231  ev.key.m_context = GetContext ();
232  ev.key.m_uid = m_uid;
233  m_uid++;
234  m_unscheduledEvents++;
235  m_events->Insert (ev);
236  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
237 }
238 
239 void
240 DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event)
241 {
242  NS_LOG_FUNCTION (this << context << time.GetTimeStep () << event);
243 
244  if (SystemThread::Equals (m_main))
245  {
246  Time tAbsolute = time + TimeStep (m_currentTs);
247  Scheduler::Event ev;
248  ev.impl = event;
249  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
250  ev.key.m_context = context;
251  ev.key.m_uid = m_uid;
252  m_uid++;
253  m_unscheduledEvents++;
254  m_events->Insert (ev);
255  }
256  else
257  {
258  EventWithContext ev;
259  ev.context = context;
260  ev.timestamp = time.GetTimeStep ();
261  ev.event = event;
262  {
263  CriticalSection cs (m_eventsWithContextMutex);
264  m_eventsWithContext.push_back(ev);
265  m_eventsWithContextEmpty = false;
266  }
267  }
268 }
269 
270 EventId
272 {
273  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleNow Thread-unsafe invocation!");
274 
275  Scheduler::Event ev;
276  ev.impl = event;
277  ev.key.m_ts = m_currentTs;
278  ev.key.m_context = GetContext ();
279  ev.key.m_uid = m_uid;
280  m_uid++;
281  m_unscheduledEvents++;
282  m_events->Insert (ev);
283  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
284 }
285 
286 EventId
288 {
289  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleDestroy Thread-unsafe invocation!");
290 
291  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
292  m_destroyEvents.push_back (id);
293  m_uid++;
294  return id;
295 }
296 
297 Time
299 {
300  // Do not add function logging here, to avoid stack overflow
301  return TimeStep (m_currentTs);
302 }
303 
304 Time
306 {
307  if (IsExpired (id))
308  {
309  return TimeStep (0);
310  }
311  else
312  {
313  return TimeStep (id.GetTs () - m_currentTs);
314  }
315 }
316 
317 void
319 {
320  if (id.GetUid () == 2)
321  {
322  // destroy events.
323  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
324  {
325  if (*i == id)
326  {
327  m_destroyEvents.erase (i);
328  break;
329  }
330  }
331  return;
332  }
333  if (IsExpired (id))
334  {
335  return;
336  }
337  Scheduler::Event event;
338  event.impl = id.PeekEventImpl ();
339  event.key.m_ts = id.GetTs ();
340  event.key.m_context = id.GetContext ();
341  event.key.m_uid = id.GetUid ();
342  m_events->Remove (event);
343  event.impl->Cancel ();
344  // whenever we remove an event from the event list, we have to unref it.
345  event.impl->Unref ();
346 
347  m_unscheduledEvents--;
348 }
349 
350 void
352 {
353  if (!IsExpired (id))
354  {
355  id.PeekEventImpl ()->Cancel ();
356  }
357 }
358 
359 bool
361 {
362  if (ev.GetUid () == 2)
363  {
364  if (ev.PeekEventImpl () == 0 ||
365  ev.PeekEventImpl ()->IsCancelled ())
366  {
367  return true;
368  }
369  // destroy events.
370  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
371  {
372  if (*i == ev)
373  {
374  return false;
375  }
376  }
377  return true;
378  }
379  if (ev.PeekEventImpl () == 0 ||
380  ev.GetTs () < m_currentTs ||
381  (ev.GetTs () == m_currentTs &&
382  ev.GetUid () <= m_currentUid) ||
383  ev.PeekEventImpl ()->IsCancelled ())
384  {
385  return true;
386  }
387  else
388  {
389  return false;
390  }
391 }
392 
393 Time
395 {
396  // XXX: I am fairly certain other compilers use other non-standard
397  // post-fixes to indicate 64 bit constants.
398  return TimeStep (0x7fffffffffffffffLL);
399 }
400 
401 uint32_t
403 {
404  return m_currentContext;
405 }
406 
407 } // namespace ns3
keep track of time unit.
Definition: nstime.h:149
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:59
bool IsPositive(void) const
Definition: nstime.h:234
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
virtual Time GetMaximumSimulationTime(void) const
virtual void SetScheduler(ObjectFactory schedulerFactory)
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
bool IsCancelled(void)
Definition: event-impl.cc:57
virtual void DoDispose(void)
Definition: object.cc:335
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Definition: simulator.h:820
virtual EventId ScheduleNow(EventImpl *event)
virtual uint32_t GetSystemId(void) const
void Invoke(void)
Definition: event-impl.cc:40
virtual void Remove(const EventId &ev)
Ptr< Object > Create(void) const
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:109
virtual Time Now(void) const
void Unref(void) const
Maintain the event list.
Definition: scheduler.h:53
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
virtual bool IsExpired(const EventId &ev) const
virtual Time GetDelayLeft(const EventId &id) const
virtual EventId ScheduleDestroy(EventImpl *event)
static bool Equals(ThreadId id)
Compares an TharedId with the current ThreadId .
virtual void Cancel(const EventId &ev)
virtual uint32_t GetContext(void) const
int64_t GetTimeStep(void) const
Definition: nstime.h:311
virtual void ScheduleWithContext(uint32_t context, Time const &time, EventImpl *event)
#define NS_ASSERT_MSG(condition, message)
Definition: assert.h:86
virtual EventId Schedule(Time const &time, EventImpl *event)
instantiate subclasses of ns3::Object.
a simulation event
Definition: event-impl.h:39
virtual bool IsFinished(void) const
an identifier for simulation events.
Definition: event-id.h:46
static void Stop(void)
Definition: simulator.cc:164
static ThreadId Self(void)
Returns the current thread Id.