/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2005,2006 INRIA * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage */ #include "ns3/core-config.h" #include "simulator.h" #include "simulator-impl.h" #include "scheduler.h" #include "map-scheduler.h" #include "event-impl.h" #include "des-metrics.h" #include "ptr.h" #include "string.h" #include "object-factory.h" #include "global-value.h" #include "assert.h" #include "log.h" #include #include #include #include #include #include /** * \file * \ingroup simulator * ns3::Simulator implementation, as well as implementation pointer, * global scheduler implementation. */ namespace ns3 { // Note: Logging in this file is largely avoided due to the // number of calls that are made to these functions and the possibility // of causing recursions leading to stack overflow NS_LOG_COMPONENT_DEFINE ("Simulator"); /** * \ingroup simulator * \anchor GlobalValueSimulatorImplementationType * The specific simulator implementation to use. * * Must be derived from SimulatorImpl. */ static GlobalValue g_simTypeImpl = GlobalValue ("SimulatorImplementationType", "The object class to use as the simulator implementation", StringValue ("ns3::DefaultSimulatorImpl"), MakeStringChecker ()); /** * \ingroup scheduler * \anchor GlobalValueSchedulerType * The specific event scheduler implementation to use. * * Must be derived from Scheduler. */ static GlobalValue g_schedTypeImpl = GlobalValue ("SchedulerType", "The object class to use as the scheduler implementation", TypeIdValue (MapScheduler::GetTypeId ()), MakeTypeIdChecker ()); /** * \ingroup simulator * \brief Get the static SimulatorImpl instance. * \return The SimulatorImpl instance pointer. */ static SimulatorImpl ** PeekImpl (void) { static SimulatorImpl *impl = 0; return &impl; } /** * \ingroup simulator * \brief Get the SimulatorImpl singleton. * \return The singleton pointer. * \see Simulator::GetImplementation() */ static SimulatorImpl * GetImpl (void) { SimulatorImpl **pimpl = PeekImpl (); /* Please, don't include any calls to logging macros in this function * or pay the price, that is, stack explosions. */ if (*pimpl == 0) { { ObjectFactory factory; StringValue s; g_simTypeImpl.GetValue (s); factory.SetTypeId (s.Get ()); *pimpl = GetPointer (factory.Create ()); } { ObjectFactory factory; StringValue s; g_schedTypeImpl.GetValue (s); factory.SetTypeId (s.Get ()); (*pimpl)->SetScheduler (factory); } // // Note: we call LogSetTimePrinter _after_ creating the implementation // object because the act of creation can trigger calls to the logging // framework which would call the TimePrinter function which would call // Simulator::Now which would call Simulator::GetImpl, and, thus, get us // in an infinite recursion until the stack explodes. // LogSetTimePrinter (&DefaultTimePrinter); LogSetNodePrinter (&DefaultNodePrinter); } return *pimpl; } void Simulator::Destroy (void) { NS_LOG_FUNCTION_NOARGS (); SimulatorImpl **pimpl = PeekImpl (); if (*pimpl == 0) { return; } /* Note: we have to call LogSetTimePrinter (0) below because if we do not do * this, and restart a simulation after this call to Destroy, (which is * legal), Simulator::GetImpl will trigger again an infinite recursion until * the stack explodes. */ LogSetTimePrinter (0); LogSetNodePrinter (0); (*pimpl)->Destroy (); (*pimpl)->Unref (); *pimpl = 0; } void Simulator::SetScheduler (ObjectFactory schedulerFactory) { NS_LOG_FUNCTION (schedulerFactory); GetImpl ()->SetScheduler (schedulerFactory); } bool Simulator::IsFinished (void) { NS_LOG_FUNCTION_NOARGS (); return GetImpl ()->IsFinished (); } void Simulator::Run (void) { NS_LOG_FUNCTION_NOARGS (); Time::ClearMarkedTimes (); GetImpl ()->Run (); } void Simulator::Stop (void) { NS_LOG_FUNCTION_NOARGS (); NS_LOG_LOGIC ("stop"); GetImpl ()->Stop (); } void Simulator::Stop (Time const &delay) { NS_LOG_FUNCTION (delay); GetImpl ()->Stop (delay); } Time Simulator::Now (void) { /* Please, don't include any calls to logging macros in this function * or pay the price, that is, stack explosions. */ return GetImpl ()->Now (); } Time Simulator::GetDelayLeft (const EventId &id) { NS_LOG_FUNCTION (&id); return GetImpl ()->GetDelayLeft (id); } EventId Simulator::Schedule (Time const &delay, const Ptr &event) { return DoSchedule (delay, GetPointer (event)); } EventId Simulator::ScheduleNow (const Ptr &ev) { return DoScheduleNow (GetPointer (ev)); } void Simulator::ScheduleWithContext (uint32_t context, const Time &delay, EventImpl *impl) { #ifdef ENABLE_DES_METRICS DesMetrics::Get ()->TraceWithContext (context, Now (), delay); #endif return GetImpl ()->ScheduleWithContext (context, delay, impl); } EventId Simulator::ScheduleDestroy (const Ptr &ev) { return DoScheduleDestroy (GetPointer (ev)); } EventId Simulator::DoSchedule (Time const &time, EventImpl *impl) { #ifdef ENABLE_DES_METRICS DesMetrics::Get ()->Trace (Now (), time); #endif return GetImpl ()->Schedule (time, impl); } EventId Simulator::DoScheduleNow (EventImpl *impl) { #ifdef ENABLE_DES_METRICS DesMetrics::Get ()->Trace (Now (), Time (0)); #endif return GetImpl ()->ScheduleNow (impl); } EventId Simulator::DoScheduleDestroy (EventImpl *impl) { return GetImpl ()->ScheduleDestroy (impl); } void Simulator::Remove (const EventId &id) { if (*PeekImpl () == 0) { return; } return GetImpl ()->Remove (id); } void Simulator::Cancel (const EventId &id) { if (*PeekImpl () == 0) { return; } return GetImpl ()->Cancel (id); } bool Simulator::IsExpired (const EventId &id) { if (*PeekImpl () == 0) { return true; } return GetImpl ()->IsExpired (id); } Time Now (void) { return Time (Simulator::Now ()); } Time Simulator::GetMaximumSimulationTime (void) { NS_LOG_FUNCTION_NOARGS (); return GetImpl ()->GetMaximumSimulationTime (); } uint32_t Simulator::GetContext (void) { return GetImpl ()->GetContext (); } uint64_t Simulator::GetEventCount (void) { return GetImpl ()->GetEventCount (); } uint32_t Simulator::GetSystemId (void) { NS_LOG_FUNCTION_NOARGS (); if (*PeekImpl () != 0) { return GetImpl ()->GetSystemId (); } else { return 0; } } void Simulator::SetImplementation (Ptr impl) { NS_LOG_FUNCTION (impl); if (*PeekImpl () != 0) { NS_FATAL_ERROR ("It is not possible to set the implementation after calling any Simulator:: function. Call Simulator::SetImplementation earlier or after Simulator::Destroy."); } *PeekImpl () = GetPointer (impl); // Set the default scheduler ObjectFactory factory; StringValue s; g_schedTypeImpl.GetValue (s); factory.SetTypeId (s.Get ()); impl->SetScheduler (factory); // // Note: we call LogSetTimePrinter _after_ creating the implementation // object because the act of creation can trigger calls to the logging // framework which would call the TimePrinter function which would call // Simulator::Now which would call Simulator::GetImpl, and, thus, get us // in an infinite recursion until the stack explodes. // LogSetTimePrinter (&DefaultTimePrinter); LogSetNodePrinter (&DefaultNodePrinter); } Ptr Simulator::GetImplementation (void) { NS_LOG_FUNCTION_NOARGS (); return GetImpl (); } } // namespace ns3