--- a/samples/main-test-sync.cc Fri Oct 10 16:22:13 2008 -0700
+++ b/samples/main-test-sync.cc Fri Oct 10 16:43:43 2008 -0700
@@ -1,9 +1,9 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
#include "ns3/simulator.h"
+#include "ns3/realtime-simulator.h"
#include "ns3/nstime.h"
#include "ns3/log.h"
-#include "ns3/wall-clock-synchronizer.h"
#include "ns3/system-thread.h"
#include "ns3/string.h"
#include "ns3/config.h"
@@ -48,6 +48,8 @@
FakeNetDevice ();
void Doit1 (void);
void Doit2 (void);
+ void Doit3 (void);
+ void Doit4 (void);
};
FakeNetDevice::FakeNetDevice ()
@@ -56,6 +58,21 @@
}
void
+FakeNetDevice::Doit1 (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ sleep (1);
+ for (uint32_t i = 0.001; i < 10000; ++i)
+ {
+ //
+ // Exercise the relative now path
+ //
+ Simulator::ScheduleNow (&inserted_function);
+ usleep (1000);
+ }
+}
+
+ void
FakeNetDevice::Doit2 (void)
{
NS_LOG_FUNCTION_NOARGS ();
@@ -71,16 +88,31 @@
}
void
-FakeNetDevice::Doit1 (void)
+FakeNetDevice::Doit3 (void)
{
NS_LOG_FUNCTION_NOARGS ();
sleep (1);
for (uint32_t i = 0.001; i < 10000; ++i)
{
- //
- // Exercise the ScheduleNow path
+ //
+ // Exercise the realtime relative now path
//
- Simulator::ScheduleNow (&inserted_function);
+ RealtimeSimulatorExtension::ScheduleRealNow (&inserted_function);
+ usleep (1000);
+ }
+}
+
+ void
+FakeNetDevice::Doit4 (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ sleep (1);
+ for (uint32_t i = 0.001; i < 10000; ++i)
+ {
+ //
+ // Exercise the realtime relative schedule path
+ //
+ RealtimeSimulatorExtension::ScheduleReal (Seconds (0), &inserted_function);
usleep (1000);
}
}
@@ -109,14 +141,25 @@
Ptr<SystemThread> st1 = Create<SystemThread> (
MakeCallback (&FakeNetDevice::Doit1, &fnd));
st1->Start ();
+
Ptr<SystemThread> st2 = Create<SystemThread> (
MakeCallback (&FakeNetDevice::Doit2, &fnd));
st2->Start ();
+ Ptr<SystemThread> st3 = Create<SystemThread> (
+ MakeCallback (&FakeNetDevice::Doit3, &fnd));
+ st3->Start ();
+
+ Ptr<SystemThread> st4 = Create<SystemThread> (
+ MakeCallback (&FakeNetDevice::Doit4, &fnd));
+ st4->Start ();
+
Simulator::Stop (Seconds (15.0));
Simulator::Run ();
st1->Join ();
st2->Join ();
+ st3->Join ();
+ st4->Join ();
Simulator::Destroy ();
}
--- a/src/simulator/realtime-simulator-impl.cc Fri Oct 10 16:22:13 2008 -0700
+++ b/src/simulator/realtime-simulator-impl.cc Fri Oct 10 16:43:43 2008 -0700
@@ -548,35 +548,36 @@
//
// 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)
{
NS_LOG_FUNCTION (time << event);
- //
- // 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 id;
{
CriticalSection cs (m_mutex);
@@ -631,28 +632,49 @@
RealtimeSimulatorImpl::ScheduleReal (Time const &time, const Ptr<EventImpl> &event)
{
NS_LOG_FUNCTION (time << event);
- NS_ASSERT (false);
+
EventId id;
+ {
+ CriticalSection cs (m_mutex);
+
+ uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep ();
+ NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleReal(): schedule for time < m_currentTs");
+ id = EventId (event, ts, m_uid);
+ m_uid++;
+ ++m_unscheduledEvents;
+ m_events->Insert (id);
+ m_synchronizer->Signal ();
+ }
+
return id;
}
EventId
RealtimeSimulatorImpl::ScheduleRealNow (const Ptr<EventImpl> &event)
{
- NS_LOG_FUNCTION (event);
- NS_ASSERT (false);
+ NS_LOG_FUNCTION_NOARGS ();
EventId id;
+ {
+ CriticalSection cs (m_mutex);
+
+ uint64_t ts = m_synchronizer->GetCurrentRealtime ();
+ NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealNow(): schedule for time < m_currentTs");
+ id = EventId (event, ts, m_uid);
+ m_uid++;
+ ++m_unscheduledEvents;
+ m_events->Insert (id);
+ m_synchronizer->Signal ();
+ }
+
return id;
}
Time
RealtimeSimulatorImpl::RealNow (void) const
{
- NS_ASSERT (false);
- return TimeStep (m_currentTs);
+ return TimeStep (m_synchronizer->GetCurrentRealtime ());
}
-
EventId
RealtimeSimulatorImpl::ScheduleDestroy (const Ptr<EventImpl> &event)
{