From f4d296baaa58fde0df9648a32bf6c675ba1c1ee2 Mon Sep 17 00:00:00 2001 From: Eduardo Almeida Date: Sun, 24 Oct 2021 01:33:08 +0100 Subject: [PATCH] core: Replace SystemCondition class with STL --- src/core/examples/sample-show-progress.cc | 9 +- src/core/model/system-condition.h | 126 ----------- src/core/model/unix-system-condition.cc | 263 ---------------------- src/core/model/wall-clock-synchronizer.cc | 30 ++- src/core/model/wall-clock-synchronizer.h | 15 +- src/fd-net-device/model/fd-net-device.h | 1 - 6 files changed, 37 insertions(+), 407 deletions(-) delete mode 100644 src/core/model/system-condition.h delete mode 100644 src/core/model/unix-system-condition.cc diff --git a/src/core/examples/sample-show-progress.cc b/src/core/examples/sample-show-progress.cc index 59099d6ad..26d5c9793 100644 --- a/src/core/examples/sample-show-progress.cc +++ b/src/core/examples/sample-show-progress.cc @@ -33,8 +33,9 @@ #include "ns3/core-module.h" -#include +#include #include +#include #include @@ -92,15 +93,12 @@ public: int64x64_t ratio = (Simulator::Now () / m_interval) / 10; bool even = (ratio.GetHigh () % 2); Time work = m_wait * (even ? 3 : 1); - m_condition.TimedWait ( work.GetNanoSeconds () ); - + std::this_thread::sleep_for (std::chrono::nanoseconds (work.GetNanoSeconds ())); } private: /** The random number generator for the interval between events. */ Ptr m_rng; - /** Timer to represent workload. */ - SystemCondition m_condition; /** Mean inter-event time. */ Time m_wait; /** Time between switching workloads. */ @@ -145,4 +143,5 @@ main (int argc, char ** argv) Simulator::Run (); Simulator::Destroy (); + return 0; } diff --git a/src/core/model/system-condition.h b/src/core/model/system-condition.h deleted file mode 100644 index a0cb07f3c..000000000 --- a/src/core/model/system-condition.h +++ /dev/null @@ -1,126 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2008 University of Washington - * - * 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 - */ - -#ifndef SYSTEM_CONDITION_H -#define SYSTEM_CONDITION_H - -#include "ptr.h" - -/** - * @file - * @ingroup thread - * ns3::SystemCondition declaration. - */ - -namespace ns3 { - -/** - * @ingroup system - * @defgroup thread Threading and Signaling. - * - * System-independent interfaces to threads, signal conditions, and mutex. - */ - -class SystemConditionPrivate; - -/** - * @ingroup thread - * @brief A class which provides a relatively platform-independent - * conditional-wait thread synchronization primitive. - * - * It is often desirable to have a mechanism by which a thread can suspend its - * execution and relinquish the process until some condition to becomes true. - * We provide platform-independent access to this OS-dependent capability with - * the SystemCondition class. - * - * There are two ways to tell the underlying primitive that the condition has - * become true: Signal and Broadcast. Signal will only wake up one thread - * waiting on the condition (according to the OS scheduling policy); - * Broadcast will wake up all of the threads waiting on the condition - * (cf. "The Thundering Herd"). - * - * In order to wait for the underlying condition, you also have two - * alternatives: Wait and TimedWait. The Wait call will wait forever for the - * condition to become true; but the TimedWait has a timeout. - * - * The condition underlying this class is a simple boolean variable. It is - * set to false in each call to Wait and TimedWait. It is set to true in each - * call to Signal and Broadcast. This is a fairly simple-minded condition - * designed for - * - * A typical use case will be to call Wait() or TimedWait() in one thread - * context and put the processor to sleep until an event happens somewhere - * else that - */ -// The last two paragraphs are truncated in the earliest commit of this code: -// 2008-07-15 Craig Dowell add system threads and synchronization primitives -class SystemCondition -{ -public: - SystemCondition (); - ~SystemCondition (); - - /** - * Set the value of the underlying condition. - * @param [in] condition value - */ - void SetCondition (bool condition); - - /** - * Get the value of the underlying condition. - * \returns The state of the condition - */ - bool GetCondition (void); - - /** - * Release one thread if waiting for the condition to be true. If you want - * a waiting thread to return, you should have done a SetCondition (true) - * prior to calling. - */ - void Signal (void); - - /** - * Release all threads waiting for the condition to be true. If you want - * all waiting threads to return, you should have done a SetCondition (true) - * prior to calling. - */ - void Broadcast (void); - - /** - * Wait, possibly forever, for the condition to be true. - */ - void Wait (void); - - /** - * Wait a maximum of ns nanoseconds for the condition to be true. If the - * wait times out, return true else return false. - * @param [in] ns maximum of nanoseconds to wait - * @returns \c true if the timer expired, otherwise return \c false. - */ - bool TimedWait (uint64_t ns); - -private: - /** The (system-dependent) implementation. */ - SystemConditionPrivate * m_priv; -}; - -} // namespace ns3 - -#endif /* SYSTEM_CONDITION_H */ - - diff --git a/src/core/model/unix-system-condition.cc b/src/core/model/unix-system-condition.cc deleted file mode 100644 index 17f850818..000000000 --- a/src/core/model/unix-system-condition.cc +++ /dev/null @@ -1,263 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2008 University of Washington - * - * 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 - */ - -#include -#include // for ETIMEDOUT -#include // for timespec -#include // for timeval, gettimeofday - -#include "fatal-error.h" -#include "system-condition.h" -#include "log.h" - - -/** - * \file - * \ingroup thread - * ns3::SystemCondition and ns3::SystemConditionPrivate implementations. - */ - -namespace ns3 { - -NS_LOG_COMPONENT_DEFINE ("SystemCondition"); - -/** - * \ingroup thread - * Implementation of SystemCondition for Unix-like systems. - */ -class SystemConditionPrivate -{ -public: - /** Conversion from ns to s. */ - static const uint64_t NS_PER_SEC = (uint64_t)1000000000; - - /** Constructor. */ - SystemConditionPrivate (); - /** Destructor. */ - ~SystemConditionPrivate (); - - /** - * Set the condition. - * - * \param [in] condition The new condition value. - */ - void SetCondition (bool condition); - /** - * Get the condition value. - * - * \returns The condition value. - */ - bool GetCondition (void); - /** Signal the condition. */ - void Signal (void); - /** Broadcast the condition. */ - void Broadcast (void); - /** - * Unset the condition, then wait for another thread - * to set it with SetCondition. */ - void Wait (void); - /** - * Unset the condition, then wait for a limited amount of wall-clock - * time for another thread to set it with SetCondition. - * - * \param [in] ns Maximum time to wait, in ns. - * \returns \c true if the condition timed out; \c false if the other - * thread set it. - */ - bool TimedWait (uint64_t ns); - -private: - /** Mutex controlling access to the condition. */ - pthread_mutex_t m_mutex; - /** The pthread condition variable. */ - pthread_cond_t m_cond; - /** The condition state. */ - bool m_condition; -}; - -SystemConditionPrivate::SystemConditionPrivate () -{ - NS_LOG_FUNCTION (this); - - m_condition = false; - - pthread_mutexattr_t mAttr; - pthread_mutexattr_init (&mAttr); -// -// Linux and OS X (at least) have, of course chosen different names for the -// error checking flags just to make life difficult. -// -#if defined (PTHREAD_MUTEX_ERRORCHECK_NP) - pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK_NP); -#else - pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK); -#endif - pthread_mutex_init (&m_mutex, &mAttr); - - pthread_condattr_t cAttr; - pthread_condattr_init (&cAttr); - pthread_condattr_setpshared (&cAttr, PTHREAD_PROCESS_PRIVATE); - pthread_cond_init (&m_cond, &cAttr); -} - -SystemConditionPrivate::~SystemConditionPrivate () -{ - NS_LOG_FUNCTION (this); - pthread_mutex_destroy (&m_mutex); - pthread_cond_destroy (&m_cond); -} - -void -SystemConditionPrivate::SetCondition (bool condition) -{ - NS_LOG_FUNCTION (this << condition); - m_condition = condition; -} - -bool -SystemConditionPrivate::GetCondition (void) -{ - NS_LOG_FUNCTION (this); - return m_condition; -} - -void -SystemConditionPrivate::Signal (void) -{ - NS_LOG_FUNCTION (this); - - pthread_mutex_lock (&m_mutex); - pthread_cond_signal (&m_cond); - pthread_mutex_unlock (&m_mutex); -} - -void -SystemConditionPrivate::Broadcast (void) -{ - NS_LOG_FUNCTION (this); - - pthread_mutex_lock (&m_mutex); - pthread_cond_broadcast (&m_cond); - pthread_mutex_unlock (&m_mutex); -} - -void -SystemConditionPrivate::Wait (void) -{ - NS_LOG_FUNCTION (this); - - pthread_mutex_lock (&m_mutex); - m_condition = false; - while (m_condition == false) - { - pthread_cond_wait (&m_cond, &m_mutex); - } - pthread_mutex_unlock (&m_mutex); -} - -bool -SystemConditionPrivate::TimedWait (uint64_t ns) -{ - NS_LOG_FUNCTION (this << ns); - - struct timespec ts; - ts.tv_sec = ns / NS_PER_SEC; - ts.tv_nsec = ns % NS_PER_SEC; - - struct timeval tv; - gettimeofday (&tv, NULL); - - ts.tv_sec += tv.tv_sec; - ts.tv_nsec += tv.tv_usec * 1000; - if (ts.tv_nsec > (int64_t)NS_PER_SEC) - { - ++ts.tv_sec; - ts.tv_nsec %= NS_PER_SEC; - } - - int rc; - - pthread_mutex_lock (&m_mutex); - while (m_condition == false) - { - rc = pthread_cond_timedwait (&m_cond, &m_mutex, &ts); - if (rc == ETIMEDOUT) - { - pthread_mutex_unlock (&m_mutex); - return true; - } - } - pthread_mutex_unlock (&m_mutex); - return false; -} - -SystemCondition::SystemCondition () - : m_priv (new SystemConditionPrivate ()) -{ - NS_LOG_FUNCTION (this); -} - -SystemCondition::~SystemCondition () -{ - NS_LOG_FUNCTION (this); - delete m_priv; -} - -void -SystemCondition::SetCondition (bool condition) -{ - NS_LOG_FUNCTION (this << condition); - m_priv->SetCondition (condition); -} - -bool -SystemCondition::GetCondition (void) -{ - NS_LOG_FUNCTION (this); - return m_priv->GetCondition (); -} - -void -SystemCondition::Signal (void) -{ - NS_LOG_FUNCTION (this); - m_priv->Signal (); -} - -void -SystemCondition::Broadcast (void) -{ - NS_LOG_FUNCTION (this); - m_priv->Broadcast (); -} - -void -SystemCondition::Wait (void) -{ - NS_LOG_FUNCTION (this); - m_priv->Wait (); -} - -bool -SystemCondition::TimedWait (uint64_t ns) -{ - NS_LOG_FUNCTION (this << ns); - return m_priv->TimedWait (ns); -} - -} // namespace ns3 diff --git a/src/core/model/wall-clock-synchronizer.cc b/src/core/model/wall-clock-synchronizer.cc index b87571771..ed17afe7b 100644 --- a/src/core/model/wall-clock-synchronizer.cc +++ b/src/core/model/wall-clock-synchronizer.cc @@ -16,16 +16,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #include // clock_t #include // gettimeofday // clock_getres: glibc < 2.17, link with librt #include "log.h" -#include "system-condition.h" - #include "wall-clock-synchronizer.h" +#include +#include +#include + /** * \file * \ingroup realtime @@ -286,15 +287,21 @@ WallClockSynchronizer::DoSignal (void) { NS_LOG_FUNCTION (this); - m_condition.SetCondition (true); - m_condition.Signal (); + std::unique_lock lock (m_mutex); + m_condition = true; + + // Manual unlocking is done before notifying, to avoid waking up + // the waiting thread only to block again (see notify_one for details). + // Reference: https://en.cppreference.com/w/cpp/thread/condition_variable + lock.unlock (); + m_conditionVariable.notify_one (); } void WallClockSynchronizer::DoSetCondition (bool cond) { NS_LOG_FUNCTION (this << cond); - m_condition.SetCondition (cond); + m_condition = cond; } void @@ -323,7 +330,7 @@ WallClockSynchronizer::SpinWait (uint64_t ns) { return true; } - if (m_condition.GetCondition ()) + if (m_condition) { return false; } @@ -336,7 +343,14 @@ bool WallClockSynchronizer::SleepWait (uint64_t ns) { NS_LOG_FUNCTION (this << ns); - return m_condition.TimedWait (ns); + + std::unique_lock lock (m_mutex); + bool finishedWaiting = m_conditionVariable.wait_for ( + lock, + std::chrono::nanoseconds (ns), // Timeout + [this](){ return m_condition; }); // Wait condition + + return finishedWaiting; } uint64_t diff --git a/src/core/model/wall-clock-synchronizer.h b/src/core/model/wall-clock-synchronizer.h index 1f63e2296..33eff8e94 100644 --- a/src/core/model/wall-clock-synchronizer.h +++ b/src/core/model/wall-clock-synchronizer.h @@ -19,9 +19,11 @@ #ifndef WALL_CLOCK_CLOCK_SYNCHRONIZER_H #define WALL_CLOCK_CLOCK_SYNCHRONIZER_H -#include "system-condition.h" #include "synchronizer.h" +#include +#include + /** * @file * @ingroup realtime @@ -114,7 +116,8 @@ protected: * scheduled event might be before the time we are waiting until, so we have * to break out of both the SleepWait and the following SpinWait to go back * and reschedule/resynchronize taking the new event into account. The - * SystemCondition we have saved in m_condition takes care of this for us. + * condition we have saved in m_condition, along with the condition variable + * m_conditionVariable take care of this for us. * * This call will return if the timeout expires OR if the condition is * set @c true by a call to SetCondition (true) followed by a call to @@ -194,8 +197,12 @@ protected: /** Time recorded by DoEventStart. */ uint64_t m_nsEventStart; - /** Thread synchronizer. */ - SystemCondition m_condition; + /** Condition variable for thread synchronizer. */ + std::condition_variable m_conditionVariable; + /** Mutex controlling access to the condition variable. */ + std::mutex m_mutex; + /** The condition state. */ + bool m_condition; }; } // namespace ns3 diff --git a/src/fd-net-device/model/fd-net-device.h b/src/fd-net-device/model/fd-net-device.h index 99cc80d28..a791d5d61 100644 --- a/src/fd-net-device/model/fd-net-device.h +++ b/src/fd-net-device/model/fd-net-device.h @@ -31,7 +31,6 @@ #include "ns3/node.h" #include "ns3/packet.h" #include "ns3/ptr.h" -#include "ns3/system-condition.h" #include "ns3/traced-callback.h" #include "ns3/unix-fd-reader.h"