diff --git a/src/simulator/default-simulator-impl.cc b/src/simulator/default-simulator-impl.cc index b670b019e..4516fbb4a 100644 --- a/src/simulator/default-simulator-impl.cc +++ b/src/simulator/default-simulator-impl.cc @@ -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) { 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 &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 &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 diff --git a/src/simulator/heap-scheduler.cc b/src/simulator/heap-scheduler.cc index e52b36a8a..6795f64fd 100644 --- a/src/simulator/heap-scheduler.cc +++ b/src/simulator/heap-scheduler.cc @@ -23,20 +23,9 @@ #include "heap-scheduler.h" #include "event-impl.h" #include "ns3/assert.h" +#include "ns3/log.h" -#include -#define noTRACE_HEAP 1 - -#ifdef TRACE_HEAP -#include -# 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 (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 diff --git a/src/simulator/heap-scheduler.h b/src/simulator/heap-scheduler.h index 3ad608e75..ca4a38be5 100644 --- a/src/simulator/heap-scheduler.h +++ b/src/simulator/heap-scheduler.h @@ -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 BinaryHeap; diff --git a/src/simulator/list-scheduler.cc b/src/simulator/list-scheduler.cc index 8e367e332..822cfe4a8 100644 --- a/src/simulator/list-scheduler.cc +++ b/src/simulator/list-scheduler.cc @@ -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 (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 diff --git a/src/simulator/list-scheduler.h b/src/simulator/list-scheduler.h index 824c197e9..064ae1d17 100644 --- a/src/simulator/list-scheduler.h +++ b/src/simulator/list-scheduler.h @@ -22,7 +22,6 @@ #define LIST_SCHEDULER_H #include "scheduler.h" -#include "event-id.h" #include #include #include @@ -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: diff --git a/src/simulator/map-scheduler.cc b/src/simulator/map-scheduler.cc index 10a8ea5a2..ce861b8d0 100644 --- a/src/simulator/map-scheduler.cc +++ b/src/simulator/map-scheduler.cc @@ -22,18 +22,10 @@ #include "map-scheduler.h" #include "event-impl.h" #include "ns3/assert.h" +#include "ns3/log.h" #include -#define noTRACE_MAP 1 - -#ifdef TRACE_MAP -#include -# 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 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 next = *i; + Event ev; + ev.impl = i->second; + ev.key = i->first; m_list.erase (i); - return EventId (Ptr (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 diff --git a/src/simulator/map-scheduler.h b/src/simulator/map-scheduler.h index ce99f895d..d82eb7fec 100644 --- a/src/simulator/map-scheduler.h +++ b/src/simulator/map-scheduler.h @@ -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 EventMap; diff --git a/src/simulator/realtime-simulator-impl.cc b/src/simulator/realtime-simulator-impl.cc index 3fd50dcb7..dc311416d 100644 --- a/src/simulator/realtime-simulator-impl.cc +++ b/src/simulator/realtime-simulator-impl.cc @@ -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) { 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 passed down to us in some -// thread context. This Ptr 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 &event) +RealtimeSimulatorImpl::Schedule (Time const &time, const Ptr &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 &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 &event) +RealtimeSimulatorImpl::ScheduleNow (const Ptr &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 &event) +RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, const Ptr &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 &event) +RealtimeSimulatorImpl::ScheduleRealtimeNow (const Ptr &impl) { NS_LOG_FUNCTION_NOARGS (); - EventId id; + Scheduler::Event ev; { CriticalSection cs (m_mutex); @@ -703,14 +683,16 @@ RealtimeSimulatorImpl::ScheduleRealtimeNow (const Ptr &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 &event) +RealtimeSimulatorImpl::ScheduleDestroy (const Ptr &impl) { NS_LOG_FUNCTION_NOARGS (); - EventId id; + EventId id; { CriticalSection cs (m_mutex); @@ -733,7 +715,7 @@ RealtimeSimulatorImpl::ScheduleDestroy (const Ptr &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 (); } } diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h index d45425f33..5b26392ad 100644 --- a/src/simulator/scheduler.h +++ b/src/simulator/scheduler.h @@ -22,11 +22,12 @@ #define SCHEDULER_H #include -#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: diff --git a/src/simulator/simulator-impl.h b/src/simulator/simulator-impl.h index 8123ad96f..177133ea6 100644 --- a/src/simulator/simulator-impl.h +++ b/src/simulator/simulator-impl.h @@ -23,6 +23,7 @@ #include "scheduler.h" #include "event-impl.h" +#include "event-id.h" #include "nstime.h" #include "ns3/ptr.h"