Get emu working again: Add Dix/Llc option, add and use contextual realtime schedule ops, don't refcount realtime simulator impl
authorCraig Dowell <craigdo@ee.washington.edu>
Mon, 30 Nov 2009 18:22:10 -0800
changeset 5822 c16bcd1c6647
parent 5821 2fe328444a2b
child 5823 a61b59819f10
Get emu working again: Add Dix/Llc option, add and use contextual realtime schedule ops, don't refcount realtime simulator impl
bindings/python/apidefs/gcc-ILP32/ns3_module_emu.py
bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py
bindings/python/apidefs/gcc-LP64/ns3_module_emu.py
bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py
examples/emulation/emu-udp-echo.cc
src/devices/emu/emu-net-device.cc
src/devices/emu/emu-net-device.h
src/simulator/realtime-simulator-impl.cc
src/simulator/realtime-simulator-impl.h
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_emu.py	Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_emu.py	Mon Nov 30 18:22:10 2009 -0800
@@ -5,6 +5,8 @@
     
     ## emu-net-device.h: ns3::EmuNetDevice [class]
     module.add_class('EmuNetDevice', parent=root_module['ns3::NetDevice'])
+    ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode [enumeration]
+    module.add_enum('EncapsulationMode', ['ILLEGAL', 'DIX', 'LLC'], outer_class=root_module['ns3::EmuNetDevice'])
     
     ## Register a nested module for the namespace Config
     
@@ -115,6 +117,11 @@
                    'ns3::Ptr< ns3::Channel >', 
                    [], 
                    is_const=True, is_virtual=True)
+    ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode ns3::EmuNetDevice::GetEncapsulationMode() const [member function]
+    cls.add_method('GetEncapsulationMode', 
+                   'ns3::EmuNetDevice::EncapsulationMode', 
+                   [], 
+                   is_const=True)
     ## emu-net-device.h: uint32_t ns3::EmuNetDevice::GetIfIndex() const [member function]
     cls.add_method('GetIfIndex', 
                    'uint32_t', 
@@ -194,6 +201,10 @@
     cls.add_method('SetDataRate', 
                    'void', 
                    [param('ns3::DataRate', 'bps')])
+    ## emu-net-device.h: void ns3::EmuNetDevice::SetEncapsulationMode(ns3::EmuNetDevice::EncapsulationMode mode) [member function]
+    cls.add_method('SetEncapsulationMode', 
+                   'void', 
+                   [param('ns3::EmuNetDevice::EncapsulationMode', 'mode')])
     ## emu-net-device.h: void ns3::EmuNetDevice::SetIfIndex(uint32_t const index) [member function]
     cls.add_method('SetIfIndex', 
                    'void', 
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py	Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py	Mon Nov 30 18:22:10 2009 -0800
@@ -1486,6 +1486,14 @@
     cls.add_method('ScheduleRealtimeNow', 
                    'void', 
                    [param('ns3::EventImpl *', 'event')])
+    ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(uint32_t context, ns3::EventImpl * event) [member function]
+    cls.add_method('ScheduleRealtimeNowWithContext', 
+                   'void', 
+                   [param('uint32_t', 'context'), param('ns3::EventImpl *', 'event')])
+    ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
+    cls.add_method('ScheduleRealtimeWithContext', 
+                   'void', 
+                   [param('uint32_t', 'context'), param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')])
     ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
     cls.add_method('ScheduleWithContext', 
                    'void', 
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_emu.py	Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_emu.py	Mon Nov 30 18:22:10 2009 -0800
@@ -5,6 +5,8 @@
     
     ## emu-net-device.h: ns3::EmuNetDevice [class]
     module.add_class('EmuNetDevice', parent=root_module['ns3::NetDevice'])
+    ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode [enumeration]
+    module.add_enum('EncapsulationMode', ['ILLEGAL', 'DIX', 'LLC'], outer_class=root_module['ns3::EmuNetDevice'])
     
     ## Register a nested module for the namespace Config
     
@@ -115,6 +117,11 @@
                    'ns3::Ptr< ns3::Channel >', 
                    [], 
                    is_const=True, is_virtual=True)
+    ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode ns3::EmuNetDevice::GetEncapsulationMode() const [member function]
+    cls.add_method('GetEncapsulationMode', 
+                   'ns3::EmuNetDevice::EncapsulationMode', 
+                   [], 
+                   is_const=True)
     ## emu-net-device.h: uint32_t ns3::EmuNetDevice::GetIfIndex() const [member function]
     cls.add_method('GetIfIndex', 
                    'uint32_t', 
@@ -194,6 +201,10 @@
     cls.add_method('SetDataRate', 
                    'void', 
                    [param('ns3::DataRate', 'bps')])
+    ## emu-net-device.h: void ns3::EmuNetDevice::SetEncapsulationMode(ns3::EmuNetDevice::EncapsulationMode mode) [member function]
+    cls.add_method('SetEncapsulationMode', 
+                   'void', 
+                   [param('ns3::EmuNetDevice::EncapsulationMode', 'mode')])
     ## emu-net-device.h: void ns3::EmuNetDevice::SetIfIndex(uint32_t const index) [member function]
     cls.add_method('SetIfIndex', 
                    'void', 
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py	Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py	Mon Nov 30 18:22:10 2009 -0800
@@ -1486,6 +1486,14 @@
     cls.add_method('ScheduleRealtimeNow', 
                    'void', 
                    [param('ns3::EventImpl *', 'event')])
+    ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(uint32_t context, ns3::EventImpl * event) [member function]
+    cls.add_method('ScheduleRealtimeNowWithContext', 
+                   'void', 
+                   [param('uint32_t', 'context'), param('ns3::EventImpl *', 'event')])
+    ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
+    cls.add_method('ScheduleRealtimeWithContext', 
+                   'void', 
+                   [param('uint32_t', 'context'), param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')])
     ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
     cls.add_method('ScheduleWithContext', 
                    'void', 
--- a/examples/emulation/emu-udp-echo.cc	Mon Nov 30 14:46:02 2009 -0800
+++ b/examples/emulation/emu-udp-echo.cc	Mon Nov 30 18:22:10 2009 -0800
@@ -75,6 +75,7 @@
 main (int argc, char *argv[])
 {
   std::string deviceName ("eth1");
+  std::string encapMode ("Dix");
   uint32_t nNodes = 4;
 
   //
@@ -83,7 +84,9 @@
   //
   CommandLine cmd;
   cmd.AddValue("deviceName", "device name", deviceName);
+  cmd.AddValue("encapsulationMode", "encapsulation mode of emu device (\"Dix\" [default] or \"Llc\")", encapMode);
   cmd.AddValue("nNodes", "number of nodes to create (>= 2)", nNodes);
+
   cmd.Parse (argc, argv);
 
   GlobalValue::Bind ("SimulatorImplementationType", 
@@ -110,6 +113,8 @@
   NS_LOG_INFO ("Create channels.");
   EmuHelper emu;
   emu.SetAttribute ("DeviceName", StringValue (deviceName));
+  emu.SetAttribute ("EncapsulationMode", StringValue (encapMode));  
+
   NetDeviceContainer d = emu.Install (n);
 
   //
@@ -133,8 +138,8 @@
   // Create a UdpEchoClient application to send UDP datagrams from node zero to node one.
   //
   uint32_t packetSize = 1024;
-  uint32_t maxPacketCount = 1;
-  Time interPacketInterval = Seconds (1.);
+  uint32_t maxPacketCount = 20;
+  Time interPacketInterval = Seconds (0.1);
   UdpEchoClientHelper client (i.GetAddress (1), 9);
   client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
   client.SetAttribute ("Interval", TimeValue (interPacketInterval));
--- a/src/devices/emu/emu-net-device.cc	Mon Nov 30 14:46:02 2009 -0800
+++ b/src/devices/emu/emu-net-device.cc	Mon Nov 30 18:22:10 2009 -0800
@@ -32,8 +32,8 @@
 #include "ns3/trace-source-accessor.h"
 #include "ns3/channel.h"
 #include "ns3/system-thread.h"
-#include "ns3/realtime-simulator-impl.h"
 #include "ns3/mac48-address.h"
+#include "ns3/enum.h"
 
 #include <sys/wait.h>
 #include <sys/stat.h>
@@ -83,6 +83,12 @@
                    TimeValue (Seconds (0.)),
                    MakeTimeAccessor (&EmuNetDevice::m_tStop),
                    MakeTimeChecker ())
+    .AddAttribute ("EncapsulationMode", 
+                   "The link-layer encapsulation type to use.",
+                   EnumValue (LLC),
+                   MakeEnumAccessor (&EmuNetDevice::SetEncapsulationMode),
+                   MakeEnumChecker (DIX, "Dix",
+                                    LLC, "Llc"))
 
     //
     // Transmit queueing discipline for the device which includes its own set
@@ -165,7 +171,6 @@
   return tid;
 }
 
-
 EmuNetDevice::EmuNetDevice () 
 : 
   m_startEvent (),
@@ -178,11 +183,17 @@
   m_isMulticast (false)
 {
   NS_LOG_FUNCTION (this);
+  m_packetBuffer = new uint8_t[65536];
   Start (m_tStart);
 }
 
 EmuNetDevice::~EmuNetDevice ()
 {
+  if (m_packetBuffer)
+    {
+      delete [] m_packetBuffer;
+      m_packetBuffer = 0;
+    }
 }
 
 void 
@@ -193,6 +204,21 @@
   NetDevice::DoDispose ();
 }
 
+void 
+EmuNetDevice::SetEncapsulationMode (enum EncapsulationMode mode)
+{
+  NS_LOG_FUNCTION (mode);
+  m_encapMode = mode;
+  NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
+}
+
+EmuNetDevice::EncapsulationMode
+EmuNetDevice::GetEncapsulationMode (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_encapMode;
+}
+
 void
 EmuNetDevice::Start (Time tStart)
 {
@@ -203,6 +229,20 @@
   //
   Simulator::Cancel (m_startEvent);
   m_startEvent = Simulator::Schedule (tStart, &EmuNetDevice::StartDevice, this);
+
+  //
+  // We're going to need a pointer to the realtime simulator implementation.
+  // It's important to remember that access to that implementation may happen 
+  // in a completely different thread than the simulator is running in.  We are
+  // talking about multiple threads here, so it is very, very dangerous to do 
+  // any kind of reference couning on a shared object.  So what we are going to 
+  // do is to get a reference to the realtime simulator and then save a raw 
+  // pointer to that implementation for use by the other threads.  We must not
+  // free this pointer or we may delete the simulator out from under us an 
+  // everyone else.
+  //
+  Ptr<RealtimeSimulatorImpl> impl = DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ());
+  m_rtImpl = GetPointer (impl);
 }
 
   void
@@ -308,6 +348,7 @@
       // This one is OK to enable at runtime
       m_isMulticast = true;
     }
+
   //
   // Now spin up a read thread to read packets.
   //
@@ -563,6 +604,10 @@
   locations.push_back ("../../../build/optimized/src/devices/emu/");
   locations.push_back ("../../../build/debug/src/devices/emu/");
 
+  // src/devices/emu (or build/debug/examples/emulation)
+  locations.push_back ("../../../../build/optimized/src/devices/emu/");
+  locations.push_back ("../../../../build/debug/src/devices/emu/");
+
   for (std::list<std::string>::const_iterator i = locations.begin (); i != locations.end (); ++i)
     {
       struct stat st;
@@ -632,31 +677,43 @@
 
   uint16_t protocol;
   
-  //
-  // If the length/type is less than 1500, it corresponds to a length 
-  // interpretation packet.  In this case, it is an 802.3 packet and 
-  // will also have an 802.2 LLC header.  If greater than 1500, we
-  // find the protocol number (Ethernet type) directly.
-  //
-  if (header.GetLengthType () <= 1500)
+  switch (m_encapMode)
     {
-      LlcSnapHeader llc;
+    case LLC:
       //
-      // Check to see that the packet is long enough to possibly contain the
-      // header we want to remove before just naively calling.
+      // If the length/type is less than 1500, it corresponds to a length 
+      // interpretation packet.  In this case, it is an 802.3 packet and 
+      // will also have an 802.2 LLC header.  If greater than 1500, we
+      // find the protocol number (Ethernet type) directly.
       //
-      if (packet->GetSize() < llc.GetSerializedSize())
+      if (header.GetLengthType () <= 1500)
         {
-          m_phyRxDropTrace (originalPacket);
-          return;
-        }
+          LlcSnapHeader llc;
+          //
+          // Check to see that the packet is long enough to possibly contain the
+          // header we want to remove before just naively calling.
+          //
+          if (packet->GetSize() < llc.GetSerializedSize())
+            {
+              m_phyRxDropTrace (originalPacket);
+              return;
+            }
 
-      packet->RemoveHeader (llc);
-      protocol = llc.GetType ();
-    }
-  else
-    {
+          packet->RemoveHeader (llc);
+          protocol = llc.GetType ();
+        }
+      else
+        {
+          protocol = header.GetLengthType ();
+        }
+      break;
+
+    case DIX:
       protocol = header.GetLengthType ();
+      break;
+
+    default:
+      NS_FATAL_ERROR ("invalid encapsulation mode");
     }
 
   PacketType packetType;
@@ -709,13 +766,9 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  //
-  // It's important to remember that we're in a completely different thread than the simulator is running in.  We
-  // need to synchronize with that other thread to get the packet up into ns-3.  What we will need to do is to schedule 
-  // a method to forward up the packet using the multithreaded simulator we are most certainly running.  However, I just 
-  // said it -- we are talking about two threads here, so it is very, very dangerous to do any kind of reference couning
-  // on a shared object.  Just don't do it.  So what we're going to do is to allocate a buffer on the heap and pass that
-  // buffer into the ns-3 context thread where it will create the packet.
+  // It's important to remember that we're in a completely different thread than the simulator is running in.
+  // We are talking about multiple threads here, so it is very, very dangerous to do any kind of reference couning
+  // on a shared object.
   //
 
   int32_t len = -1;
@@ -724,6 +777,10 @@
 
   for (;;) 
     {
+      //
+      // to avoid any issues with a shared reference counted packet, we allocate a buffer on the heap and pass that
+      // buffer into the ns-3 context thread where it will create the packet, copy the buffer and then free it.
+      //
       uint32_t bufferSize = 65536;
       uint8_t *buf = (uint8_t *)malloc (bufferSize);
       if (buf == 0)
@@ -743,8 +800,8 @@
 
       NS_LOG_INFO ("EmuNetDevice::ReadThread(): Received packet");
       NS_LOG_INFO ("EmuNetDevice::ReadThread(): Scheduling handler");
-      DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
-        MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
+      NS_ASSERT_MSG (m_rtImpl, "EmuNetDevice::ReadThread(): Realtime simulator implementation pointer not set");
+      m_rtImpl->ScheduleRealtimeNowWithContext (GetNode ()->GetId (), MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
       buf = 0;
     }
 }
@@ -795,19 +852,30 @@
   NS_LOG_LOGIC ("Transmit packet from " << source);
   NS_LOG_LOGIC ("Transmit packet to " << destination);
 
-  //
-  // We've got to pick either DIX (Ethernet) or LLC/SNAP (IEEE 802.3) as a 
-  // packet format.  IEEE 802.3 is slightly more formally correct, so we 
-  // go that route.
-  //
-  LlcSnapHeader llc;
-  llc.SetType (protocolNumber);
-  packet->AddHeader (llc);
-
   EthernetHeader header (false);
   header.SetSource (source);
   header.SetDestination (destination);
-  header.SetLengthType (packet->GetSize ());
+
+  switch (m_encapMode)
+    {
+    case LLC:
+      {
+        LlcSnapHeader llc;
+        llc.SetType (protocolNumber);
+        packet->AddHeader (llc);
+
+        header.SetLengthType (packet->GetSize ());
+      }
+      break;
+      
+    case DIX:
+      header.SetLengthType (protocolNumber);
+      break;
+      
+    default:
+      NS_FATAL_ERROR ("invalid encapsulation mode");
+    }
+  
   packet->AddHeader (header);
 
   //
@@ -827,7 +895,6 @@
   m_promiscSnifferTrace (packet);
   m_snifferTrace (packet);
 
-
   struct sockaddr_ll ll;
   bzero (&ll, sizeof (ll));
 
@@ -837,8 +904,10 @@
 
   NS_LOG_LOGIC ("calling sendto");
 
-  int32_t rc;
-  rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
+  NS_ASSERT_MSG (packet->GetSize () <= 65536, "EmuNetDevice::SendFrom(): Packet too big " << packet->GetSize ());
+  packet->CopyData (m_packetBuffer, packet->GetSize ());
+
+  int32_t rc = sendto (m_sock, m_packetBuffer, packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
   NS_LOG_LOGIC ("sendto returns " << rc);
 
   return rc == -1 ? false : true;
--- a/src/devices/emu/emu-net-device.h	Mon Nov 30 14:46:02 2009 -0800
+++ b/src/devices/emu/emu-net-device.h	Mon Nov 30 18:22:10 2009 -0800
@@ -32,6 +32,7 @@
 #include "ns3/ptr.h"
 #include "ns3/mac48-address.h"
 #include "ns3/system-thread.h"
+#include "ns3/realtime-simulator-impl.h"
 
 namespace ns3 {
 
@@ -47,6 +48,15 @@
   static TypeId GetTypeId (void);
 
   /**
+   * Enumeration of the types of packets supported in the class.
+   */
+  enum EncapsulationMode {
+    ILLEGAL,     /**< Encapsulation mode not set */
+    DIX,         /**< DIX II / Ethernet II packet */
+    LLC,         /**< 802.2 LLC/SNAP Packet*/  
+  };
+
+  /**
    * Construct a EmuNetDevice
    *
    * This is the constructor for the EmuNetDevice.  It takes as a
@@ -176,6 +186,22 @@
 
   virtual bool SupportsSendFrom (void) const;
 
+  /**
+   * Set the encapsulation mode of this device.
+   *
+   * \param mode The encapsulation mode of this device.
+   *
+   * \see SetFrameSize
+   */
+  void SetEncapsulationMode (EmuNetDevice::EncapsulationMode mode);
+
+  /**
+   * Get the encapsulation mode of this device.
+   *
+   * \returns The encapsulation mode of this device.
+   */
+  EmuNetDevice::EncapsulationMode  GetEncapsulationMode (void) const;
+
 private:
 
   virtual void DoDispose (void);
@@ -445,6 +471,13 @@
   int32_t m_sll_ifindex;
 
   /**
+   * The type of packet that should be created by the AddHeader
+   * function and that should be processed by the ProcessHeader
+   * function.
+   */
+  EncapsulationMode m_encapMode;
+
+  /**
    * Flag indicating whether or not the link is up.  In this case,
    * whether or not the device is connected to a channel.
    */
@@ -471,6 +504,17 @@
    * The unix/linux name of the underlying device (e.g., eth0)
    */
   std::string m_deviceName;
+
+  /**
+   * A 64K buffer to hold packet data while it is being sent.
+   */
+  uint8_t *m_packetBuffer;
+
+  /**
+   * A copy of a raw pointer to the required real-time simulator implementation.
+   * Never free this pointer!
+   */
+  RealtimeSimulatorImpl *m_rtImpl;
 };
 
 } // namespace ns3
--- a/src/simulator/realtime-simulator-impl.cc	Mon Nov 30 14:46:02 2009 -0800
+++ b/src/simulator/realtime-simulator-impl.cc	Mon Nov 30 18:22:10 2009 -0800
@@ -620,10 +620,9 @@
 // Schedule an event for a _relative_ time in the future.
 //
 void
-RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, EventImpl *impl)
+RealtimeSimulatorImpl::ScheduleRealtimeWithContext (uint32_t context, Time const &time, EventImpl *impl)
 {
-  NS_LOG_FUNCTION (time << impl);
-
+  NS_LOG_FUNCTION (context << time << impl);
   
   {
     CriticalSection cs (m_mutex);
@@ -639,13 +638,19 @@
     m_events->Insert (ev);
     m_synchronizer->Signal ();
   }
-
 }
 
 void
-RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
+RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, EventImpl *impl)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION (time << impl);
+  ScheduleRealtimeWithContext (GetContext (), time, impl);
+}
+
+void
+RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext (uint32_t context, EventImpl *impl)
+{
+  NS_LOG_FUNCTION (context << impl);
   {
     CriticalSection cs (m_mutex);
 
@@ -654,11 +659,13 @@
     // realtime clock.  If we're not, then m_currentTs is were we stopped.
     // 
     uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
-    NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtimeNow(): schedule for time < m_currentTs");
+    NS_ASSERT_MSG (ts >= m_currentTs, 
+                   "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
     Scheduler::Event ev;
     ev.impl = impl;
     ev.key.m_ts = ts;
     ev.key.m_uid = m_uid;
+    ev.key.m_context = context;
     m_uid++;
     m_unscheduledEvents++;
     m_events->Insert (ev);
@@ -666,6 +673,13 @@
   }
 }
 
+void
+RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
+{
+  NS_LOG_FUNCTION (impl);
+  ScheduleRealtimeNowWithContext (GetContext (), impl);
+}
+
 Time
 RealtimeSimulatorImpl::RealtimeNow (void) const
 {
--- a/src/simulator/realtime-simulator-impl.h	Mon Nov 30 14:46:02 2009 -0800
+++ b/src/simulator/realtime-simulator-impl.h	Mon Nov 30 18:22:10 2009 -0800
@@ -71,7 +71,9 @@
   virtual void SetScheduler (ObjectFactory schedulerFactory);
   virtual uint32_t GetContext (void) const;
 
+  void ScheduleRealtimeWithContext (uint32_t context, Time const &time, EventImpl *event);
   void ScheduleRealtime (Time const &time, EventImpl *event);
+  void ScheduleRealtimeNowWithContext (uint32_t context, EventImpl *event);
   void ScheduleRealtimeNow (EventImpl *event);
   Time RealtimeNow (void) const;