don't use EventId in Schedulers: use Scheduler::Event instead.
This commit is contained in:
@@ -69,7 +69,8 @@ DefaultSimulatorImpl::~DefaultSimulatorImpl ()
|
||||
{
|
||||
while (!m_events->IsEmpty ())
|
||||
{
|
||||
EventId next = m_events->RemoveNext ();
|
||||
Scheduler::Event next = m_events->RemoveNext ();
|
||||
next.impl->Unref ();
|
||||
}
|
||||
m_events = 0;
|
||||
}
|
||||
@@ -96,7 +97,7 @@ DefaultSimulatorImpl::SetScheduler (Ptr<Scheduler> scheduler)
|
||||
{
|
||||
while (!m_events->IsEmpty ())
|
||||
{
|
||||
EventId next = m_events->RemoveNext ();
|
||||
Scheduler::Event next = m_events->RemoveNext ();
|
||||
scheduler->Insert (next);
|
||||
}
|
||||
}
|
||||
@@ -113,16 +114,16 @@ DefaultSimulatorImpl::GetScheduler (void) const
|
||||
void
|
||||
DefaultSimulatorImpl::ProcessOneEvent (void)
|
||||
{
|
||||
EventId next = m_events->RemoveNext ();
|
||||
Scheduler::Event next = m_events->RemoveNext ();
|
||||
|
||||
NS_ASSERT (next.GetTs () >= m_currentTs);
|
||||
NS_ASSERT (next.key.m_ts >= m_currentTs);
|
||||
--m_unscheduledEvents;
|
||||
|
||||
NS_LOG_LOGIC ("handle " << next.GetTs ());
|
||||
m_currentTs = next.GetTs ();
|
||||
m_currentUid = next.GetUid ();
|
||||
EventImpl *event = next.PeekEventImpl ();
|
||||
event->Invoke ();
|
||||
NS_LOG_LOGIC ("handle " << next.key.m_ts);
|
||||
m_currentTs = next.key.m_ts;
|
||||
m_currentUid = next.key.m_uid;
|
||||
next.impl->Invoke ();
|
||||
next.impl->Unref ();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -135,8 +136,8 @@ uint64_t
|
||||
DefaultSimulatorImpl::NextTs (void) const
|
||||
{
|
||||
NS_ASSERT (!m_events->IsEmpty ());
|
||||
EventId id = m_events->PeekNext ();
|
||||
return id.GetTs ();
|
||||
Scheduler::Event ev = m_events->PeekNext ();
|
||||
return ev.key.m_ts;
|
||||
}
|
||||
|
||||
Time
|
||||
@@ -190,22 +191,27 @@ DefaultSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
|
||||
|
||||
NS_ASSERT (tAbsolute.IsPositive ());
|
||||
NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
|
||||
uint64_t ts = (uint64_t) tAbsolute.GetTimeStep ();
|
||||
EventId id (event, ts, m_uid);
|
||||
Scheduler::Event ev;
|
||||
ev.impl = GetPointer (event);
|
||||
ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
|
||||
ev.key.m_uid = m_uid;
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
m_events->Insert (id);
|
||||
return id;
|
||||
m_events->Insert (ev);
|
||||
return EventId (event, ev.key.m_ts, ev.key.m_uid);
|
||||
}
|
||||
|
||||
EventId
|
||||
DefaultSimulatorImpl::ScheduleNow (const Ptr<EventImpl> &event)
|
||||
{
|
||||
EventId id (event, m_currentTs, m_uid);
|
||||
Scheduler::Event ev;
|
||||
ev.impl = GetPointer (event);
|
||||
ev.key.m_ts = m_currentTs;
|
||||
ev.key.m_uid = m_uid;
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
m_events->Insert (id);
|
||||
return id;
|
||||
m_events->Insert (ev);
|
||||
return EventId (event, ev.key.m_ts, ev.key.m_uid);
|
||||
}
|
||||
|
||||
EventId
|
||||
@@ -237,14 +243,14 @@ DefaultSimulatorImpl::GetDelayLeft (const EventId &id) const
|
||||
}
|
||||
|
||||
void
|
||||
DefaultSimulatorImpl::Remove (const EventId &ev)
|
||||
DefaultSimulatorImpl::Remove (const EventId &id)
|
||||
{
|
||||
if (ev.GetUid () == 2)
|
||||
if (id.GetUid () == 2)
|
||||
{
|
||||
// destroy events.
|
||||
for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
|
||||
{
|
||||
if (*i == ev)
|
||||
if (*i == id)
|
||||
{
|
||||
m_destroyEvents.erase (i);
|
||||
break;
|
||||
@@ -252,12 +258,18 @@ DefaultSimulatorImpl::Remove (const EventId &ev)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (IsExpired (ev))
|
||||
if (IsExpired (id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_events->Remove (ev);
|
||||
Cancel (ev);
|
||||
Scheduler::Event event;
|
||||
event.impl = id.PeekEventImpl ();
|
||||
event.key.m_ts = id.GetTs ();
|
||||
event.key.m_uid = id.GetUid ();
|
||||
m_events->Remove (event);
|
||||
event.impl->Cancel ();
|
||||
// whenever we remove an event from the event list, we have to unref it.
|
||||
event.impl->Unref ();
|
||||
|
||||
--m_unscheduledEvents;
|
||||
}
|
||||
@@ -308,6 +320,6 @@ DefaultSimulatorImpl::GetMaximumSimulationTime (void) const
|
||||
return TimeStep (0x7fffffffffffffffLL);
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
|
||||
@@ -23,20 +23,9 @@
|
||||
#include "heap-scheduler.h"
|
||||
#include "event-impl.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include <string>
|
||||
#define noTRACE_HEAP 1
|
||||
|
||||
#ifdef TRACE_HEAP
|
||||
#include <iostream>
|
||||
# define TRACE(x) \
|
||||
std::cout << "HEAP TRACE " << x << std::endl;
|
||||
#else /* TRACE_HEAP */
|
||||
# define TRACE(format,...)
|
||||
#endif /* TRACE_HEAP */
|
||||
|
||||
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("HeapScheduler");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -103,7 +92,7 @@ void
|
||||
HeapScheduler::Exch (uint32_t a, uint32_t b)
|
||||
{
|
||||
NS_ASSERT (b < m_heap.size () && a < m_heap.size ());
|
||||
TRACE ("Exch " << a << ", " << b);
|
||||
NS_LOG_DEBUG ("Exch " << a << ", " << b);
|
||||
Event tmp (m_heap[a]);
|
||||
m_heap[a] = m_heap[b];
|
||||
m_heap[b] = tmp;
|
||||
@@ -177,49 +166,42 @@ HeapScheduler::TopDown (uint32_t start)
|
||||
void
|
||||
HeapScheduler::Insert (const Event &ev)
|
||||
{
|
||||
// acquire single ref
|
||||
ev.impl->Ref ();
|
||||
m_heap.push_back (ev);
|
||||
BottomUp ();
|
||||
}
|
||||
|
||||
EventId
|
||||
Scheduler::Event
|
||||
HeapScheduler::PeekNext (void) const
|
||||
{
|
||||
Event next = m_heap[Root ()];
|
||||
return EventId (next.impl, next.key.m_ts, next.key.m_uid);
|
||||
return m_heap[Root ()];
|
||||
}
|
||||
EventId
|
||||
Scheduler::Event
|
||||
HeapScheduler::RemoveNext (void)
|
||||
{
|
||||
Event next = m_heap[Root ()];
|
||||
Exch (Root (), Last ());
|
||||
m_heap.pop_back ();
|
||||
TopDown (Root ());
|
||||
return EventId (Ptr<EventImpl> (next.impl, false), next.key.m_ts, next.key.m_uid);
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
HeapScheduler::Remove (const EventId &id)
|
||||
void
|
||||
HeapScheduler::Remove (const Event &ev)
|
||||
{
|
||||
uint32_t uid = id.GetUid ();
|
||||
uint32_t uid = ev.key.m_uid;
|
||||
for (uint32_t i = 1; i < m_heap.size (); i++)
|
||||
{
|
||||
if (uid == m_heap[i].key.m_uid)
|
||||
{
|
||||
NS_ASSERT (m_heap[i].impl == id.PeekEventImpl ());
|
||||
// release single ref
|
||||
m_heap[i].impl->Unref ();
|
||||
NS_ASSERT (m_heap[i].impl == ev.impl);
|
||||
Exch (i, Last ());
|
||||
m_heap.pop_back ();
|
||||
TopDown (i);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_ASSERT (false);
|
||||
// quiet compiler
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class EventHolder;
|
||||
|
||||
/**
|
||||
* \ingroup scheduler
|
||||
* \brief a binary heap event scheduler
|
||||
@@ -54,9 +52,9 @@ public:
|
||||
|
||||
virtual void Insert (const Event &ev);
|
||||
virtual bool IsEmpty (void) const;
|
||||
virtual EventId PeekNext (void) const;
|
||||
virtual EventId RemoveNext (void);
|
||||
virtual bool Remove (const EventId &ev);
|
||||
virtual Event PeekNext (void) const;
|
||||
virtual Event RemoveNext (void);
|
||||
virtual void Remove (const Event &ev);
|
||||
|
||||
private:
|
||||
typedef std::vector<Event> BinaryHeap;
|
||||
|
||||
@@ -35,8 +35,6 @@ ListScheduler::~ListScheduler ()
|
||||
void
|
||||
ListScheduler::Insert (const Event &ev)
|
||||
{
|
||||
// acquire refcount on EventImpl
|
||||
ev.impl->Ref ();
|
||||
for (EventsI i = m_events.begin (); i != m_events.end (); i++)
|
||||
{
|
||||
if (ev.key < i->key)
|
||||
@@ -52,37 +50,33 @@ ListScheduler::IsEmpty (void) const
|
||||
{
|
||||
return m_events.empty ();
|
||||
}
|
||||
EventId
|
||||
Scheduler::Event
|
||||
ListScheduler::PeekNext (void) const
|
||||
{
|
||||
Event next = m_events.front ();
|
||||
return EventId (next.impl, next.key.m_ts, next.key.m_uid);
|
||||
return m_events.front ();
|
||||
}
|
||||
|
||||
EventId
|
||||
Scheduler::Event
|
||||
ListScheduler::RemoveNext (void)
|
||||
{
|
||||
Event next = m_events.front ();
|
||||
m_events.pop_front ();
|
||||
return EventId (Ptr<EventImpl> (next.impl,false), next.key.m_ts, next.key.m_uid);
|
||||
return next;
|
||||
}
|
||||
|
||||
bool
|
||||
ListScheduler::Remove (const EventId &id)
|
||||
void
|
||||
ListScheduler::Remove (const Event &ev)
|
||||
{
|
||||
for (EventsI i = m_events.begin (); i != m_events.end (); i++)
|
||||
{
|
||||
if (i->key.m_uid == id.GetUid ())
|
||||
if (i->key.m_uid == ev.key.m_uid)
|
||||
{
|
||||
NS_ASSERT (id.PeekEventImpl () == i->impl);
|
||||
// release single acquire ref.
|
||||
i->impl->Unref ();
|
||||
NS_ASSERT (ev.impl == i->impl);
|
||||
m_events.erase (i);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_ASSERT (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define LIST_SCHEDULER_H
|
||||
|
||||
#include "scheduler.h"
|
||||
#include "event-id.h"
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <stdint.h>
|
||||
@@ -35,7 +34,7 @@ class EventImpl;
|
||||
* \ingroup scheduler
|
||||
* \brief a std::list event scheduler
|
||||
*
|
||||
* This class implements the an event scheduler using an std::list
|
||||
* This class implements an event scheduler using an std::list
|
||||
* data structure, that is, a double linked-list.
|
||||
*/
|
||||
class ListScheduler : public Scheduler
|
||||
@@ -46,9 +45,9 @@ class ListScheduler : public Scheduler
|
||||
|
||||
virtual void Insert (const Event &ev);
|
||||
virtual bool IsEmpty (void) const;
|
||||
virtual EventId PeekNext (void) const;
|
||||
virtual EventId RemoveNext (void);
|
||||
virtual bool Remove (const EventId &ev);
|
||||
virtual Event PeekNext (void) const;
|
||||
virtual Event RemoveNext (void);
|
||||
virtual void Remove (const Event &ev);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -22,18 +22,10 @@
|
||||
#include "map-scheduler.h"
|
||||
#include "event-impl.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/log.h"
|
||||
#include <string>
|
||||
|
||||
#define noTRACE_MAP 1
|
||||
|
||||
#ifdef TRACE_MAP
|
||||
#include <iostream>
|
||||
# define TRACE(x) \
|
||||
std::cout << "MAP TRACE " << x << std::endl;
|
||||
#else /* TRACE_MAP */
|
||||
# define TRACE(format,...)
|
||||
#endif /* TRACE_MAP */
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("MapScheduler");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -45,8 +37,7 @@ MapScheduler::~MapScheduler ()
|
||||
void
|
||||
MapScheduler::Insert (const Event &ev)
|
||||
{
|
||||
// acquire a single ref
|
||||
ev.impl->Ref ();
|
||||
NS_LOG_FUNCTION (this << ev.impl << ev.key.m_ts << ev.key.m_uid);
|
||||
std::pair<EventMapI,bool> result;
|
||||
result = m_list.insert (std::make_pair (ev.key, ev.impl));
|
||||
NS_ASSERT (result.second);
|
||||
@@ -58,35 +49,41 @@ MapScheduler::IsEmpty (void) const
|
||||
return m_list.empty ();
|
||||
}
|
||||
|
||||
EventId
|
||||
Scheduler::Event
|
||||
MapScheduler::PeekNext (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
EventMapCI i = m_list.begin ();
|
||||
NS_ASSERT (i != m_list.end ());
|
||||
|
||||
return EventId (i->second, i->first.m_ts, i->first.m_uid);
|
||||
Event ev;
|
||||
ev.impl = i->second;
|
||||
ev.key = i->first;
|
||||
NS_LOG_DEBUG (this << ev.impl << ev.key.m_ts << ev.key.m_uid);
|
||||
return ev;
|
||||
}
|
||||
EventId
|
||||
Scheduler::Event
|
||||
MapScheduler::RemoveNext (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
EventMapI i = m_list.begin ();
|
||||
NS_ASSERT (i != m_list.end ());
|
||||
std::pair<Scheduler::EventKey, EventImpl*> next = *i;
|
||||
Event ev;
|
||||
ev.impl = i->second;
|
||||
ev.key = i->first;
|
||||
m_list.erase (i);
|
||||
return EventId (Ptr<EventImpl> (next.second, false), next.first.m_ts, next.first.m_uid);
|
||||
NS_LOG_DEBUG (this << ev.impl << ev.key.m_ts << ev.key.m_uid);
|
||||
return ev;
|
||||
}
|
||||
|
||||
bool
|
||||
MapScheduler::Remove (const EventId &id)
|
||||
void
|
||||
MapScheduler::Remove (const Event &ev)
|
||||
{
|
||||
Scheduler::EventKey key;
|
||||
key.m_ts = id.GetTs ();
|
||||
key.m_uid = id.GetUid ();
|
||||
EventMapI i = m_list.find (key);
|
||||
NS_ASSERT (i->second == id.PeekEventImpl ());
|
||||
// release single ref.
|
||||
i->second->Unref ();
|
||||
NS_LOG_FUNCTION (this << ev.impl << ev.key.m_ts << ev.key.m_uid);
|
||||
EventMapI i = m_list.find (ev.key);
|
||||
NS_ASSERT (i->second == ev.impl);
|
||||
m_list.erase (i);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class EventImpl;
|
||||
|
||||
/**
|
||||
* \ingroup scheduler
|
||||
* \brief a std::map event scheduler
|
||||
@@ -45,9 +43,9 @@ public:
|
||||
|
||||
virtual void Insert (const Event &ev);
|
||||
virtual bool IsEmpty (void) const;
|
||||
virtual EventId PeekNext (void) const;
|
||||
virtual EventId RemoveNext (void);
|
||||
virtual bool Remove (const EventId &ev);
|
||||
virtual Event PeekNext (void) const;
|
||||
virtual Event RemoveNext (void);
|
||||
virtual void Remove (const Event &ev);
|
||||
private:
|
||||
|
||||
typedef std::map<Scheduler::EventKey, EventImpl*> EventMap;
|
||||
|
||||
@@ -103,7 +103,8 @@ RealtimeSimulatorImpl::~RealtimeSimulatorImpl ()
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
while (m_events->IsEmpty () == false)
|
||||
{
|
||||
EventId next = m_events->RemoveNext ();
|
||||
Scheduler::Event next = m_events->RemoveNext ();
|
||||
next.impl->Unref ();
|
||||
}
|
||||
m_events = 0;
|
||||
m_synchronizer = 0;
|
||||
@@ -148,7 +149,7 @@ RealtimeSimulatorImpl::SetScheduler (Ptr<Scheduler> scheduler)
|
||||
{
|
||||
while (m_events->IsEmpty () == false)
|
||||
{
|
||||
EventId next = m_events->RemoveNext ();
|
||||
Scheduler::Event next = m_events->RemoveNext ();
|
||||
scheduler->Insert (next);
|
||||
}
|
||||
}
|
||||
@@ -315,7 +316,7 @@ RealtimeSimulatorImpl::ProcessOneEvent (void)
|
||||
// is the one we think it is. What we can be sure of is that it is time to execute
|
||||
// whatever event is at the head of this list if the list is in time order.
|
||||
//
|
||||
EventId next;
|
||||
Scheduler::Event next;
|
||||
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
@@ -336,18 +337,18 @@ RealtimeSimulatorImpl::ProcessOneEvent (void)
|
||||
// for. We can only assume that only that it must be due and cannot cause time
|
||||
// to move backward.
|
||||
//
|
||||
NS_ASSERT_MSG (next.GetTs () >= m_currentTs,
|
||||
NS_ASSERT_MSG (next.key.m_ts >= m_currentTs,
|
||||
"RealtimeSimulatorImpl::ProcessOneEvent(): "
|
||||
"next.GetTs() earlier than m_currentTs (list order error)");
|
||||
NS_LOG_LOGIC ("handle " << next.GetTs ());
|
||||
NS_LOG_LOGIC ("handle " << next.key.m_ts);
|
||||
|
||||
//
|
||||
// Update the current simulation time to be the timestamp of the event we're
|
||||
// executing. From the rest of the simulation's point of view, simulation time
|
||||
// is frozen until the next event is executed.
|
||||
//
|
||||
m_currentTs = next.GetTs ();
|
||||
m_currentUid = next.GetUid ();
|
||||
m_currentTs = next.key.m_ts;
|
||||
m_currentUid = next.key.m_uid;
|
||||
|
||||
//
|
||||
// We're about to run the event and we've done our best to synchronize this
|
||||
@@ -385,10 +386,11 @@ RealtimeSimulatorImpl::ProcessOneEvent (void)
|
||||
// event list so we can execute it outside a critical section without fear of someone
|
||||
// changing things out from under us.
|
||||
|
||||
EventImpl *event = next.PeekEventImpl ();
|
||||
EventImpl *event = next.impl;
|
||||
m_synchronizer->EventStart ();
|
||||
event->Invoke ();
|
||||
m_synchronizer->EventEnd ();
|
||||
event->Unref ();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -413,9 +415,8 @@ RealtimeSimulatorImpl::NextTs (void) const
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NS_ASSERT_MSG (m_events->IsEmpty () == false,
|
||||
"RealtimeSimulatorImpl::NextTs(): event queue is empty");
|
||||
EventId id = m_events->PeekNext ();
|
||||
|
||||
return id.GetTs ();
|
||||
Scheduler::Event ev = m_events->PeekNext ();
|
||||
return ev.key.m_ts;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -523,7 +524,6 @@ RealtimeSimulatorImpl::RunOneEvent (void)
|
||||
NS_ASSERT_MSG (m_running == false,
|
||||
"RealtimeSimulatorImpl::RunOneEvent(): An internal simulator event loop is running");
|
||||
|
||||
EventId next;
|
||||
EventImpl *event = 0;
|
||||
|
||||
//
|
||||
@@ -533,18 +533,18 @@ RealtimeSimulatorImpl::RunOneEvent (void)
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
|
||||
next = m_events->RemoveNext ();
|
||||
Scheduler::Event next = m_events->RemoveNext ();
|
||||
|
||||
NS_ASSERT (next.GetTs () >= m_currentTs);
|
||||
NS_ASSERT (next.key.m_ts >= m_currentTs);
|
||||
--m_unscheduledEvents;
|
||||
|
||||
NS_LOG_LOGIC ("handle " << next.GetTs ());
|
||||
m_currentTs = next.GetTs ();
|
||||
m_currentUid = next.GetUid ();
|
||||
event = next.PeekEventImpl ();
|
||||
NS_LOG_LOGIC ("handle " << next.key.m_ts);
|
||||
m_currentTs = next.key.m_ts;
|
||||
m_currentUid = next.key.m_ts;
|
||||
event = next.impl;
|
||||
}
|
||||
|
||||
event->Invoke ();
|
||||
event->Unref ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -588,37 +588,12 @@ RealtimeSimulatorImpl::Stop (Time const &time)
|
||||
//
|
||||
// Schedule an event for a _relative_ time in the future.
|
||||
//
|
||||
// A little side-note on events and multthreading:
|
||||
//
|
||||
// This is a little tricky. We get a Ptr<EventImpl> passed down to us in some
|
||||
// thread context. This Ptr<EventImpl> is not yet shared in any way. It is
|
||||
// possible however that the calling context is not the context of the main
|
||||
// scheduler thread (e.g. it is in the context of a separate device thread).
|
||||
// It would be bad (TM) if we naively wrapped the EventImpl up in an EventId
|
||||
// that would be accessible from multiple threads without considering thread
|
||||
// safety.
|
||||
//
|
||||
// It's clear that we cannot have a situation where the EventImpl is "owned" by
|
||||
// multiple threads. The calling thread is free to hold the EventId as long as
|
||||
// it wants and manage the reference counts to the underlying EventImpl all it
|
||||
// wants. The scheduler is free to do the same; and will eventually release
|
||||
// the reference in the context of thread running ProcessOneEvent(). It is
|
||||
// "a bad thing" (TM) if these two threads decide to release the underlying
|
||||
// EventImpl "at the same time" since the result is sure to be multiple frees,
|
||||
// memory leaks or bus errors.
|
||||
//
|
||||
// The answer is to make the reference counting of the EventImpl thread safe;
|
||||
// which we do. We don't want to force the event implementation to carry around
|
||||
// a mutex, so we "lend" it one using a RealtimeEventLock object (m_eventLock)
|
||||
// in the constructor of the event and take it back in the destructor. See the
|
||||
// event code for details.
|
||||
//
|
||||
EventId
|
||||
RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
|
||||
RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &impl)
|
||||
{
|
||||
NS_LOG_FUNCTION (time << event);
|
||||
NS_LOG_FUNCTION (time << impl);
|
||||
|
||||
EventId id;
|
||||
Scheduler::Event ev;
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
//
|
||||
@@ -630,33 +605,36 @@ RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr<EventImpl> &event)
|
||||
Time tAbsolute = Simulator::Now () + time;
|
||||
NS_ASSERT_MSG (tAbsolute.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative time");
|
||||
NS_ASSERT_MSG (tAbsolute >= TimeStep (m_currentTs), "RealtimeSimulatorImpl::Schedule(): time < m_currentTs");
|
||||
uint64_t ts = (uint64_t) tAbsolute.GetTimeStep ();
|
||||
id = EventId (event, ts, m_uid);
|
||||
ev.impl = GetPointer (impl);
|
||||
ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
|
||||
ev.key.m_uid = m_uid;
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
m_events->Insert (id);
|
||||
m_events->Insert (ev);
|
||||
m_synchronizer->Signal ();
|
||||
}
|
||||
|
||||
return id;
|
||||
return EventId (impl, ev.key.m_ts, ev.key.m_uid);
|
||||
}
|
||||
|
||||
EventId
|
||||
RealtimeSimulatorImpl::ScheduleNow (const Ptr<EventImpl> &event)
|
||||
RealtimeSimulatorImpl::ScheduleNow (const Ptr<EventImpl> &impl)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
EventId id;
|
||||
Scheduler::Event ev;
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
|
||||
id = EventId (event, m_currentTs, m_uid);
|
||||
ev.impl = GetPointer (impl);
|
||||
ev.key.m_ts = m_currentTs;
|
||||
ev.key.m_uid = m_uid;
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
m_events->Insert (id);
|
||||
m_events->Insert (ev);
|
||||
m_synchronizer->Signal ();
|
||||
}
|
||||
|
||||
return id;
|
||||
return EventId (impl, ev.key.m_ts, ev.key.m_uid);
|
||||
}
|
||||
|
||||
Time
|
||||
@@ -669,31 +647,33 @@ RealtimeSimulatorImpl::Now (void) const
|
||||
// Schedule an event for a _relative_ time in the future.
|
||||
//
|
||||
EventId
|
||||
RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, const Ptr<EventImpl> &event)
|
||||
RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, const Ptr<EventImpl> &impl)
|
||||
{
|
||||
NS_LOG_FUNCTION (time << event);
|
||||
NS_LOG_FUNCTION (time << impl);
|
||||
|
||||
EventId id;
|
||||
Scheduler::Event ev;
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
|
||||
uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
|
||||
NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs");
|
||||
id = EventId (event, ts, m_uid);
|
||||
ev.impl = GetPointer (impl);
|
||||
ev.key.m_ts = ts;
|
||||
ev.key.m_uid = m_uid;
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
m_events->Insert (id);
|
||||
m_events->Insert (ev);
|
||||
m_synchronizer->Signal ();
|
||||
}
|
||||
|
||||
return id;
|
||||
return EventId (impl, ev.key.m_ts, ev.key.m_uid);
|
||||
}
|
||||
|
||||
EventId
|
||||
RealtimeSimulatorImpl::ScheduleRealtimeNow (const Ptr<EventImpl> &event)
|
||||
RealtimeSimulatorImpl::ScheduleRealtimeNow (const Ptr<EventImpl> &impl)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
EventId id;
|
||||
Scheduler::Event ev;
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
|
||||
@@ -703,14 +683,16 @@ RealtimeSimulatorImpl::ScheduleRealtimeNow (const Ptr<EventImpl> &event)
|
||||
//
|
||||
uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
|
||||
NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealrimeNow(): schedule for time < m_currentTs");
|
||||
id = EventId (event, ts, m_uid);
|
||||
ev.impl = GetPointer (impl);
|
||||
ev.key.m_ts = ts;
|
||||
ev.key.m_uid = m_uid;
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
m_events->Insert (id);
|
||||
m_events->Insert (ev);
|
||||
m_synchronizer->Signal ();
|
||||
}
|
||||
|
||||
return id;
|
||||
return EventId (impl, ev.key.m_ts, ev.key.m_uid);
|
||||
}
|
||||
|
||||
Time
|
||||
@@ -720,11 +702,11 @@ RealtimeSimulatorImpl::RealtimeNow (void) const
|
||||
}
|
||||
|
||||
EventId
|
||||
RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &event)
|
||||
RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &impl)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
EventId id;
|
||||
|
||||
EventId id;
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
|
||||
@@ -733,7 +715,7 @@ RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &event)
|
||||
// overridden by the uid of 2 which identifies this as an event to be
|
||||
// executed at Simulator::Destroy time.
|
||||
//
|
||||
id = EventId (event, m_currentTs, 2);
|
||||
id = EventId (impl, m_currentTs, 2);
|
||||
m_destroyEvents.push_back (id);
|
||||
m_uid++;
|
||||
}
|
||||
@@ -757,16 +739,16 @@ RealtimeSimulatorImpl::GetDelayLeft (const EventId &id) const
|
||||
}
|
||||
|
||||
void
|
||||
RealtimeSimulatorImpl::Remove (const EventId &ev)
|
||||
RealtimeSimulatorImpl::Remove (const EventId &id)
|
||||
{
|
||||
if (ev.GetUid () == 2)
|
||||
if (id.GetUid () == 2)
|
||||
{
|
||||
// destroy events.
|
||||
for (DestroyEvents::iterator i = m_destroyEvents.begin ();
|
||||
i != m_destroyEvents.end ();
|
||||
i++)
|
||||
{
|
||||
if (*i == ev)
|
||||
if (*i == id)
|
||||
{
|
||||
m_destroyEvents.erase (i);
|
||||
break;
|
||||
@@ -774,7 +756,7 @@ RealtimeSimulatorImpl::Remove (const EventId &ev)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (IsExpired (ev))
|
||||
if (IsExpired (id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -782,11 +764,15 @@ RealtimeSimulatorImpl::Remove (const EventId &ev)
|
||||
{
|
||||
CriticalSection cs (m_mutex);
|
||||
|
||||
m_events->Remove (ev);
|
||||
Scheduler::Event event;
|
||||
event.impl = id.PeekEventImpl ();
|
||||
event.key.m_ts = id.GetTs ();
|
||||
event.key.m_uid = id.GetUid ();
|
||||
|
||||
m_events->Remove (event);
|
||||
--m_unscheduledEvents;
|
||||
|
||||
Cancel (ev);
|
||||
|
||||
event.impl->Cancel ();
|
||||
event.impl->Unref ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,12 @@
|
||||
#define SCHEDULER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "event-id.h"
|
||||
#include "ns3/object.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class EventImpl;
|
||||
|
||||
/**
|
||||
* \ingroup simulator
|
||||
* \defgroup scheduler Scheduler
|
||||
@@ -38,13 +39,16 @@ namespace ns3 {
|
||||
* This base class specifies the interface used to maintain the
|
||||
* event list. If you want to provide a new event list scheduler,
|
||||
* you need to create a subclass of this base class and implement
|
||||
* all the pure virtual methods defined here. Namely:
|
||||
* - ns3::Scheduler::Insert
|
||||
* - ns3::Scheduler::IsEmpty
|
||||
* - ns3::Scheduler::PeekNext
|
||||
* - ns3::Scheduler::RemoveNext
|
||||
* - ns3::Scheduler::Remove
|
||||
* all the pure virtual methods defined here.
|
||||
*
|
||||
* The only tricky aspect of this API is the memory management of
|
||||
* the EventImpl pointer which is a member of the Event data structure.
|
||||
* The lifetime of this pointer is assumed to always be longer than
|
||||
* the lifetime of the Scheduler class which means that the caller
|
||||
* is responsible for ensuring that this invariant holds through
|
||||
* calling EventImpl::Ref and EventImpl::Unref at the right time.
|
||||
* Typically, ::Ref is called before Insert and ::Unref is called
|
||||
* after a call to one of the Remove methods.
|
||||
*/
|
||||
class Scheduler : public Object
|
||||
{
|
||||
@@ -76,20 +80,18 @@ class Scheduler : public Object
|
||||
*
|
||||
* This method cannot be invoked if the list is empty.
|
||||
*/
|
||||
virtual EventId PeekNext (void) const = 0;
|
||||
virtual Event PeekNext (void) const = 0;
|
||||
/**
|
||||
* This method cannot be invoked if the list is empty.
|
||||
* Remove the next earliest event from the event list.
|
||||
*/
|
||||
virtual EventId RemoveNext (void) = 0;
|
||||
virtual Event RemoveNext (void) = 0;
|
||||
/**
|
||||
* \param id the id of the event to remove
|
||||
* \returns true if the id was found and removed
|
||||
* successfully, false otherwise.
|
||||
*
|
||||
* This methods cannot be invoked if the list is empty.
|
||||
*/
|
||||
virtual bool Remove (const EventId &id) = 0;
|
||||
virtual void Remove (const Event &ev) = 0;
|
||||
};
|
||||
|
||||
/* Note the invariants which this function must provide:
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "scheduler.h"
|
||||
#include "event-impl.h"
|
||||
#include "event-id.h"
|
||||
#include "nstime.h"
|
||||
|
||||
#include "ns3/ptr.h"
|
||||
|
||||
Reference in New Issue
Block a user