diff --git a/examples/mesh/mesh.cc b/examples/mesh/mesh.cc index fa42ae62b..866b28a33 100644 --- a/examples/mesh/mesh.cc +++ b/examples/mesh/mesh.cc @@ -158,7 +158,16 @@ MeshTest::CreateNodes () * mesh point device */ mesh = MeshHelper::Default (); - mesh.SetStackInstaller (m_stack, "Root", Mac48AddressValue (Mac48Address (m_root.c_str ()))); + if (!Mac48Address (m_root.c_str ()).IsBroadcast ()) + { + mesh.SetStackInstaller (m_stack, "Root", Mac48AddressValue (Mac48Address (m_root.c_str ()))); + } + else + { + //If root is not set, we do not use "Root" attribute, because it + //is specified only for 11s + mesh.SetStackInstaller (m_stack); + } if (m_chan) { mesh.SetSpreadInterfaceChannels (MeshHelper::SPREAD_CHANNELS); diff --git a/src/common/pcap-file-test-suite.cc b/src/common/pcap-file-test-suite.cc index 6a9e3903f..d71c19b31 100644 --- a/src/common/pcap-file-test-suite.cc +++ b/src/common/pcap-file-test-suite.cc @@ -12,6 +12,8 @@ * 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: Craig Dowell (craigdo@ee.washington.edu) */ #include @@ -948,6 +950,62 @@ ReadFileTestCase::DoRun (void) return false; } +// =========================================================================== +// Test case to make sure that the Pcap::Diff method works as expected +// =========================================================================== +class DiffTestCase : public TestCase +{ +public: + DiffTestCase (); + +private: + virtual bool DoRun (void); +}; + +DiffTestCase::DiffTestCase () + : TestCase ("Check that PcapFile::Diff works as expected") +{ +} + +bool +DiffTestCase::DoRun (void) +{ + // + // Check that PcapDiff(file, file) is false + // + std::string filename = NS_TEST_SOURCEDIR + "known.pcap"; + uint32_t sec(0), usec(0); + bool diff = PcapFile::Diff (filename, filename, sec, usec); + NS_TEST_EXPECT_MSG_EQ (diff, false, "PcapDiff(file, file) must always be false"); + + // + // Create different PCAP file (with the same timestamps, but different packets) and check that it is indeed different + // + std::string filename2 = "different.pcap"; + PcapFile f; + + bool err = f.Open (filename2, "w"); + NS_TEST_ASSERT_MSG_EQ (err, false, "Open (" << filename2 << ", \"w\") returns error"); + err = f.Init (1, N_PACKET_BYTES); + NS_TEST_ASSERT_MSG_EQ (err, false, "Init (1, " << N_PACKET_BYTES << ") returns error"); + + for (uint32_t i = 0; i < N_KNOWN_PACKETS; ++i) + { + PacketEntry const & p = knownPackets[i]; + + err = f.Write (p.tsSec, p.tsUsec, (uint8_t const *)p.data, p.origLen); + NS_TEST_EXPECT_MSG_EQ (err, false, "Write must not fail"); + } + f.Close (); + + diff = PcapFile::Diff (filename, filename2, sec, usec); + NS_TEST_EXPECT_MSG_EQ (diff, true, "PcapDiff(file, file2) must be true"); + NS_TEST_EXPECT_MSG_EQ (sec, 2, "Files are different from 2.3696 seconds"); + NS_TEST_EXPECT_MSG_EQ (usec, 3696, "Files are different from 2.3696 seconds"); + + return GetErrorStatus(); +} + class PcapFileTestSuite : public TestSuite { public: @@ -963,6 +1021,7 @@ PcapFileTestSuite::PcapFileTestSuite () AddTestCase (new FileHeaderTestCase); AddTestCase (new RecordHeaderTestCase); AddTestCase (new ReadFileTestCase); + AddTestCase (new DiffTestCase); } PcapFileTestSuite pcapFileTestSuite; diff --git a/src/common/pcap-file.cc b/src/common/pcap-file.cc index c652d9808..e55e9da10 100644 --- a/src/common/pcap-file.cc +++ b/src/common/pcap-file.cc @@ -14,14 +14,16 @@ * 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: Craig Dowell (craigdo@ee.washington.edu) */ #include #include #include +#include #include "pcap-file.h" - // // This file is used as part of the ns-3 test framework, so please refrain from // adding any ns-3 specific constructs such as Packet to this file. @@ -516,4 +518,65 @@ PcapFile::Read ( return false; } +bool +PcapFile::Diff (std::string const & f1, std::string const & f2, + uint32_t & sec, uint32_t & usec, + uint32_t snapLen) +{ + PcapFile pcap[2]; + for (int i = 0; i < 2; ++i) + { + std::string const & file = (i == 0) ? f1 : f2; + bool err = pcap[i].Open (file, "r"); + if (err) + { + // Can't open file + return true; + } + } + + uint8_t data[2][snapLen]; + uint32_t tsSec[2], tsUsec[2], inclLen[2], origLen[2], readLen[2]; + bool err[2]; + bool diff(false); + + while (1) + { + for (int i = 0; i < 2; ++i) + err[i] = pcap[i].Read (data[i], snapLen, tsSec[i], tsUsec[i], inclLen[i], origLen[i], readLen[i]); + + sec = tsSec[0]; + usec = tsUsec[0]; + + if (err[0] != err[1]) + { + diff = true; // Read status doesn't match + break; + } + + if (err[0]) break; // nothing left + + if (tsSec[0] != tsSec[1] || tsUsec[0] != tsUsec[1]) + { + diff = true; // Next packet timestamps do not match + break; + } + + if (readLen[0] != readLen[1]) + { + diff = true; // Packet lengths do not match + break; + } + + if (std::memcmp(data[0], data[1], readLen[0]) != 0) + { + diff = true; // Packet data do not match + break; + } + } + pcap[0].Close (); + pcap[1].Close (); + return diff; +} + } //namespace ns3 diff --git a/src/common/pcap-file.h b/src/common/pcap-file.h index 2e9fe03e7..648766965 100644 --- a/src/common/pcap-file.h +++ b/src/common/pcap-file.h @@ -14,6 +14,8 @@ * 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: Craig Dowell (craigdo@ee.washington.edu) */ #ifndef PCAP_FILE_H @@ -125,7 +127,7 @@ public: * time zone from UTC/GMT. For example, Pacific Standard Time in the US is * GMT-8, so one would enter -8 for that correction. Defaults to 0 (UTC). * - * \returns false if the open succeeds, true otherwise. + * \return false if the open succeeds, true otherwise. * * \warning Calling this method on an existing file will result in the loss * any existing data. @@ -135,8 +137,31 @@ public: int32_t timeZoneCorrection = ZONE_DEFAULT, bool swapMode = false); + /** + * \brief Write next packet to file + * + * \param tsSec Packet timestamp, seconds + * \param tsUsec Packet timestamp, microseconds + * \param data Data buffer + * \param totalLen Total packet length + * + * \return true on error, false otherwise + */ bool Write (uint32_t tsSec, uint32_t tsUsec, uint8_t const * const data, uint32_t totalLen); + /** + * \brief Read next packet from file + * + * \param data [out] Data buffer + * \param maxBytes Allocated data buffer size + * \param tsSec [out] Packet timestamp, seconds + * \param tsUsec [out] Packet timestamp, microseconds + * \param inclLen [out] Included length + * \param origLen [out] Original length + * \param readLen [out] Number of bytes read + * + * \return true if read failed, false otherwise + */ bool Read (uint8_t * const data, uint32_t maxBytes, uint32_t &tsSec, @@ -154,6 +179,21 @@ public: uint32_t GetSigFigs (void); uint32_t GetSnapLen (void); uint32_t GetDataLinkType (void); + + /** + * \brief Compare two PCAP files packet-by-packet + * + * \return true if files are different, false otherwise + * + * \param f1 First PCAP file name + * \param f2 Second PCAP file name + * \param sec [out] Time stamp of first different packet, seconds. Undefined if files doesn't differ. + * \param uses [out] Time stamp of first different packet, microseconds. Undefined if files doesn't differ. + * \param snapLen Snap length (if used) + */ + static bool Diff (std::string const & f1, std::string const & f2, + uint32_t & sec, uint32_t & usec, + uint32_t snapLen = SNAPLEN_DEFAULT); private: typedef struct { diff --git a/src/core/system-wall-clock-ms.h b/src/core/system-wall-clock-ms.h index 0c512d3ad..2895f3dd8 100644 --- a/src/core/system-wall-clock-ms.h +++ b/src/core/system-wall-clock-ms.h @@ -21,10 +21,13 @@ #ifndef SYSTEM_WALL_CLOCK_MS_H #define SYSTEM_WALL_CLOCK_MS_H +#include + namespace ns3 { /** - * \brief measure wall-clock time in milliseconds + * \brief measure elapsed time in milliseconds + * */ class SystemWallClockMs { public: @@ -36,13 +39,39 @@ public: */ void Start (void); /** - * \returns the measured elapsed wall clock time since - * ns3::SystemWallClockMs::start was invoked. + * \brief Stop measuring the time since Start() was called. + * \returns the measured elapsed wall clock time (in milliseconds) since + * ns3::SystemWallClockMs::Start was invoked. * - * It is possible to start a new measurement with ns3::SystemWallClockMs::start + * It is possible to start a new measurement with ns3::SystemWallClockMs::Start * after this method returns. + * + * Returns int64_t to avoid dependency on clock_t in ns-3 code. */ - unsigned long long End (void); + int64_t End (void); + + /** + * \returns the measured elapsed wall clock time (in milliseconds) since + * ns3::SystemWallClockMs::Start was invoked. + * + * Returns int64_t to avoid dependency on clock_t in ns-3 code. + */ + int64_t GetElapsedReal (void) const; + /** + * \returns the measured elapsed 'user' wall clock time (in milliseconds) since + * ns3::SystemWallClockMs::Start was invoked. + * + * Returns int64_t to avoid dependency on clock_t in ns-3 code. + */ + int64_t GetElapsedUser (void) const; + /** + * \returns the measured elapsed 'system' wall clock time (in milliseconds) since + * ns3::SystemWallClockMs::Start was invoked. + * + * Returns int64_t to avoid dependency on clock_t in ns-3 code. + */ + int64_t GetElapsedSystem (void) const; + private: class SystemWallClockMsPrivate *m_priv; }; diff --git a/src/core/test.cc b/src/core/test.cc index 57d285ad0..77d833651 100644 --- a/src/core/test.cc +++ b/src/core/test.cc @@ -262,7 +262,7 @@ TestCase::ContinueOnFailure (void) void TestCase::DoReportStart (void) { - m_startTime = times (&m_startTimes); + m_msClock.Start (); if (m_ofs == 0) { @@ -319,26 +319,21 @@ TestCase::DoReportTestFailure ( void TestCase::DoReportEnd (void) { - static long ticksPerSecond = sysconf (_SC_CLK_TCK); + m_msClock.End (); if (m_ofs == 0) { return; } - struct tms endTimes; - clock_t endTime = times (&endTimes); - - clock_t elapsed = endTime - m_startTime; - clock_t elapsedUsr = endTimes.tms_utime - m_startTimes.tms_utime; - clock_t elapsedSys = endTimes.tms_stime - m_startTimes.tms_stime; - - (*m_ofs).precision (2); + (*m_ofs).precision (3); *m_ofs << std::fixed; - *m_ofs << " " << "real " << static_cast (elapsed) / ticksPerSecond - << " user " << static_cast (elapsedUsr) / ticksPerSecond - << " system " << static_cast (elapsedSys) / ticksPerSecond + const double MS_PER_SEC = 1000.; + + *m_ofs << " " << "real " << m_msClock.GetElapsedReal () / MS_PER_SEC + << " user " << m_msClock.GetElapsedUser () / MS_PER_SEC + << " system " << m_msClock.GetElapsedSystem () / MS_PER_SEC << "" << std::endl; *m_ofs << " " << std::endl; @@ -523,8 +518,8 @@ TestSuite::ContinueOnFailure (void) void TestSuite::DoReportStart (void) { - m_startTime = times (&m_startTimes); - + m_msClock.Start (); + if (m_ofs == 0) { return; @@ -556,25 +551,21 @@ TestSuite::DoReportSuccess (void) void TestSuite::DoReportEnd (void) { - static long ticksPerSecond = sysconf (_SC_CLK_TCK); - + m_msClock.End (); + if (m_ofs == 0) { return; } - struct tms endTimes; - clock_t endTime = times (&endTimes); - clock_t elapsed = endTime - m_startTime; - clock_t elapsedUsr = endTimes.tms_utime - m_startTimes.tms_utime; - clock_t elapsedSys = endTimes.tms_stime - m_startTimes.tms_stime; - - (*m_ofs).precision (2); + (*m_ofs).precision (3); *m_ofs << std::fixed; - *m_ofs << " " << "real " << static_cast (elapsed) / ticksPerSecond - << " user " << static_cast (elapsedUsr) / ticksPerSecond - << " system " << static_cast (elapsedSys) / ticksPerSecond + const double MS_PER_SEC = 1000.; + + *m_ofs << " " << "real " << m_msClock.GetElapsedReal () / MS_PER_SEC + << " user " << m_msClock.GetElapsedUser () / MS_PER_SEC + << " system " << m_msClock.GetElapsedSystem () / MS_PER_SEC << "" << std::endl; *m_ofs << "" << std::endl; diff --git a/src/core/test.h b/src/core/test.h index 58db025f9..571578ff1 100644 --- a/src/core/test.h +++ b/src/core/test.h @@ -27,7 +27,10 @@ #include #include #include -#include + +#include "ns3/system-wall-clock-ms.h" + + // // Note on below macros: // @@ -821,6 +824,7 @@ private: TestCase (TestCase& tc); TestCase& operator= (TestCase& tc); + SystemWallClockMs m_msClock; std::string m_name; bool m_verbose; bool m_continueOnFailure; @@ -828,8 +832,6 @@ private: std::string m_basedir; std::ofstream *m_ofs; bool m_error; - clock_t m_startTime; - struct tms m_startTimes; }; /** @@ -1057,6 +1059,7 @@ private: TestSuite (TestSuite& ts); TestSuite& operator= (TestSuite& ts); + SystemWallClockMs m_msClock; std::string m_name; bool m_verbose; bool m_continueOnFailure; @@ -1064,10 +1067,7 @@ private: std::ofstream *m_ofs; bool m_error; TestType m_type; - - clock_t m_startTime; - struct tms m_startTimes; - + typedef std::vector TestCaseVector_t; TestCaseVector_t m_tests; }; diff --git a/src/core/unix-system-wall-clock-ms.cc b/src/core/unix-system-wall-clock-ms.cc index 14f1fbb5b..78c83b566 100644 --- a/src/core/unix-system-wall-clock-ms.cc +++ b/src/core/unix-system-wall-clock-ms.cc @@ -19,36 +19,105 @@ */ #include "system-wall-clock-ms.h" -#include +#include "abort.h" +#include namespace ns3 { class SystemWallClockMsPrivate { public: void Start (void); - unsigned long long End (void); + int64_t End (void); + int64_t GetElapsedReal (void) const; + int64_t GetElapsedUser (void) const; + int64_t GetElapsedSystem (void) const; + private: - struct timeval m_startTv; - struct timeval m_endTv; + struct tms m_startTimes; + clock_t m_startTime; + int64_t m_elapsedReal; + int64_t m_elapsedUser; + int64_t m_elapsedSystem; }; void SystemWallClockMsPrivate::Start (void) { - struct timezone tz; - gettimeofday (&m_startTv, &tz); + m_startTime = times (&m_startTimes); } -unsigned long long +int64_t SystemWallClockMsPrivate::End (void) { - struct timezone tz; - gettimeofday (&m_endTv, &tz); - unsigned long long end = m_endTv.tv_sec *1000 + m_endTv.tv_usec / 1000; - unsigned long long start = m_startTv.tv_sec *1000 + m_startTv.tv_usec / 1000; - return end - start; + // + // We need to return the number of milliseconds that have elapsed in some + // reasonably portable way. The underlying function that we will use returns + // a number of elapsed ticks. We can look up the number of ticks per second + // from the system configuration. + // + // Conceptually, we need to find the number of elapsed clock ticks and then + // multiply the result by the milliseconds per clock tick (or divide by clock + // ticks per millisecond). Integer dividing by clock ticks per millisecond + // is bad since this number is fractional on most machines and would result + // in divide by zero errors due to integer rounding. + // + // Multiplying by milliseconds per clock tick works up to a clock resolution + // of 1000 ticks per second. If we go past this point, we begin to get zero + // elapsed times when millisecondsPerTick becomes fractional and another + // rounding error appears. + // + // So rounding errors using integers can bite you from both direction. Since + // all of our targets have math coprocessors, why not just use doubles + // internally? Works fine, lasts a long time. + // + // If millisecondsPerTick becomes fractional, and an elapsed time greater than + // a milliscond is measured, the function will work as expected. If an elapsed + // time is measured that turns out to be less than a millisecond, we'll just + // return zero which would, I think, also will be expected. + // + static int64_t ticksPerSecond = sysconf (_SC_CLK_TCK); + static double millisecondsPerTick = 1000. / ticksPerSecond; + + // + // If sysconf () fails, we have no idea how to do the required conversion to ms. + // + NS_ABORT_MSG_IF (ticksPerSecond == -1, "SystemWallClockMsPrivate(): Cannot sysconf (_SC_CLK_TCK)"); + + struct tms endTimes; + clock_t endTime = times (&endTimes); + + double tmp; + + tmp = static_cast (endTime - m_startTime) * millisecondsPerTick; + m_elapsedReal = static_cast (tmp); + + tmp = static_cast (endTimes.tms_utime - m_startTimes.tms_utime) * millisecondsPerTick; + m_elapsedUser = static_cast (tmp); + + tmp = static_cast (endTimes.tms_stime - m_startTimes.tms_stime) * millisecondsPerTick; + m_elapsedSystem = static_cast (tmp); + + return m_elapsedReal; } +int64_t +SystemWallClockMsPrivate::GetElapsedReal (void) const +{ + return m_elapsedReal; +} + +int64_t +SystemWallClockMsPrivate::GetElapsedUser (void) const +{ + return m_elapsedUser; +} + +int64_t +SystemWallClockMsPrivate::GetElapsedSystem (void) const +{ + return m_elapsedSystem; +} + SystemWallClockMs::SystemWallClockMs () : m_priv (new SystemWallClockMsPrivate ()) {} @@ -64,10 +133,29 @@ SystemWallClockMs::Start (void) { m_priv->Start (); } -unsigned long long + +int64_t SystemWallClockMs::End (void) { return m_priv->End (); } +int64_t +SystemWallClockMs::GetElapsedReal (void) const +{ + return m_priv->GetElapsedReal (); +} + +int64_t +SystemWallClockMs::GetElapsedUser (void) const +{ + return m_priv->GetElapsedUser (); +} + +int64_t +SystemWallClockMs::GetElapsedSystem (void) const +{ + return m_priv->GetElapsedSystem (); +} + }; // namespace ns3 diff --git a/src/core/win32-system-wall-clock-ms.cc b/src/core/win32-system-wall-clock-ms.cc index 1cc9fc2c5..25046dbea 100644 --- a/src/core/win32-system-wall-clock-ms.cc +++ b/src/core/win32-system-wall-clock-ms.cc @@ -20,26 +20,97 @@ #include "system-wall-clock-ms.h" +#include + namespace ns3 { class SystemWallClockMsPrivate { public: void Start (void); - unsigned long long End (void); + int64_t End (void); + int64_t GetElapsedReal (void) const; + int64_t GetElapsedUser (void) const; + int64_t GetElapsedSystem (void) const; + private: + clock_t m_startTime; + int64_t m_elapsedReal; + int64_t m_elapsedUser; + int64_t m_elapsedSystem; }; void SystemWallClockMsPrivate::Start (void) { + m_startTime = clock (); } -unsigned long long +int64_t SystemWallClockMsPrivate::End (void) { - return 0; + // + // We need to return the number of milliseconds that have elapsed in some + // reasonably portable way. The underlying function that we will use returns + // a number of elapsed ticks. We can look up the number of ticks per second + // from the system configuration. + // + // Conceptually, we need to find the number of elapsed clock ticks and then + // multiply the result by the milliseconds per clock tick (or just as easily + // divide by clock ticks per millisecond). Integer dividing by clock ticks + // per millisecond is bad since this number is fractional on most machines + // and would result in divide by zero errors due to integer rounding. + // + // Multiplying by milliseconds per clock tick works up to a clock resolution + // of 1000 ticks per second. If we go past this point, we begin to get zero + // elapsed times when millisecondsPerTick becomes fractional and another + // rounding error appears. + // + // So rounding errors using integers can bite you from two direction. Since + // all of our targets have math coprocessors, why not just use doubles + // internally? Works fine, lasts a long time. + // + // If millisecondsPerTick becomes fractional, and an elapsed time greater than + // a milliscond is measured, the function will work as expected. If an elapsed + // time is measured that turns out to be less than a millisecond, we'll just + // return zero which would, I think, also will be expected. + // + static int64_t ticksPerSecond = CLOCKS_PER_SEC; + static double millisecondsPerTick = 1000. / ticksPerSecond; + + clock_t endTime = clock (); + + double tmp; + + tmp = static_cast (endTime - m_startTime) * millisecondsPerTick; + m_elapsedReal = static_cast (tmp); + + // + // Nothing like this in MinGW, for example. + // + m_elapsedUser = 0; + m_elapsedSystem = 0; + + return m_elapsedReal; } +int64_t +SystemWallClockMsPrivate::GetElapsedReal (void) const +{ + return m_elapsedReal; +} + +int64_t +SystemWallClockMsPrivate::GetElapsedUser (void) const +{ + return m_elapsedUser; +} + +int64_t +SystemWallClockMsPrivate::GetElapsedSystem (void) const +{ + return m_elapsedSystem; +} + SystemWallClockMs::SystemWallClockMs () : m_priv (new SystemWallClockMsPrivate ()) {} @@ -55,10 +126,29 @@ SystemWallClockMs::Start (void) { m_priv->Start (); } -unsigned long long + +int64_t SystemWallClockMs::End (void) { return m_priv->End (); } +int64_t +SystemWallClockMs::GetElapsedReal (void) const +{ + return m_priv->GetElapsedReal (); +} + +int64_t +SystemWallClockMs::GetElapsedUser (void) const +{ + return m_priv->GetElapsedUser (); +} + +int64_t +SystemWallClockMs::GetElapsedSystem (void) const +{ + return m_priv->GetElapsedSystem (); +} + }; // namespace ns3 diff --git a/src/devices/mesh/dot11s/hwmp-protocol.cc b/src/devices/mesh/dot11s/hwmp-protocol.cc index 7c3883d69..acc60136f 100644 --- a/src/devices/mesh/dot11s/hwmp-protocol.cc +++ b/src/devices/mesh/dot11s/hwmp-protocol.cc @@ -320,7 +320,7 @@ HwmpProtocol::ForwardUnicast (uint32_t sourceIface, const Mac48Address source, { NS_ASSERT(destination != Mac48Address::GetBroadcast ()); HwmpRtable::LookupResult result = m_rtable->LookupReactive (destination); - NS_LOG_DEBUG("Requested src = "<LookupProactive (); - } if (result.retransmitter == Mac48Address::GetBroadcast ()) { return; @@ -1008,7 +1012,6 @@ HwmpProtocol::SetRoot () Time randomStart = Seconds (coefficient.GetValue ()); m_proactivePreqTimer = Simulator::Schedule (randomStart, &HwmpProtocol::SendProactivePreq, this); NS_LOG_DEBUG ("ROOT IS: " << m_address); - SendProactivePreq (); m_isRoot = true; } void diff --git a/src/devices/mesh/dot11s/peer-management-protocol.h b/src/devices/mesh/dot11s/peer-management-protocol.h index 0a23fb1e5..9703d1cea 100644 --- a/src/devices/mesh/dot11s/peer-management-protocol.h +++ b/src/devices/mesh/dot11s/peer-management-protocol.h @@ -78,6 +78,7 @@ public: * \param interface the interface where a beacon was received from * \param peerAddress address of station, which sent a beacon * \param beaconInterval beacon interval (needed by beacon loss counter) + * \param beaconTiming beacon timing element (needed by BCA) */ void ReceiveBeacon (uint32_t interface, Mac48Address peerAddress, Time beaconInterval, Ptr beaconTiming); //\} diff --git a/src/devices/mesh/flame/flame-protocol-mac.cc b/src/devices/mesh/flame/flame-protocol-mac.cc index f9b6650c5..d1a047a4a 100644 --- a/src/devices/mesh/flame/flame-protocol-mac.cc +++ b/src/devices/mesh/flame/flame-protocol-mac.cc @@ -31,6 +31,8 @@ FlameProtocolMac::FlameProtocolMac (uint32_t ifIndex, Ptr protoco } FlameProtocolMac::~FlameProtocolMac () { + m_protocol = 0; + m_parent = 0; } void FlameProtocolMac::SetParent (Ptr parent) diff --git a/src/devices/mesh/flame/flame-protocol.cc b/src/devices/mesh/flame/flame-protocol.cc index d0bd251f0..8a0ebbdf2 100644 --- a/src/devices/mesh/flame/flame-protocol.cc +++ b/src/devices/mesh/flame/flame-protocol.cc @@ -127,7 +127,7 @@ FlameProtocol::GetTypeId () return tid; } FlameProtocol::FlameProtocol () : - m_address (Mac48Address ()), m_broadcastInterval (Seconds (5)), m_lastBroadcast (Simulator::Now ()), + m_address (Mac48Address ()), m_broadcastInterval (Seconds (5)), m_lastBroadcast (Seconds (0)), m_maxCost (32), m_myLastSeqno (1), m_rtable (CreateObject ()) { } @@ -137,6 +137,9 @@ FlameProtocol::~FlameProtocol () void FlameProtocol::DoDispose () { + m_interfaces.clear (); + m_rtable = 0; + m_mp = 0; } bool FlameProtocol::RequestRoute (uint32_t sourceIface, const Mac48Address source, const Mac48Address destination, @@ -224,8 +227,12 @@ FlameProtocol::RequestRoute (uint32_t sourceIface, const Mac48Address source, co m_stats.totalDropped++; return false; } + tag.receiver = result.retransmitter; + } + else + { + tag.receiver = Mac48Address::GetBroadcast (); } - tag.receiver = result.retransmitter; if (result.retransmitter == Mac48Address::GetBroadcast ()) { m_stats.txBroadcast++; @@ -262,19 +269,21 @@ FlameProtocol::RemoveRoutingStuff (uint32_t fromIface, const Mac48Address source } FlameHeader flameHdr; packet->RemoveHeader (flameHdr); - if ((destination == GetAddress ()) && (m_lastBroadcast + m_broadcastInterval < Simulator::Now ())) - { - Ptr packet = Create (); - m_mp->Send(packet, Mac48Address::GetBroadcast (), 0); - m_lastBroadcast = Simulator::Now (); - } - NS_ASSERT (protocolType == FLAME_PROTOCOL); - protocolType = flameHdr.GetProtocol (); - if ((HandleDataFrame (flameHdr.GetSeqno (), source, flameHdr, tag.transmitter, fromIface)) - || packet->GetSize () == 0) + if (HandleDataFrame (flameHdr.GetSeqno (), source, flameHdr, tag.transmitter, fromIface)) { return false; } + // Start PATH_UPDATE procedure if destination is our own address and last broadcast was sent more + // than broadcast interval ago or was not sent at all + if ((destination == GetAddress ()) && ((m_lastBroadcast + m_broadcastInterval < Simulator::Now ()) + || (m_lastBroadcast == Seconds (0)))) + { + Ptr packet = Create (); + m_mp->Send (packet, Mac48Address::GetBroadcast (), 0); + m_lastBroadcast = Simulator::Now (); + } + NS_ASSERT (protocolType == FLAME_PROTOCOL); + protocolType = flameHdr.GetProtocol (); return true; } bool diff --git a/src/helper/qos-wifi-mac-helper.cc b/src/helper/qos-wifi-mac-helper.cc index 4f1a08444..9ad423795 100644 --- a/src/helper/qos-wifi-mac-helper.cc +++ b/src/helper/qos-wifi-mac-helper.cc @@ -27,14 +27,7 @@ namespace ns3 { QosWifiMacHelper::QosWifiMacHelper () -{ - ObjectFactory defaultAggregator; - defaultAggregator.SetTypeId ("ns3::MsduStandardAggregator"); - m_aggregators.insert (std::make_pair (AC_VO, defaultAggregator)); - m_aggregators.insert (std::make_pair (AC_VI, defaultAggregator)); - m_aggregators.insert (std::make_pair (AC_BE, defaultAggregator)); - m_aggregators.insert (std::make_pair (AC_BK, defaultAggregator)); -} +{} QosWifiMacHelper::~QosWifiMacHelper () {} @@ -77,8 +70,7 @@ QosWifiMacHelper::SetMsduAggregatorForAc (AccessClass accessClass, std::string t std::string n2, const AttributeValue &v2, std::string n3, const AttributeValue &v3) { - std::map::iterator it; - it = m_aggregators.find (accessClass); + std::map::iterator it = m_aggregators.find (accessClass); if (it != m_aggregators.end ()) { it->second.SetTypeId (type); @@ -87,17 +79,32 @@ QosWifiMacHelper::SetMsduAggregatorForAc (AccessClass accessClass, std::string t it->second.Set (n2, v2); it->second.Set (n3, v3); } + else + { + ObjectFactory factory; + factory.SetTypeId (type); + factory.Set (n0, v0); + factory.Set (n1, v1); + factory.Set (n2, v2); + factory.Set (n3, v3); + m_aggregators.insert (std::make_pair (accessClass, factory)); + } } void QosWifiMacHelper::Setup (Ptr mac, enum AccessClass ac, std::string dcaAttrName) const { - ObjectFactory factory = m_aggregators.find (ac)->second; - PointerValue ptr; - mac->GetAttribute (dcaAttrName, ptr); - Ptr edca = ptr.Get (); - Ptr aggregator = factory.Create (); - edca->SetMsduAggregator (aggregator); + std::map::const_iterator it = m_aggregators.find (ac); + if (it != m_aggregators.end ()) + { + ObjectFactory factory = it->second; + + PointerValue ptr; + mac->GetAttribute (dcaAttrName, ptr); + Ptr edca = ptr.Get (); + Ptr aggregator = factory.Create (); + edca->SetMsduAggregator (aggregator); + } } diff --git a/src/routing/olsr/olsr-routing-protocol.cc b/src/routing/olsr/olsr-routing-protocol.cc index 2537ddcd0..7ec59bb0f 100644 --- a/src/routing/olsr/olsr-routing-protocol.cc +++ b/src/routing/olsr/olsr-routing-protocol.cc @@ -552,7 +552,23 @@ RoutingProtocol::MprComputation() } } - NS_LOG_DEBUG ("Size of N2: " << N2.size ()); +#ifdef NS3_LOG_ENABLE + { + std::ostringstream os; + os << "["; + for (TwoHopNeighborSet::const_iterator iter = N2.begin (); + iter != N2.end (); iter++) + { + TwoHopNeighborSet::const_iterator next = iter; + next++; + os << iter->neighborMainAddr << "->" << iter->twoHopNeighborAddr; + if (next != N2.end ()) + os << ", "; + } + os << "]"; + NS_LOG_DEBUG ("N2: " << os.str ()); + } +#endif //NS3_LOG_ENABLE // 1. Start with an MPR set made of all members of N with // N_willingness equal to WILL_ALWAYS @@ -584,30 +600,37 @@ RoutingProtocol::MprComputation() // 3. Add to the MPR set those nodes in N, which are the *only* // nodes to provide reachability to a node in N2. std::set coveredTwoHopNeighbors; - for (TwoHopNeighborSet::iterator twoHopNeigh = N2.begin (); twoHopNeigh != N2.end (); twoHopNeigh++) + for (TwoHopNeighborSet::const_iterator twoHopNeigh = N2.begin (); twoHopNeigh != N2.end (); twoHopNeigh++) { - NeighborSet::const_iterator onlyNeighbor = N.end (); - - for (NeighborSet::const_iterator neighbor = N.begin (); - neighbor != N.end (); neighbor++) + bool onlyOne = true; + // try to find another neighbor that can reach twoHopNeigh->twoHopNeighborAddr + for (TwoHopNeighborSet::const_iterator otherTwoHopNeigh = N2.begin (); otherTwoHopNeigh != N2.end (); otherTwoHopNeigh++) { - if (neighbor->neighborMainAddr == twoHopNeigh->neighborMainAddr) + if (otherTwoHopNeigh->twoHopNeighborAddr == twoHopNeigh->twoHopNeighborAddr + && otherTwoHopNeigh->neighborMainAddr != twoHopNeigh->neighborMainAddr) { - if (onlyNeighbor == N.end ()) - { - onlyNeighbor = neighbor; - } - else - { - onlyNeighbor = N.end (); - break; - } + onlyOne = false; + break; } } - if (onlyNeighbor != N.end ()) + if (onlyOne) { - mprSet.insert (onlyNeighbor->neighborMainAddr); - coveredTwoHopNeighbors.insert (twoHopNeigh->twoHopNeighborAddr); + NS_LOG_LOGIC ("Neighbor " << twoHopNeigh->neighborMainAddr + << " is the only that can reach 2-hop neigh. " + << twoHopNeigh->twoHopNeighborAddr + << " => select as MPR."); + + mprSet.insert (twoHopNeigh->neighborMainAddr); + + // take note of all the 2-hop neighbors reachable by the newly elected MPR + for (TwoHopNeighborSet::const_iterator otherTwoHopNeigh = N2.begin (); + otherTwoHopNeigh != N2.end (); otherTwoHopNeigh++) + { + if (otherTwoHopNeigh->neighborMainAddr == twoHopNeigh->neighborMainAddr) + { + coveredTwoHopNeighbors.insert (otherTwoHopNeigh->twoHopNeighborAddr); + } + } } } // Remove the nodes from N2 which are now covered by a node in the MPR set. @@ -616,6 +639,7 @@ RoutingProtocol::MprComputation() { if (coveredTwoHopNeighbors.find (twoHopNeigh->twoHopNeighborAddr) != coveredTwoHopNeighbors.end ()) { + NS_LOG_LOGIC ("2-hop neigh. " << twoHopNeigh->twoHopNeighborAddr << " is already covered by an MPR."); twoHopNeigh = N2.erase (twoHopNeigh); } else @@ -628,6 +652,26 @@ RoutingProtocol::MprComputation() // least one node in the MPR set: while (N2.begin () != N2.end ()) { + +#ifdef NS3_LOG_ENABLE + { + std::ostringstream os; + os << "["; + for (TwoHopNeighborSet::const_iterator iter = N2.begin (); + iter != N2.end (); iter++) + { + TwoHopNeighborSet::const_iterator next = iter; + next++; + os << iter->neighborMainAddr << "->" << iter->twoHopNeighborAddr; + if (next != N2.end ()) + os << ", "; + } + os << "]"; + NS_LOG_DEBUG ("Step 4 iteration: N2=" << os.str ()); + } +#endif //NS3_LOG_ENABLE + + // 4.1. For each node in N, calculate the reachability, i.e., the // number of nodes in N2 which are not yet covered by at // least one node in the MPR set, and which are reachable diff --git a/test.py b/test.py index ddfd39d09..6a029e0b8 100755 --- a/test.py +++ b/test.py @@ -202,7 +202,8 @@ def translate_to_text(results_file, text_file): for example in dom.getElementsByTagName("Example"): result = get_node_text(example.getElementsByTagName("Result")[0]) name = get_node_text(example.getElementsByTagName("Name")[0]) - output = "%s: Example \"%s\"\n" % (result, name) + time = get_node_text(example.getElementsByTagName("ElapsedTime")[0]) + output = "%s: Example \"%s\" (%s)\n" % (result, name, time) f.write(output) f.close() @@ -408,12 +409,13 @@ def translate_to_html(results_file, html_file): # # The table headings look like, # - # +--------+--------------+ - # | Result | Example Name | - # +--------+--------------+ + # +--------+--------------+--------------+ + # | Result | Example Name | Elapsed Time | + # +--------+--------------+--------------+ # f.write(" Result \n") f.write("Example Name\n") + f.write("Elapsed Time\n") # # Now iterate through all of the examples @@ -430,6 +432,7 @@ def translate_to_html(results_file, html_file): # result = get_node_text(example.getElementsByTagName("Result")[0]) name = get_node_text(example.getElementsByTagName("Name")[0]) + time = get_node_text(example.getElementsByTagName("ElapsedTime")[0]) # # If the example either failed or crashed, print its result status @@ -447,6 +450,11 @@ def translate_to_html(results_file, html_file): # f.write("%s\n" % name) + # + # Write the elapsed time as a new tag data. + # + f.write("%s\n" % time) + # # That's it for the current example, so terminate the row. # @@ -533,37 +541,68 @@ def read_waf_config(): # path -- it is cooked up dynamically, so we do that too. # def make_library_path(): - global LIBRARY_PATH + have_DYLD_LIBRARY_PATH = False + have_LD_LIBRARY_PATH = False + have_PATH = False - LIBRARY_PATH = "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:'" + keys = os.environ.keys() + for key in keys: + if key == "DYLD_LIBRARY_PATH": + have_DYLD_LIBRARY_PATH = True + if key == "LD_LIBRARY_PATH": + have_LD_LIBRARY_PATH = True + if key == "PATH": + have_PATH = True if sys.platform == "darwin": - LIBRARY_PATH = "DYLD_LIBRARY_PATH='" + if not have_DYLD_LIBRARY_PATH: + os.environ["DYLD_LIBRARY_PATH"] = "" + for path in NS3_MODULE_PATH: + os.environ["DYLD_LIBRARY_PATH"] += ":" + path + if options.verbose: + print "os.environ[\"DYLD_LIBRARY_PATH\"] == %s" % os.environ["DYLD_LIBRARY_PATH"] elif sys.platform == "win32": - LIBRARY_PATH = "PATH=$PATH:'" + if not have_PATH: + os.environ["PATH"] = "" + for path in NS3_MODULE_PATH: + os.environ["PATH"] += ';' + path + if options.verbose: + print "os.environ[\"PATH\"] == %s" % os.environ["PATH"] elif sys.platform == "cygwin": - LIBRARY_PATH = "PATH=$PATH:'" - - for path in NS3_MODULE_PATH: - LIBRARY_PATH = LIBRARY_PATH + path + ":" - - LIBRARY_PATH = LIBRARY_PATH + "'" - - if options.verbose: - print "LIBRARY_PATH == %s" % LIBRARY_PATH + if not have_PATH: + os.environ["PATH"] = "" + for path in NS3_MODULE_PATH: + os.environ["PATH"] += ":" + path + if options.verbose: + print "os.environ[\"PATH\"] == %s" % os.environ["PATH"] + else: + if not have_LD_LIBRARY_PATH: + os.environ["LD_LIBRARY_PATH"] = "" + for path in NS3_MODULE_PATH: + os.environ["LD_LIBRARY_PATH"] += ":" + path + if options.verbose: + print "os.environ[\"LD_LIBRARY_PATH\"] == %s" % os.environ["LD_LIBRARY_PATH"] def run_job_synchronously(shell_command, directory, valgrind): + path_cmd = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command) if valgrind: - cmd = "%s valgrind --leak-check=full --error-exitcode=2 %s/%s/%s" % (LIBRARY_PATH, NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command) + cmd = "valgrind --leak-check=full --error-exitcode=2 %s" % path_cmd else: - cmd = "%s %s/%s/%s" % (LIBRARY_PATH, NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command) + cmd = path_cmd if options.verbose: print "Synchronously execute %s" % cmd - proc = subprocess.Popen(cmd, shell=True, cwd=directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + start_time = time.time() + proc = subprocess.Popen(cmd, shell = True, cwd = directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout_results, stderr_results = proc.communicate() - return (proc.returncode, stdout_results, stderr_results) + elapsed_time = time.time() - start_time + + if options.verbose: + print "Return code = ", proc.returncode + print "stderr = ", stderr_results + + return (proc.returncode, stdout_results, stderr_results, elapsed_time) # # This class defines a unit of testing work. It will typically refer to @@ -580,6 +619,7 @@ class Job: self.cwd = "" self.tmp_file_name = "" self.returncode = False + self.elapsed_time = 0 # # A job is either a standard job or a special job indicating that a worker @@ -659,6 +699,12 @@ class Job: def set_returncode(self, returncode): self.returncode = returncode + # + # The elapsed real time for the job execution. + # + def set_elapsed_time(self, elapsed_time): + self.elapsed_time = elapsed_time + # # The worker thread class that handles the actual running of a given test. # Once spawned, it receives requests for work through its input_queue and @@ -711,17 +757,19 @@ class worker_thread(threading.Thread): # If we have an example, the shell command is all we need to # know. It will be something like "examples/udp-echo" # - (job.returncode, standard_out, standard_err) = run_job_synchronously(job.shell_command, job.cwd, - options.valgrind) + (job.returncode, standard_out, standard_err, et) = run_job_synchronously(job.shell_command, + job.cwd, options.valgrind) else: # # If we're a test suite, we need to provide a little more info # to the test runner, specifically the base directory and temp # file name # - (job.returncode, standard_out, standard_err) = run_job_synchronously(job.shell_command + + (job.returncode, standard_out, standard_err, et) = run_job_synchronously(job.shell_command + " --basedir=%s --out=%s" % (job.basedir, job.tmp_file_name), job.cwd, options.valgrind) + job.set_elapsed_time(et) + if options.verbose: print "returncode = %d" % job.returncode print "---------- beign standard out ----------" @@ -756,11 +804,33 @@ def run_tests(): # For example, if the user only wants to run BVT tests, we only have # to build the test-runner and can ignore all of the examples. # + # If the user only wants to run a single example, then we can just build + # that example. + # + # If there is no constraint, then we have to build everything since the + # user wants to run everything. + # if options.kinds or options.list or (len(options.constrain) and options.constrain in core_kinds): - proc = subprocess.Popen("./waf --target=test-runner", shell=True) - else: - proc = subprocess.Popen("./waf", shell=True) + if sys.platform == "win32": + waf_cmd = "waf --target=test-runner" + else: + waf_cmd = "./waf --target=test-runner" + elif len(options.example): + if sys.platform == "win32": + waf_cmd = "waf --target=%s" % os.path.basename(options.example) + else: + waf_cmd = "./waf --target=%s" % os.path.basename(options.example) + else: + if sys.platform == "win32": + waf_cmd = "waf" + else: + waf_cmd = "./waf" + + if options.verbose: + print "Building: %s" % waf_cmd + + proc = subprocess.Popen(waf_cmd, shell = True) proc.communicate() # @@ -779,11 +849,13 @@ def run_tests(): # handle them without doing all of the hard work. # if options.kinds: - (rc, standard_out, standard_err) = run_job_synchronously("utils/test-runner --kinds", os.getcwd(), False) + path_cmd = os.path.join("utils", "test-runner --kinds") + (rc, standard_out, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False) print standard_out if options.list: - (rc, standard_out, standard_err) = run_job_synchronously("utils/test-runner --list", os.getcwd(), False) + path_cmd = os.path.join("utils", "test-runner --list") + (rc, standard_out, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False) print standard_out if options.kinds or options.list: @@ -854,10 +926,11 @@ def run_tests(): suites = options.suite + "\n" elif len(options.example) == 0: if len(options.constrain): - (rc, suites, standard_err) = run_job_synchronously("utils/test-runner --list --constrain=%s" % - options.constrain, os.getcwd(), False) + path_cmd = os.path.join("utils", "test-runner --list --constrain=%s" % options.constrain) + (rc, suites, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False) else: - (rc, suites, standard_err) = run_job_synchronously("utils/test-runner --list", os.getcwd(), False) + path_cmd = os.path.join("utils", "test-runner --list") + (rc, suites, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False) else: suites = "" @@ -888,13 +961,14 @@ def run_tests(): # processors = 1 - if 'SC_NPROCESSORS_ONLN'in os.sysconf_names: - processors = os.sysconf('SC_NPROCESSORS_ONLN') - else: - proc = subprocess.Popen("sysctl -n hw.ncpu", shell = True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout_results, stderr_results = proc.communicate() - if len(stderr_results) == 0: - processors = int(stdout_results) + if sys.platform != "win32": + if 'SC_NPROCESSORS_ONLN'in os.sysconf_names: + processors = os.sysconf('SC_NPROCESSORS_ONLN') + else: + proc = subprocess.Popen("sysctl -n hw.ncpu", shell = True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout_results, stderr_results = proc.communicate() + if len(stderr_results) == 0: + processors = int(stdout_results) # # Now, spin up one thread per processor which will eventually mean one test @@ -922,6 +996,7 @@ def run_tests(): # PASS, FAIL, CRASH and SKIP processing is done in the same place. # for test in suite_list: + test = test.strip() if len(test): job = Job() job.set_is_example(False) @@ -934,7 +1009,8 @@ def run_tests(): else: multiple = "" - job.set_shell_command("utils/test-runner --suite='%s'%s" % (test, multiple)) + path_cmd = os.path.join("utils", "test-runner --suite=%s%s" % (test, multiple)) + job.set_shell_command(path_cmd) if options.valgrind and test in core_valgrind_skip_tests: job.set_is_skip(True) @@ -1108,6 +1184,7 @@ def run_tests(): else: f.write(' CRASH\n') + f.write(' %.3f\n' % job.elapsed_time) f.write('\n') f.close() @@ -1167,7 +1244,7 @@ def run_tests(): else: if job.returncode == 0 or job.returncode == 1 or job.returncode == 2: f_to = open(xml_results_file, 'a') - f_from = open(job.tmp_file_name, 'r') + f_from = open(job.tmp_file_name) f_to.write(f_from.read()) f_to.close() f_from.close() diff --git a/utils/bench-packets.cc b/utils/bench-packets.cc index ff9ef71ae..ad951072c 100644 --- a/utils/bench-packets.cc +++ b/utils/bench-packets.cc @@ -248,7 +248,7 @@ runBench (void (*bench) (uint32_t), uint32_t n, char const *name) SystemWallClockMs time; time.Start (); (*bench) (n); - unsigned long long deltaMs = time.End (); + uint64_t deltaMs = time.End (); double ps = n; ps *= 1000; ps /= deltaMs; diff --git a/wscript b/wscript index f816bfa22..ba2a6d795 100644 --- a/wscript +++ b/wscript @@ -194,8 +194,13 @@ def set_options(opt): help=('Compile NS-3 statically: works only on linux, without python'), dest='enable_static', action='store_true', default=False) + opt.add_option('--doxygen-no-build', + help=('Run doxygen to generate html documentation from source comments, ' + 'but do not wait for ns-3 to finish the full build.'), + action="store_true", default=False, + dest='doxygen_no_build') - # options provided in a script in a subdirectory named "src" + # options provided in subdirectories opt.sub_options('src') opt.sub_options('bindings/python') opt.sub_options('src/internet-stack') @@ -282,13 +287,14 @@ def configure(conf): env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE') env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE') - if Options.options.build_profile == 'release': - env.append_value('CXXFLAGS', '-fomit-frame-pointer') - env.append_value('CXXFLAGS', '-march=native') - env['PLATFORM'] = sys.platform if conf.env['CXX_NAME'] in ['gcc', 'icc']: + if Options.options.build_profile == 'release': + env.append_value('CXXFLAGS', '-fomit-frame-pointer') + if conf.check_compilation_flag('-march=native'): + env.append_value('CXXFLAGS', '-march=native') + if sys.platform == 'win32': env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc") elif sys.platform == 'cygwin': @@ -595,6 +601,11 @@ def build(bld): raise Utils.WafError("Cannot run regression tests: building the ns-3 examples is not enabled" " (regression tests are based on examples)") + + if Options.options.doxygen_no_build: + _doxygen(bld) + raise SystemExit(0) + def shutdown(ctx): bld = wutils.bld if wutils.bld is None: @@ -711,9 +722,7 @@ def shell(ctx): env = wutils.bld.env wutils.run_argv([shell], env, {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])}) -def doxygen(bld): - """do a full build, generate the introspected doxygen and then the doxygen""" - Scripting.build(bld) +def _doxygen(bld): env = wutils.bld.env proc_env = wutils.get_proc_env() @@ -735,6 +744,11 @@ def doxygen(bld): if subprocess.Popen(['doxygen', doxygen_config]).wait(): raise SystemExit(1) +def doxygen(bld): + """do a full build, generate the introspected doxygen and then the doxygen""" + Scripting.build(bld) + _doxygen(bld) + def lcov_report(): env = Build.bld.env variant_name = env['NS3_ACTIVE_VARIANT']