bug 954: avoid segfault upon startup due to recursion in TimeSet code to Simulator::Schedule
--- a/src/core/model/nstime.h Mon Dec 10 10:54:28 2012 -0800
+++ b/src/core/model/nstime.h Wed Dec 12 04:10:25 2012 -0500
@@ -110,47 +110,47 @@
inline Time ()
: m_data ()
{
- TimeSet (this);
+ Time::Track (this);
}
inline Time(const Time &o)
: m_data (o.m_data)
{
- TimeSet (this);
+ Time::Track (this);
}
explicit inline Time (double v)
: m_data (lround (v))
{
- TimeSet (this);
+ Time::Track (this);
}
explicit inline Time (int v)
: m_data (v)
{
- TimeSet (this);
+ Time::Track (this);
}
explicit inline Time (long int v)
: m_data (v)
{
- TimeSet (this);
+ Time::Track (this);
}
explicit inline Time (long long int v)
: m_data (v)
{
- TimeSet (this);
+ Time::Track (this);
}
explicit inline Time (unsigned int v)
: m_data (v)
{
- TimeSet (this);
+ Time::Track (this);
}
explicit inline Time (unsigned long int v)
: m_data (v)
{
- TimeSet (this);
+ Time::Track (this);
}
explicit inline Time (unsigned long long int v)
: m_data (v)
{
- TimeSet (this);
+ Time::Track (this);
}
/**
* \brief Construct Time object from common time expressions like "1ms"
@@ -175,7 +175,7 @@
*/
~Time ()
{
- TimeUnset (this);
+ Time::UnTrack (this);
}
/**
@@ -296,6 +296,13 @@
*/
static void SetResolution (enum Unit resolution);
/**
+ * Freeze the current time resolution. This function is called
+ * internally from the Simulator::Run function. After this
+ * function is called, calls to SetResolution will trigger
+ * an assert.
+ */
+ static void FreezeResolution(void);
+ /**
* \returns the current global resolution.
*/
static enum Unit GetResolution (void);
@@ -402,7 +409,7 @@
explicit inline Time (const int64x64_t &value)
: m_data (value.GetHigh ())
{
- TimeSet (this);
+ Time::Track (this);
}
inline static Time From (const int64x64_t &value)
{
@@ -441,8 +448,7 @@
}
static struct Resolution SetDefaultNsResolution (void);
- static void SetResolution (enum Unit unit, struct Resolution *resolution,
- const bool convert = true);
+ static void SetResolution (enum Unit unit, struct Resolution *resolution);
/**
* Record all instances of Time, so we can rescale them when
@@ -461,30 +467,18 @@
* (and gcc 4.2) say no.
*/
typedef std::set< Time * > TimesSet;
- /**
- * Get the TimesSet instance.
- *
- * \param [in] deleteMe If true delete the TimesSet, so that it returns a null pointer ever after
- */
- static TimesSet * GetTimesSet ( const bool deleteMe = false );
- /**
- * Helper to clean up at Simulator::Run
- */
- static void DeleteTimesSet ();
+ static TimesSet * GetTimesSet ();
+ static TimesSet ** PeekTimesSet ();
/**
- * Record a Time instance with the TimesSet
- */
- static void TimeSet (Time * const time);
- /**
- * Remove a Time instance from the TimesSet, called by ~Time()
+ * Start tracking a Time instance with the TimesSet
+ * to be able to change the underlying value if the
+ * time resolution changes later
*/
- static void TimeUnset (Time * const time);
-
-
+ static void Track (Time * const time);
/**
- * Convert existing Times to the new unit.
+ * We do not need to track a Time instance anymore
*/
- static void ConvertTimes (const enum Unit unit);
+ static void UnTrack (Time * const time);
friend bool operator == (const Time &lhs, const Time &rhs);
friend bool operator != (const Time &lhs, const Time &rhs);
--- a/src/core/model/simulator.cc Mon Dec 10 10:54:28 2012 -0800
+++ b/src/core/model/simulator.cc Wed Dec 12 04:10:25 2012 -0500
@@ -157,7 +157,9 @@
Simulator::Run (void)
{
NS_LOG_FUNCTION_NOARGS ();
- GetImpl ()->Run ();
+ SimulatorImpl *impl = GetImpl ();
+ Time::FreezeResolution();
+ impl->Run ();
}
void
--- a/src/core/model/time.cc Mon Dec 10 10:54:28 2012 -0800
+++ b/src/core/model/time.cc Wed Dec 12 04:10:25 2012 -0500
@@ -21,7 +21,6 @@
*/
#include "nstime.h"
#include "abort.h"
-#include "log.h"
#include "global-value.h"
#include "enum.h"
#include "string.h"
@@ -31,8 +30,6 @@
#include <cmath>
#include <sstream>
-NS_LOG_COMPONENT_DEFINE ("Time");
-
namespace ns3 {
Time::Time (const std::string& s)
@@ -84,16 +81,15 @@
*this = Time::FromDouble (v, Time::S);
}
- TimeSet (this);
+ Time::Track (this);
}
// static
struct Time::Resolution
Time::SetDefaultNsResolution (void)
{
- NS_LOG_FUNCTION_NOARGS();
struct Resolution resolution;
- SetResolution (Time::NS, &resolution, false);
+ SetResolution (Time::NS, &resolution);
return resolution;
}
@@ -101,7 +97,6 @@
void
Time::SetResolution (enum Unit resolution)
{
- NS_LOG_FUNCTION (resolution);
SetResolution (resolution, PeekResolution ());
}
@@ -109,21 +104,19 @@
enum Time::Unit
Time::GetResolution (void)
{
- NS_LOG_FUNCTION_NOARGS();
return PeekResolution ()->unit;
}
// static
void
-Time::SetResolution (enum Unit unit, struct Resolution *resolution,
- const bool convert /* = true */)
+Time::SetResolution (enum Unit unit, struct Resolution *resolution)
{
- NS_LOG_FUNCTION (unit << resolution << convert);
- if (convert)
- { // We have to convert old values
- ConvertTimes (unit);
+ TimesSet * times = GetTimesSet();
+ if (times == 0)
+ {
+ NS_FATAL_ERROR("It is not legal to try to set the resolution " \
+ "_after_ it has been frozen by Simulator::Run");
}
-
int8_t power [LAST] = { 15, 12, 9, 6, 3, 0};
for (int i = 0; i < Time::LAST; i++)
{
@@ -157,37 +150,49 @@
resolution->unit = unit;
}
+// static
+Time::TimesSet **
+Time::PeekTimesSet (void)
+{
+ static TimesSet *times = new TimesSet();
+ return ×
+}
// static
Time::TimesSet *
-Time::GetTimesSet ( const bool deleteMe /* = false */ )
+Time::GetTimesSet ()
{
- static TimesSet * times = new TimesSet;
-
- if (deleteMe)
- {
- NS_LOG_LOGIC ("deleting TimesSet");
- if (times)
- {
- delete times;
- }
- times = 0;
- }
-
- return times;
+ TimesSet **ptimes = PeekTimesSet();
+ return *ptimes;
}
// static
void
-Time::DeleteTimesSet ()
+Time::FreezeResolution (void)
{
- NS_LOG_FUNCTION_NOARGS();
- Time::GetTimesSet (true);
+ TimesSet * times = GetTimesSet ();
+ if (times == 0)
+ {
+ // We froze the resolution more than once: no big deal
+ return;
+ }
+
+ for ( TimesSet::iterator it = times->begin();
+ it != times->end();
+ it++ )
+ {
+ Time * const tp = *it;
+ (*tp) = tp->ToInteger (Time::GetResolution());
+ }
+
+ TimesSet **ptimes = PeekTimesSet();
+ delete *ptimes;
+ *ptimes = 0;
}
// static
void
-Time::TimeSet (Time * const time)
+Time::Track (Time * const time)
{
NS_ASSERT (time != 0);
@@ -196,30 +201,12 @@
{
std::pair< TimesSet::iterator, bool> ret;
ret = times->insert ( time);
- NS_LOG_LOGIC ("\t[" << times->size () << "] recording " << time);
-
- if (ret.second == false)
- {
- NS_LOG_WARN ("already recorded " << time << "!");
- }
- // If this is the first Time, schedule the cleanup.
- if (times->size () == 1)
- {
- // We schedule here, after the first event has been added,
- // rather than in GetTimesSet when the set is empty.
- // Scheduling there creates another Time, which
- // finds an empty set and schedules an event . . .
- // Doing it here, the schedule creates the second Time,
- // which doesn't recurse.
- NS_LOG_LOGIC ("scheduling DeleteTimesSet()");
- Simulator::Schedule ( Seconds (0), & DeleteTimesSet);
- }
}
}
// static
void
-Time::TimeUnset (Time * const time)
+Time::UnTrack (Time * const time)
{
NS_ASSERT (time != 0);
TimesSet * times = GetTimesSet ();
@@ -229,39 +216,10 @@
"Time object " << time << " registered "
<< times->count (time) << " times (should be 1)." );
- TimesSet::size_type num = times->erase (time);
- if (num != 1)
- {
- NS_LOG_WARN ("unexpected result erasing " << time << "!");
- NS_LOG_WARN ("got " << num << ", expected 1");
- }
- else
- {
- NS_LOG_LOGIC ("\t[" << times->size () << "] removing " << time);
- }
+ times->erase (time);
}
}
-// static
-void
-Time::ConvertTimes (const enum Unit unit)
-{
- NS_LOG_FUNCTION_NOARGS();
- TimesSet * times = GetTimesSet ();
- NS_ASSERT_MSG (times != 0, "No Time registry. Time::SetResolution () called mare than once?");
-
- for ( TimesSet::iterator it = times->begin();
- it != times->end();
- it++ )
- {
- Time * const tp = *it;
- (*tp) = tp->ToInteger (unit);
- }
-
- NS_LOG_LOGIC ("logged " << GetTimesSet ()->size () << " Time objects.");
- GetTimesSet (true);
-}
-
std::ostream&
operator<< (std::ostream& os, const Time & time)
{