it helps to remember to add function implementations
authorCraig Dowell <craigdo@ee.washington.edu>
Fri, 10 Oct 2008 16:43:43 -0700
changeset 3799 ceea04d07e60
parent 3798 898d8a14b88f
child 3800 804beebf1ba5
it helps to remember to add function implementations
samples/main-test-sync.cc
src/simulator/realtime-simulator-impl.cc
--- 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)
 {