core: Replace SystemThread class with STL

This commit is contained in:
Eduardo Almeida
2021-10-24 01:40:19 +01:00
parent b32c80ecb0
commit 85ad3961fc
13 changed files with 62 additions and 344 deletions

View File

@@ -1,6 +1,7 @@
#include "ns3module.h"
#include "ns3/ref-count-base.h"
#include <unistd.h>
#include <thread>
#if PY_VERSION_HEX >= 0x03000000
# define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
@@ -362,7 +363,7 @@ private:
volatile bool m_stopped;
bool m_failed;
volatile bool m_isCheckPending;
ns3::Ptr<ns3::SystemThread> m_thread;
std::thread m_thread;
PyThreadState *m_py_thread_state;
};
@@ -371,7 +372,6 @@ PythonSimulator::PythonSimulator()
m_failed(false),
m_isCheckPending(false)
{
m_thread = ns3::Create<ns3::SystemThread>(ns3::MakeCallback(&PythonSimulator::DoRun, this));
m_py_thread_state = NULL;
}
@@ -381,7 +381,7 @@ PythonSimulator::Run(void)
m_failed = false;
m_stopped = false;
m_isCheckPending = false;
m_thread->Start();
m_thread = std::thread (&PythonSimulator::DoRun, this);
Py_BEGIN_ALLOW_THREADS;
@@ -390,7 +390,10 @@ PythonSimulator::Run(void)
Py_END_ALLOW_THREADS;
m_stopped = true;
m_thread->Join();
if (m_thread.joinable ())
{
m_thread.join ();
}
}
bool

View File

@@ -21,7 +21,6 @@
#include "ns3/realtime-simulator-impl.h"
#include "ns3/nstime.h"
#include "ns3/log.h"
#include "ns3/system-thread.h"
#include "ns3/string.h"
#include "ns3/config.h"
#include "ns3/global-value.h"
@@ -36,8 +35,7 @@
* \ingroup scheduler
* An example of scheduling events in a background thread.
*
* See \ref ns3::SystemThread,
* \ref ns3::SimulatorImpl::ScheduleWithContext
* See \ref ns3::SimulatorImpl::ScheduleWithContext
*/
using namespace ns3;
@@ -109,7 +107,7 @@ FakeNetDevice::Doit3 (void)
}
/**
* Example use of ns3::SystemThread.
* Example use of std::thread.
*
* This example is a complete simulation.
* It schedules \c first_function and many executions of \c background_function
@@ -138,13 +136,16 @@ test (void)
Simulator::Schedule (Seconds (d), &background_function);
}
Ptr<SystemThread> st3 = Create<SystemThread> (
MakeCallback (&FakeNetDevice::Doit3, &fnd));
st3->Start ();
std::thread st3 = std::thread (&FakeNetDevice::Doit3, &fnd);
Simulator::Stop (Seconds (15.0));
Simulator::Run ();
st3->Join ();
if (st3.joinable ())
{
st3.join ();
}
Simulator::Destroy ();
}

View File

@@ -65,7 +65,7 @@ DefaultSimulatorImpl::DefaultSimulatorImpl ()
m_unscheduledEvents = 0;
m_eventCount = 0;
m_eventsWithContextEmpty = true;
m_main = SystemThread::Self ();
m_mainThreadId = std::this_thread::get_id ();
}
DefaultSimulatorImpl::~DefaultSimulatorImpl ()
@@ -190,7 +190,7 @@ DefaultSimulatorImpl::Run (void)
{
NS_LOG_FUNCTION (this);
// Set the current threadId as the main threadId
m_main = SystemThread::Self ();
m_mainThreadId = std::this_thread::get_id ();
ProcessEventsWithContext ();
m_stop = false;
@@ -225,7 +225,8 @@ EventId
DefaultSimulatorImpl::Schedule (Time const &delay, EventImpl *event)
{
NS_LOG_FUNCTION (this << delay.GetTimeStep () << event);
NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::Schedule Thread-unsafe invocation!");
NS_ASSERT_MSG (m_mainThreadId == std::this_thread::get_id (),
"Simulator::Schedule Thread-unsafe invocation!");
NS_ASSERT_MSG (delay.IsPositive (), "DefaultSimulatorImpl::Schedule(): Negative delay");
Time tAbsolute = delay + TimeStep (m_currentTs);
@@ -246,7 +247,7 @@ DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay,
{
NS_LOG_FUNCTION (this << context << delay.GetTimeStep () << event);
if (SystemThread::Equals (m_main))
if (m_mainThreadId == std::this_thread::get_id ())
{
Time tAbsolute = delay + TimeStep (m_currentTs);
Scheduler::Event ev;
@@ -276,7 +277,8 @@ DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay,
EventId
DefaultSimulatorImpl::ScheduleNow (EventImpl *event)
{
NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleNow Thread-unsafe invocation!");
NS_ASSERT_MSG (m_mainThreadId == std::this_thread::get_id (),
"Simulator::ScheduleNow Thread-unsafe invocation!");
return Schedule (Time (0), event);
}
@@ -284,7 +286,8 @@ DefaultSimulatorImpl::ScheduleNow (EventImpl *event)
EventId
DefaultSimulatorImpl::ScheduleDestroy (EventImpl *event)
{
NS_ASSERT_MSG (SystemThread::Equals (m_main), "Simulator::ScheduleDestroy Thread-unsafe invocation!");
NS_ASSERT_MSG (m_mainThreadId == std::this_thread::get_id (),
"Simulator::ScheduleDestroy Thread-unsafe invocation!");
EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
m_destroyEvents.push_back (id);

View File

@@ -22,10 +22,9 @@
#define DEFAULT_SIMULATOR_IMPL_H
#include "simulator-impl.h"
#include "system-thread.h"
#include <list>
#include <mutex>
#include <thread>
/**
* \file
@@ -134,7 +133,7 @@ private:
int m_unscheduledEvents;
/** Main execution thread. */
SystemThread::ThreadId m_main;
std::thread::id m_mainThreadId;
};
} // namespace ns3

View File

@@ -31,9 +31,9 @@
#include "boolean.h"
#include "enum.h"
#include <cmath>
#include <mutex>
#include <thread>
/**
* \file
@@ -86,7 +86,7 @@ RealtimeSimulatorImpl::RealtimeSimulatorImpl ()
m_unscheduledEvents = 0;
m_eventCount = 0;
m_main = SystemThread::Self ();
m_main = std::this_thread::get_id ();
// Be very careful not to do anything that would cause a change or assignment
// of the underlying reference counts of m_synchronizer or you will be sorry.
@@ -426,7 +426,7 @@ RealtimeSimulatorImpl::Run (void)
"RealtimeSimulatorImpl::Run(): Simulator already running");
// Set the current threadId as the main threadId
m_main = SystemThread::Self ();
m_main = std::this_thread::get_id ();
m_stop = false;
m_running = true;
@@ -546,7 +546,7 @@ RealtimeSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay,
std::unique_lock lock {m_mutex};
uint64_t ts;
if (SystemThread::Equals (m_main))
if (m_main == std::this_thread::get_id ())
{
ts = m_currentTs + delay.GetTimeStep ();
}

View File

@@ -20,7 +20,6 @@
#define REALTIME_SIMULATOR_IMPL_H
#include "simulator-impl.h"
#include "system-thread.h"
#include "scheduler.h"
#include "synchronizer.h"
@@ -32,6 +31,7 @@
#include <list>
#include <mutex>
#include <thread>
/**
* \file
@@ -229,8 +229,8 @@ private:
/** The maximum allowable drift from real-time in SYNC_HARD_LIMIT mode. */
Time m_hardLimit;
/** Main SystemThread. */
SystemThread::ThreadId m_main;
/** Main thread. */
std::thread::id m_main;
};
} // namespace ns3

View File

@@ -1,104 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2008 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 <mathieu.lacage.inria.fr>
*/
#include "fatal-error.h"
#include "system-thread.h"
#include "log.h"
#include <cstring>
/**
* @file
* @ingroup thread
* System-independent thread class ns3::SystemThread definitions.
*/
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("SystemThread");
#ifdef HAVE_PTHREAD_H
SystemThread::SystemThread (Callback<void> callback)
: m_callback (callback)
{
NS_LOG_FUNCTION (this << &callback);
}
SystemThread::~SystemThread ()
{
NS_LOG_FUNCTION (this);
}
void
SystemThread::Start (void)
{
NS_LOG_FUNCTION (this);
int rc = pthread_create (&m_thread, NULL, &SystemThread::DoRun,
(void *)this);
if (rc)
{
NS_FATAL_ERROR ("pthread_create failed: " << rc << "=\"" <<
strerror (rc) << "\".");
}
}
void
SystemThread::Join (void)
{
NS_LOG_FUNCTION (this);
void *thread_return;
int rc = pthread_join (m_thread, &thread_return);
if (rc)
{
NS_FATAL_ERROR ("pthread_join failed: " << rc << "=\"" <<
strerror (rc) << "\".");
}
}
void *
SystemThread::DoRun (void *arg)
{
NS_LOG_FUNCTION (arg);
SystemThread *self = static_cast<SystemThread *> (arg);
self->m_callback ();
return 0;
}
SystemThread::ThreadId
SystemThread::Self (void)
{
NS_LOG_FUNCTION_NOARGS ();
return pthread_self ();
}
bool
SystemThread::Equals (SystemThread::ThreadId id)
{
NS_LOG_FUNCTION (id);
return (pthread_equal (pthread_self (), id) != 0);
}
#endif /* HAVE_PTHREAD_H */
} // namespace ns3

View File

@@ -1,177 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2008 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 <mathieu.lacage.inria.fr>
*/
#ifndef SYSTEM_THREAD_H
#define SYSTEM_THREAD_H
#include "ns3/core-config.h"
#include "callback.h"
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif /* HAVE_PTHREAD_H */
/**
* @file
* @ingroup thread
* System-independent thread class ns3::SystemThread declaration.
*/
namespace ns3 {
/**
* @ingroup thread
* @brief A class which provides a relatively platform-independent thread
* primitive.
*
* This class allows for creation of multiple threads of execution in a
* process. The exact implementation of the thread functionality is
* operating system dependent, but typically in ns-3 one is using an
* environment in which Posix Threads are supported (either natively or
* in the case of Windows via Cygwin's implementation of pthreads on the
* Win32 API. In either case we expect that these will be kernel-level
* threads and therefore a system with multiple CPUs will see truly concurrent
* execution.
*
* Synchronization between threads is provided via the SystemMutex class.
*
* See @ref main-test-sync.cc for example usage.
*/
class SystemThread : public SimpleRefCount<SystemThread>
{
public:
#ifdef HAVE_PTHREAD_H
/** Type alias for the system-dependent thread object. */
typedef pthread_t ThreadId;
#endif
/**
* @brief Create a SystemThread object.
*
* A system thread object is not created running. A thread of execution
* must be explicitly started by calling the Start method. When the
* Start method is called, it will spawn a thread of execution and cause
* that thread to call out into the callback function provided here as
* a parameter.
*
* Like all ns-3 callbacks, the provided callback may refer to a function
* or a method of an object depending on how the MakeCallback function is
* used.
*
* The most common use is expected to be creating a thread of execution in
* a method. In this case you would use code similar to,
* @code
* MyClass myObject;
* Ptr<SystemThread> st = Create<SystemThread> (
* MakeCallback (&MyClass::MyMethod, &myObject));
* st->Start ();
* @endcode
*
* The SystemThread is passed a callback that calls out to the function
* @c MyClass::MyMethod. When this function is called, it is called as an
* object method on the @c myObject object. Essentially what you are doing
* is asking the SystemThread to call @c object->MyMethod() in a new thread
* of execution.
*
* If starting a thread in your currently executing object, you can use the
* "this" pointer:
* @code
* Ptr<SystemThread> st = Create<SystemThread> (
* MakeCallback (&MyClass::MyMethod, this));
* st->Start ();
* @endcode
*
* Object lifetime is always an issue with threads, so it is common to use
* smart pointers. If you are spinning up a thread in an object that is
* managed by a smart pointer, you can use that pointer directly:
* @code
* Ptr<MyClass> myPtr = Create<MyClass> ();
* Ptr<SystemThread> st = Create<SystemThread> (
* MakeCallback (&MyClass::MyMethod, myPtr));
* st->Start ();
* @endcode
*
* Just like any thread, you can synchronize with its termination. The
* method provided to do this is Join(). If you call Join() you will block
* until the SystemThread run method returns.
*
* @param [in] callback entry point of the thread
*
* @warning I've made the system thread class look like a normal ns3 object
* with smart pointers, and living in the heap. This makes it very easy to
* manage threads from a single master thread context. You should be very
* aware though that I have not made Ptr multithread safe! This means that
* if you pass Ptr<SystemThread> around in a multithreaded environment, it is
* possible that the reference count will get messed up since it is not an
* atomic operation. CREATE AND MANAGE YOUR THREADS IN ONE PLACE -- LEAVE
* THE PTR THERE.
*/
SystemThread (Callback<void> callback);
/**
* @brief Destroy a SystemThread object.
*
*/
~SystemThread ();
/**
* @brief Start a thread of execution, running the provided callback.
*/
void Start (void);
/**
* @brief Suspend the caller until the thread of execution, running the
* provided callback, finishes.
*/
void Join (void);
/**
* @brief Returns the current thread Id.
*
* @returns Current thread Id.
*/
static ThreadId Self (void);
/**
* @brief Compares an ThreadId with the current ThreadId .
*
* @param [in] id The ThreadId to compare to.
* @returns @c true if @c id matches the current ThreadId.
*/
static bool Equals (ThreadId id);
private:
#ifdef HAVE_PTHREAD_H
/**
* Invoke the callback in the new thread.
*
* @param [in] arg This SystemThread instance to communicate to the newly
* launched thread.
* @return a null pointer (for compatibility)
*/
static void * DoRun (void *arg);
Callback<void> m_callback; /**< The main function for this thread when launched. */
pthread_t m_thread; /**< The thread id of the child thread. */
#endif
};
} // namespace ns3
#endif /* SYSTEM_THREAD_H */

View File

@@ -25,11 +25,11 @@
#include <cstring>
#include <unistd.h> // close()
#include <fcntl.h>
#include <thread>
#include "log.h"
#include "fatal-error.h"
#include "simple-ref-count.h"
#include "system-thread.h"
#include "simulator.h"
#include "unix-fd-reader.h"
@@ -45,7 +45,7 @@ namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("FdReader");
FdReader::FdReader ()
: m_fd (-1), m_readCallback (0), m_readThread (0), m_stop (false),
: m_fd (-1), m_readCallback (0), m_stop (false),
m_destroyEvent ()
{
NS_LOG_FUNCTION (this);
@@ -64,7 +64,7 @@ void FdReader::Start (int fd, Callback<void, uint8_t *, ssize_t> readCallback)
NS_LOG_FUNCTION (this << fd << &readCallback);
int tmp;
NS_ASSERT_MSG (m_readThread == 0, "read thread already exists");
NS_ASSERT_MSG (!m_readThread.joinable(), "read thread already exists");
// create a pipe for inter-thread event notification
tmp = pipe (m_evpipe);
@@ -107,8 +107,7 @@ void FdReader::Start (int fd, Callback<void, uint8_t *, ssize_t> readCallback)
//
NS_LOG_LOGIC ("Spinning up read thread");
m_readThread = Create<SystemThread> (MakeCallback (&FdReader::Run, this));
m_readThread->Start ();
m_readThread = std::thread (&FdReader::Run, this);
}
void FdReader::DestroyEvent (void)
@@ -135,10 +134,9 @@ void FdReader::Stop (void)
}
// join the read thread
if (m_readThread != 0)
if (m_readThread.joinable ())
{
m_readThread->Join ();
m_readThread = 0;
m_readThread.join ();
}
// close the write end of the event pipe

View File

@@ -22,9 +22,9 @@
#define UNIX_FD_READER_H
#include <stdint.h>
#include <thread>
#include "callback.h"
#include "system-thread.h"
#include "event-id.h"
/**
@@ -123,7 +123,7 @@ private:
Callback<void, uint8_t *, ssize_t> m_readCallback;
/** The thread doing the read, created and launched by Start(). */
Ptr<SystemThread> m_readThread;
std::thread m_readThread;
/** Pipe used to signal events between threads. */
int m_evpipe[2];

View File

@@ -25,7 +25,6 @@
#include "ns3/calendar-scheduler.h"
#include "ns3/config.h"
#include "ns3/string.h"
#include "ns3/system-thread.h"
#include <chrono> // seconds, milliseconds
#include <ctime>
@@ -36,7 +35,7 @@
using namespace ns3;
/// Maximum number of threads.
#define MAXTHREADS 64
constexpr int MAXTHREADS = 64;
/**
* \file
@@ -109,7 +108,7 @@ public:
ObjectFactory m_schedulerFactory; //!< Scheduler factory.
std::string m_simulatorType; //!< Simulator type.
std::string m_error; //!< Error condition.
std::list<Ptr<SystemThread> > m_threadlist; //!< Thread list.
std::list<std::thread> m_threadlist; //!< Thread list.
private:
virtual void DoSetup (void);
@@ -131,9 +130,12 @@ void
ThreadedSimulatorEventsTestCase::End (void)
{
m_stop = true;
for (std::list<Ptr<SystemThread> >::iterator it2 = m_threadlist.begin (); it2 != m_threadlist.end (); ++it2)
for (auto& thread : m_threadlist)
{
(*it2)->Join ();
if (thread.joinable ())
{
thread.join ();
}
}
}
void
@@ -236,14 +238,6 @@ ThreadedSimulatorEventsTestCase::DoSetup (void)
m_b =
m_c =
m_d = 0;
for (unsigned int i = 0; i < m_threads; ++i)
{
m_threadlist.push_back (
Create<SystemThread> (MakeBoundCallback (
&ThreadedSimulatorEventsTestCase::SchedulingThread,
std::pair<ThreadedSimulatorEventsTestCase *, unsigned int> (this,i) )) );
}
}
void
ThreadedSimulatorEventsTestCase::DoTeardown (void)
@@ -261,10 +255,11 @@ ThreadedSimulatorEventsTestCase::DoRun (void)
Simulator::Schedule (MicroSeconds (10), &ThreadedSimulatorEventsTestCase::EventA, this, 1);
Simulator::Schedule (Seconds (1), &ThreadedSimulatorEventsTestCase::End, this);
for (std::list<Ptr<SystemThread> >::iterator it = m_threadlist.begin (); it != m_threadlist.end (); ++it)
for (unsigned int i = 0; i < m_threads; ++i)
{
(*it)->Start ();
m_threadlist.push_back (
std::thread (&ThreadedSimulatorEventsTestCase::SchedulingThread,
std::pair<ThreadedSimulatorEventsTestCase *, unsigned int> (this,i) ));
}
Simulator::Run ();

View File

@@ -19,10 +19,10 @@
*/
#include "netmap-net-device.h"
#include "ns3/system-thread.h"
#include "ns3/uinteger.h"
#include <sys/ioctl.h>
#include <unistd.h>
#include <thread>
namespace ns3 {
@@ -191,7 +191,6 @@ NetmapNetDevice::NetmapNetDevice ()
m_nRxRingsSlots = 0;
m_queue = nullptr;
m_totalQueuedBytes = 0;
m_syncAndNotifyQueueThread = nullptr;
m_syncAndNotifyQueueThreadRun = false;
}
@@ -220,8 +219,7 @@ NetmapNetDevice::DoFinishStartingDevice (void)
NS_LOG_FUNCTION (this);
m_syncAndNotifyQueueThreadRun = true;
m_syncAndNotifyQueueThread = Create<SystemThread> (MakeCallback (&NetmapNetDevice::SyncAndNotifyQueue, this));
m_syncAndNotifyQueueThread->Start ();
m_syncAndNotifyQueueThread = std::thread (&NetmapNetDevice::SyncAndNotifyQueue, this);
}
@@ -233,8 +231,11 @@ NetmapNetDevice::DoFinishStoppingDevice (void)
m_queue->Stop ();
m_syncAndNotifyQueueThreadRun = false;
m_syncAndNotifyQueueThread->Join ();
m_syncAndNotifyQueueThread = nullptr;
if (m_syncAndNotifyQueueThread.joinable ())
{
m_syncAndNotifyQueueThread.join ();
}
}
uint32_t

View File

@@ -23,14 +23,13 @@
#include "ns3/net-device-queue-interface.h"
#include <mutex>
#include <thread>
#include "fd-net-device.h"
#include <net/netmap_user.h>
#include <atomic>
namespace ns3 {
class SystemThread;
/**
* \ingroup fd-net-device
*
@@ -210,7 +209,7 @@ private:
uint32_t m_nRxRingsSlots; //!< Number of slots in the receiver rings
Ptr<NetDeviceQueue> m_queue; //!< NetDevice queue
uint32_t m_totalQueuedBytes; //!< Total queued bytes
Ptr<SystemThread> m_syncAndNotifyQueueThread; //!< Thread used to perform the flow control
std::thread m_syncAndNotifyQueueThread; //!< Thread used to perform the flow control
std::atomic<bool> m_syncAndNotifyQueueThreadRun; //!< Running flag of the flow control thread
uint8_t m_syncAndNotifyQueuePeriod; //!< The period of time in us after which the device syncs the netmap ring and notifies queue status
};