core: Replace SystemCondition class with STL
This commit is contained in:
@@ -33,8 +33,9 @@
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -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<RandomVariableStream> 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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 <pthread.h>
|
||||
#include <cerrno> // for ETIMEDOUT
|
||||
#include <time.h> // for timespec
|
||||
#include <sys/time.h> // 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
|
||||
@@ -16,16 +16,17 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <ctime> // clock_t
|
||||
#include <sys/time.h> // gettimeofday
|
||||
// clock_getres: glibc < 2.17, link with librt
|
||||
|
||||
#include "log.h"
|
||||
#include "system-condition.h"
|
||||
|
||||
#include "wall-clock-synchronizer.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup realtime
|
||||
@@ -286,15 +287,21 @@ WallClockSynchronizer::DoSignal (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
m_condition.SetCondition (true);
|
||||
m_condition.Signal ();
|
||||
std::unique_lock<std::mutex> 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<std::mutex> 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
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
#ifndef WALL_CLOCK_CLOCK_SYNCHRONIZER_H
|
||||
#define WALL_CLOCK_CLOCK_SYNCHRONIZER_H
|
||||
|
||||
#include "system-condition.h"
|
||||
#include "synchronizer.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user