A Discrete-Event Network Simulator
API
default-simulator-impl.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005,2006 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  */
19 
20 #include "default-simulator-impl.h"
21 
22 #include "assert.h"
23 #include "log.h"
24 #include "scheduler.h"
25 #include "simulator.h"
26 
27 #include <cmath>
28 
35 namespace ns3
36 {
37 
38 // Note: Logging in this file is largely avoided due to the
39 // number of calls that are made to these functions and the possibility
40 // of causing recursions leading to stack overflow
41 NS_LOG_COMPONENT_DEFINE("DefaultSimulatorImpl");
42 
43 NS_OBJECT_ENSURE_REGISTERED(DefaultSimulatorImpl);
44 
45 TypeId
47 {
48  static TypeId tid = TypeId("ns3::DefaultSimulatorImpl")
50  .SetGroupName("Core")
51  .AddConstructor<DefaultSimulatorImpl>();
52  return tid;
53 }
54 
56 {
57  NS_LOG_FUNCTION(this);
58  m_stop = false;
61  m_currentTs = 0;
64  m_eventCount = 0;
66  m_mainThreadId = std::this_thread::get_id();
67 }
68 
70 {
71  NS_LOG_FUNCTION(this);
72 }
73 
74 void
76 {
77  NS_LOG_FUNCTION(this);
79 
80  while (!m_events->IsEmpty())
81  {
82  Scheduler::Event next = m_events->RemoveNext();
83  next.impl->Unref();
84  }
85  m_events = nullptr;
87 }
88 
89 void
91 {
92  NS_LOG_FUNCTION(this);
93  while (!m_destroyEvents.empty())
94  {
95  Ptr<EventImpl> ev = m_destroyEvents.front().PeekEventImpl();
96  m_destroyEvents.pop_front();
97  NS_LOG_LOGIC("handle destroy " << ev);
98  if (!ev->IsCancelled())
99  {
100  ev->Invoke();
101  }
102  }
103 }
104 
105 void
107 {
108  NS_LOG_FUNCTION(this << schedulerFactory);
109  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler>();
110 
111  if (m_events)
112  {
113  while (!m_events->IsEmpty())
114  {
115  Scheduler::Event next = m_events->RemoveNext();
116  scheduler->Insert(next);
117  }
118  }
119  m_events = scheduler;
120 }
121 
122 // System ID for non-distributed simulation is always zero
123 uint32_t
125 {
126  return 0;
127 }
128 
129 void
131 {
132  Scheduler::Event next = m_events->RemoveNext();
133 
134  PreEventHook(EventId(next.impl, next.key.m_ts, next.key.m_context, next.key.m_uid));
135 
136  NS_ASSERT(next.key.m_ts >= m_currentTs);
138  m_eventCount++;
139 
140  NS_LOG_LOGIC("handle " << next.key.m_ts);
141  m_currentTs = next.key.m_ts;
143  m_currentUid = next.key.m_uid;
144  next.impl->Invoke();
145  next.impl->Unref();
146 
148 }
149 
150 bool
152 {
153  return m_events->IsEmpty() || m_stop;
154 }
155 
156 void
158 {
160  {
161  return;
162  }
163 
164  // swap queues
165  EventsWithContext eventsWithContext;
166  {
167  std::unique_lock lock{m_eventsWithContextMutex};
168  m_eventsWithContext.swap(eventsWithContext);
170  }
171  while (!eventsWithContext.empty())
172  {
173  EventWithContext event = eventsWithContext.front();
174  eventsWithContext.pop_front();
175  Scheduler::Event ev;
176  ev.impl = event.event;
177  ev.key.m_ts = m_currentTs + event.timestamp;
178  ev.key.m_context = event.context;
179  ev.key.m_uid = m_uid;
180  m_uid++;
182  m_events->Insert(ev);
183  }
184 }
185 
186 void
188 {
189  NS_LOG_FUNCTION(this);
190  // Set the current threadId as the main threadId
191  m_mainThreadId = std::this_thread::get_id();
193  m_stop = false;
194 
195  while (!m_events->IsEmpty() && !m_stop)
196  {
197  ProcessOneEvent();
198  }
199 
200  // If the simulator stopped naturally by lack of events, make a
201  // consistency test to check that we didn't lose any events along the way.
202  NS_ASSERT(!m_events->IsEmpty() || m_unscheduledEvents == 0);
203 }
204 
205 void
207 {
208  NS_LOG_FUNCTION(this);
209  m_stop = true;
210 }
211 
212 EventId
214 {
215  NS_LOG_FUNCTION(this << delay.GetTimeStep());
216  return Simulator::Schedule(delay, &Simulator::Stop);
217 }
218 
219 //
220 // Schedule an event for a _relative_ time in the future.
221 //
222 EventId
224 {
225  NS_LOG_FUNCTION(this << delay.GetTimeStep() << event);
226  NS_ASSERT_MSG(m_mainThreadId == std::this_thread::get_id(),
227  "Simulator::Schedule Thread-unsafe invocation!");
228 
229  NS_ASSERT_MSG(delay.IsPositive(), "DefaultSimulatorImpl::Schedule(): Negative delay");
230  Time tAbsolute = delay + TimeStep(m_currentTs);
231 
232  Scheduler::Event ev;
233  ev.impl = event;
234  ev.key.m_ts = (uint64_t)tAbsolute.GetTimeStep();
235  ev.key.m_context = GetContext();
236  ev.key.m_uid = m_uid;
237  m_uid++;
239  m_events->Insert(ev);
240  return EventId(event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
241 }
242 
243 void
244 DefaultSimulatorImpl::ScheduleWithContext(uint32_t context, const Time& delay, EventImpl* event)
245 {
246  NS_LOG_FUNCTION(this << context << delay.GetTimeStep() << event);
247 
248  if (m_mainThreadId == std::this_thread::get_id())
249  {
250  Time tAbsolute = delay + TimeStep(m_currentTs);
251  Scheduler::Event ev;
252  ev.impl = event;
253  ev.key.m_ts = (uint64_t)tAbsolute.GetTimeStep();
254  ev.key.m_context = context;
255  ev.key.m_uid = m_uid;
256  m_uid++;
258  m_events->Insert(ev);
259  }
260  else
261  {
262  EventWithContext ev;
263  ev.context = context;
264  // Current time added in ProcessEventsWithContext()
265  ev.timestamp = delay.GetTimeStep();
266  ev.event = event;
267  {
268  std::unique_lock lock{m_eventsWithContextMutex};
269  m_eventsWithContext.push_back(ev);
270  m_eventsWithContextEmpty = false;
271  }
272  }
273 }
274 
275 EventId
277 {
278  NS_ASSERT_MSG(m_mainThreadId == std::this_thread::get_id(),
279  "Simulator::ScheduleNow Thread-unsafe invocation!");
280 
281  return Schedule(Time(0), event);
282 }
283 
284 EventId
286 {
287  NS_ASSERT_MSG(m_mainThreadId == std::this_thread::get_id(),
288  "Simulator::ScheduleDestroy Thread-unsafe invocation!");
289 
290  EventId id(Ptr<EventImpl>(event, false), m_currentTs, 0xffffffff, 2);
291  m_destroyEvents.push_back(id);
292  m_uid++;
293  return id;
294 }
295 
296 Time
298 {
299  // Do not add function logging here, to avoid stack overflow
300  return TimeStep(m_currentTs);
301 }
302 
303 Time
305 {
306  if (IsExpired(id))
307  {
308  return TimeStep(0);
309  }
310  else
311  {
312  return TimeStep(id.GetTs() - m_currentTs);
313  }
314 }
315 
316 void
318 {
319  if (id.GetUid() == EventId::UID::DESTROY)
320  {
321  // destroy events.
322  for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
323  {
324  if (*i == id)
325  {
326  m_destroyEvents.erase(i);
327  break;
328  }
329  }
330  return;
331  }
332  if (IsExpired(id))
333  {
334  return;
335  }
336  Scheduler::Event event;
337  event.impl = id.PeekEventImpl();
338  event.key.m_ts = id.GetTs();
339  event.key.m_context = id.GetContext();
340  event.key.m_uid = id.GetUid();
341  m_events->Remove(event);
342  event.impl->Cancel();
343  // whenever we remove an event from the event list, we have to unref it.
344  event.impl->Unref();
345 
347 }
348 
349 void
351 {
352  if (!IsExpired(id))
353  {
354  id.PeekEventImpl()->Cancel();
355  }
356 }
357 
358 bool
360 {
361  if (id.GetUid() == EventId::UID::DESTROY)
362  {
363  if (id.PeekEventImpl() == nullptr || id.PeekEventImpl()->IsCancelled())
364  {
365  return true;
366  }
367  // destroy events.
368  for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
369  {
370  if (*i == id)
371  {
372  return false;
373  }
374  }
375  return true;
376  }
377  return id.PeekEventImpl() == nullptr || id.GetTs() < m_currentTs ||
378  (id.GetTs() == m_currentTs && id.GetUid() <= m_currentUid) ||
379  id.PeekEventImpl()->IsCancelled();
380 }
381 
382 Time
384 {
385  return TimeStep(0x7fffffffffffffffLL);
386 }
387 
388 uint32_t
390 {
391  return m_currentContext;
392 }
393 
394 uint64_t
396 {
397  return m_eventCount;
398 }
399 
400 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
The default single process simulator implementation.
bool m_stop
Flag calling for the end of the simulation.
bool m_eventsWithContextEmpty
Flag true if all events with context have been moved to the primary event queue.
uint32_t m_currentContext
Execution context of the current event.
void ProcessEventsWithContext()
Move events from a different context into the main event queue.
static TypeId GetTypeId()
Register this type.
void Run() override
Run the simulation.
uint32_t GetSystemId() const override
Get the system id of this simulator.
DestroyEvents m_destroyEvents
The container of events to run at Destroy.
void ScheduleWithContext(uint32_t context, const Time &delay, EventImpl *event) override
Schedule a future event execution (in a different context).
EventId ScheduleNow(EventImpl *event) override
Schedule an event to run at the current virtual time.
Ptr< Scheduler > m_events
The event priority queue.
void Remove(const EventId &id) override
Remove an event from the event list.
Time GetDelayLeft(const EventId &id) const override
Get the remaining time until this event will execute.
uint64_t m_currentTs
Timestamp of the current event.
uint64_t GetEventCount() const override
Get the number of events executed.
std::list< EventWithContext > EventsWithContext
Container type for the events from a different context.
void Cancel(const EventId &id) override
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
uint32_t GetContext() const override
Get the current simulation context.
Time Now() const override
Return the current simulation virtual time.
uint64_t m_eventCount
The event count.
void DoDispose() override
Destructor implementation.
int m_unscheduledEvents
Number of events that have been inserted but not yet scheduled, not counting the Destroy events; this...
EventId ScheduleDestroy(EventImpl *event) override
Schedule an event to run at the end of the simulation, after the Stop() time or condition has been re...
Time GetMaximumSimulationTime() const override
Get the maximum representable simulation time.
EventId Schedule(const Time &delay, EventImpl *event) override
Schedule a future event execution (in the same context).
void Destroy() override
Execute the events scheduled with ScheduleDestroy().
std::mutex m_eventsWithContextMutex
Mutex to control access to the list of events with context.
uint32_t m_uid
Next event unique id.
uint32_t m_currentUid
Unique id of the current event.
~DefaultSimulatorImpl() override
Destructor.
void Stop() override
Tell the Simulator the calling event should be the last one executed.
bool IsFinished() const override
Check if the simulation should finish.
void ProcessOneEvent()
Process the next event.
bool IsExpired(const EventId &id) const override
Check if an event has already run or been cancelled.
std::thread::id m_mainThreadId
Main execution thread.
void SetScheduler(ObjectFactory schedulerFactory) override
Set the Scheduler to be used to manage the event list.
EventsWithContext m_eventsWithContext
The container of events from a different context.
An identifier for simulation events.
Definition: event-id.h:55
A simulation event.
Definition: event-impl.h:46
void Invoke()
Called by the simulation engine to notify the event that it is time to execute.
Definition: event-impl.cc:47
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:352
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Maintain the event list.
Definition: scheduler.h:157
void Unref() const
Decrement the reference count.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
@ NO_CONTEXT
Flag for events not associated with any particular context.
Definition: simulator.h:210
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
The SimulatorImpl base class.
virtual void PreEventHook(const EventId &id)
Hook called before processing each event.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
bool IsPositive() const
Exactly equivalent to t >= 0.
Definition: nstime.h:333
int64_t GetTimeStep() const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:445
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
ns3::DefaultSimulatorImpl declaration.
@ INVALID
INVALID.
Definition: aodv-rtable.h:53
@ VALID
VALID.
Definition: aodv-rtable.h:52
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#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:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Debug message logging.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:839
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations.
ns3::Simulator declaration.
Wrap an event with its execution context.
EventImpl * event
The event implementation.
Scheduler event.
Definition: scheduler.h:184
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:186
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:185
uint32_t m_context
Event context.
Definition: scheduler.h:173
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:171
uint32_t m_uid
Event unique id.
Definition: scheduler.h:172