A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 <math.h>
32 
33 NS_LOG_COMPONENT_DEFINE ("DefaultSimulatorImpl");
34 
35 namespace ns3 {
36 
37 NS_OBJECT_ENSURE_REGISTERED (DefaultSimulatorImpl);
38 
39 TypeId
41 {
42  static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl")
44  .AddConstructor<DefaultSimulatorImpl> ()
45  ;
46  return tid;
47 }
48 
50 {
51  m_stop = false;
52  // uids are allocated from 4.
53  // uid 0 is "invalid" events
54  // uid 1 is "now" events
55  // uid 2 is "destroy" events
56  m_uid = 4;
57  // before ::Run is entered, the m_currentUid will be zero
58  m_currentUid = 0;
59  m_currentTs = 0;
60  m_currentContext = 0xffffffff;
64 }
65 
67 {
68 }
69 
70 void
72 {
73  while (!m_events->IsEmpty ())
74  {
76  next.impl->Unref ();
77  }
78  m_events = 0;
80 }
81 void
83 {
84  while (!m_destroyEvents.empty ())
85  {
86  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
87  m_destroyEvents.pop_front ();
88  NS_LOG_LOGIC ("handle destroy " << ev);
89  if (!ev->IsCancelled ())
90  {
91  ev->Invoke ();
92  }
93  }
94 }
95 
96 void
98 {
99  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
100 
101  if (m_events != 0)
102  {
103  while (!m_events->IsEmpty ())
104  {
106  scheduler->Insert (next);
107  }
108  }
109  m_events = scheduler;
110 }
111 
112 // System ID for non-distributed simulation is always zero
113 uint32_t
115 {
116  return 0;
117 }
118 
119 void
121 {
123 
124  NS_ASSERT (next.key.m_ts >= m_currentTs);
126 
127  NS_LOG_LOGIC ("handle " << next.key.m_ts);
128  m_currentTs = next.key.m_ts;
130  m_currentUid = next.key.m_uid;
131  next.impl->Invoke ();
132  next.impl->Unref ();
133 
135 }
136 
137 bool
139 {
140  return m_events->IsEmpty () || m_stop;
141 }
142 
143 void
145 {
147  {
148  return;
149  }
150 
151  // swap queues
152  EventsWithContext eventsWithContext;
153  {
155  m_eventsWithContext.swap(eventsWithContext);
157  }
158  while (!eventsWithContext.empty ())
159  {
160  EventWithContext event = eventsWithContext.front ();
161  eventsWithContext.pop_front ();
162  Scheduler::Event ev;
163  ev.impl = event.event;
164  ev.key.m_ts = m_currentTs + event.timestamp;
165  ev.key.m_context = event.context;
166  ev.key.m_uid = m_uid;
167  m_uid++;
169  m_events->Insert (ev);
170  }
171 }
172 
173 void
175 {
176  // Set the current threadId as the main threadId
179  m_stop = false;
180 
181  while (!m_events->IsEmpty () && !m_stop)
182  {
183  ProcessOneEvent ();
184  }
185 
186  // If the simulator stopped naturally by lack of events, make a
187  // consistency test to check that we didn't lose any events along the way.
189 }
190 
191 void
193 {
194  m_stop = true;
195 }
196 
197 void
199 {
201 }
202 
203 //
204 // Schedule an event for a _relative_ time in the future.
205 //
206 EventId
208 {
209  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::Schedule Thread-unsafe invocation!");
210 
211  Time tAbsolute = time + TimeStep (m_currentTs);
212 
213  NS_ASSERT (tAbsolute.IsPositive ());
214  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
215  Scheduler::Event ev;
216  ev.impl = event;
217  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
218  ev.key.m_context = GetContext ();
219  ev.key.m_uid = m_uid;
220  m_uid++;
222  m_events->Insert (ev);
223  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
224 }
225 
226 void
227 DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event)
228 {
229  NS_LOG_FUNCTION (this << context << time.GetTimeStep () << m_currentTs << event);
230 
232  {
233  Time tAbsolute = time + TimeStep (m_currentTs);
234  Scheduler::Event ev;
235  ev.impl = event;
236  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
237  ev.key.m_context = context;
238  ev.key.m_uid = m_uid;
239  m_uid++;
241  m_events->Insert (ev);
242  }
243  else
244  {
245  EventWithContext ev;
246  ev.context = context;
247  ev.timestamp = time.GetTimeStep ();
248  ev.event = event;
249  {
251  m_eventsWithContext.push_back(ev);
252  m_eventsWithContextEmpty = false;
253  }
254  }
255 }
256 
257 EventId
259 {
260  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleNow Thread-unsafe invocation!");
261 
262  Scheduler::Event ev;
263  ev.impl = event;
264  ev.key.m_ts = m_currentTs;
265  ev.key.m_context = GetContext ();
266  ev.key.m_uid = m_uid;
267  m_uid++;
269  m_events->Insert (ev);
270  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
271 }
272 
273 EventId
275 {
276  NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleDestroy Thread-unsafe invocation!");
277 
278  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
279  m_destroyEvents.push_back (id);
280  m_uid++;
281  return id;
282 }
283 
284 Time
286 {
287  return TimeStep (m_currentTs);
288 }
289 
290 Time
292 {
293  if (IsExpired (id))
294  {
295  return TimeStep (0);
296  }
297  else
298  {
299  return TimeStep (id.GetTs () - m_currentTs);
300  }
301 }
302 
303 void
305 {
306  if (id.GetUid () == 2)
307  {
308  // destroy events.
309  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
310  {
311  if (*i == id)
312  {
313  m_destroyEvents.erase (i);
314  break;
315  }
316  }
317  return;
318  }
319  if (IsExpired (id))
320  {
321  return;
322  }
323  Scheduler::Event event;
324  event.impl = id.PeekEventImpl ();
325  event.key.m_ts = id.GetTs ();
326  event.key.m_context = id.GetContext ();
327  event.key.m_uid = id.GetUid ();
328  m_events->Remove (event);
329  event.impl->Cancel ();
330  // whenever we remove an event from the event list, we have to unref it.
331  event.impl->Unref ();
332 
334 }
335 
336 void
338 {
339  if (!IsExpired (id))
340  {
341  id.PeekEventImpl ()->Cancel ();
342  }
343 }
344 
345 bool
347 {
348  if (ev.GetUid () == 2)
349  {
350  if (ev.PeekEventImpl () == 0 ||
351  ev.PeekEventImpl ()->IsCancelled ())
352  {
353  return true;
354  }
355  // destroy events.
356  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
357  {
358  if (*i == ev)
359  {
360  return false;
361  }
362  }
363  return true;
364  }
365  if (ev.PeekEventImpl () == 0 ||
366  ev.GetTs () < m_currentTs ||
367  (ev.GetTs () == m_currentTs &&
368  ev.GetUid () <= m_currentUid) ||
369  ev.PeekEventImpl ()->IsCancelled ())
370  {
371  return true;
372  }
373  else
374  {
375  return false;
376  }
377 }
378 
379 Time
381 {
382  // XXX: I am fairly certain other compilers use other non-standard
383  // post-fixes to indicate 64 bit constants.
384  return TimeStep (0x7fffffffffffffffLL);
385 }
386 
387 uint32_t
389 {
390  return m_currentContext;
391 }
392 
393 } // namespace ns3
394 
395