A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
21
22#include "assert.h"
23#include "log.h"
24#include "scheduler.h"
25#include "simulator.h"
26
27#include <cmath>
28
29/**
30 * \file
31 * \ingroup simulator
32 * ns3::DefaultSimulatorImpl implementation.
33 */
34
35namespace 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
41NS_LOG_COMPONENT_DEFINE("DefaultSimulatorImpl");
42
43NS_OBJECT_ENSURE_REGISTERED(DefaultSimulatorImpl);
44
45TypeId
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
74void
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
89void
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
105void
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
125{
126 return 0;
127}
128
129void
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
150bool
152{
153 return m_events->IsEmpty() || m_stop;
154}
155
156void
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();
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
186void
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 {
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
205void
207{
208 NS_LOG_FUNCTION(this);
209 m_stop = true;
210}
211
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//
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
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
243void
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);
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 {
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);
271 }
272 }
273}
274
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
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
296Time
298{
299 // Do not add function logging here, to avoid stack overflow
300 return TimeStep(m_currentTs);
301}
302
303Time
305{
306 if (IsExpired(id))
307 {
308 return TimeStep(0);
309 }
310 else
311 {
312 return TimeStep(id.GetTs() - m_currentTs);
313 }
314}
315
316void
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
349void
351{
352 if (!IsExpired(id))
353 {
354 id.PeekEventImpl()->Cancel();
355 }
356}
357
358bool
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
382Time
384{
385 return TimeStep(0x7fffffffffffffffLL);
386}
387
390{
391 return m_currentContext;
392}
393
394uint64_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
@ INVALID
Invalid UID value.
Definition: event-id.h:61
@ VALID
Schedule(), etc.
Definition: event-id.h:69
@ DESTROY
ScheduleDestroy() events.
Definition: event-id.h:65
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:444
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:932
ns3::DefaultSimulatorImpl declaration.
#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.
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