add system threads and synchronization primitives
This commit is contained in:
106
src/core/system-condition.h
Normal file
106
src/core/system-condition.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* -*- 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"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class SystemConditionPrivate;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
class SystemCondition
|
||||
{
|
||||
public:
|
||||
SystemCondition ();
|
||||
~SystemCondition ();
|
||||
|
||||
/**
|
||||
* Set the value of the underlying condition.
|
||||
*/
|
||||
void SetCondition (bool condition);
|
||||
|
||||
/**
|
||||
* Get the value of the underlying 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.
|
||||
*/
|
||||
bool TimedWait (uint64_t ns);
|
||||
|
||||
|
||||
private:
|
||||
SystemConditionPrivate * m_priv;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* SYSTEM_CONDITION_H */
|
||||
|
||||
|
||||
120
src/core/system-mutex.h
Normal file
120
src/core/system-mutex.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* -*- 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_MUTEX_H
|
||||
#define SYSTEM_MUTEX_H
|
||||
|
||||
#include "ptr.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class SystemMutexPrivate;
|
||||
|
||||
/**
|
||||
* @brief A class which provides a relatively platform-independent Mutual
|
||||
* Exclusion thread synchronization primitive.
|
||||
*
|
||||
* When more than one thread needs to access a shared resource (data structure
|
||||
* or device), the system needs to provide a way to serialize access to the
|
||||
* resource. An operating system will typically provide a Mutual Exclusion
|
||||
* primitive to provide that capability. We provide plattorm-independent
|
||||
* access to the OS-dependent capability with the SystemMutex class.
|
||||
*
|
||||
* There are two operations: Lock and Unlock. Lock allows an executing
|
||||
* SystemThread to attempt to acquire ownership of the Mutual Exclusion
|
||||
* object. If the SystemMutex object is not owned by another thread, then
|
||||
* ownership is granted to the calling SystemThread and Lock returns
|
||||
* immediately, However, if the SystemMutex is already owned by another
|
||||
* SystemThread, the calling SystemThread is blocked until the current owner
|
||||
* releases the SystemMutex by calling Unlock.
|
||||
*
|
||||
* @see CriticalSection
|
||||
*/
|
||||
class SystemMutex
|
||||
{
|
||||
public:
|
||||
SystemMutex ();
|
||||
~SystemMutex ();
|
||||
|
||||
/**
|
||||
* Acquire ownership of the Mutual Exclusion object.
|
||||
*/
|
||||
void Lock ();
|
||||
|
||||
/**
|
||||
* Release ownership of the Mutual Exclusion object.
|
||||
*/
|
||||
void Unlock ();
|
||||
|
||||
private:
|
||||
SystemMutexPrivate * m_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class which provides a simple way to implement a Critical Section.
|
||||
*
|
||||
* When more than one SystemThread needs to access a shared resource, we
|
||||
* conrol access by acquiring a SystemMutex. The CriticalSection class uses
|
||||
* the C++ scoping rules to automatically perform the required Lock and Unlock
|
||||
* operations to implement a Critical Section.
|
||||
*
|
||||
* If one wants to treat an entire method call as a critical section, one would
|
||||
* do something like,
|
||||
*
|
||||
* Class::Method ()
|
||||
* {
|
||||
* CriticalSection cs (mutex);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* In this case, the critical section is entered when the CriticalSection
|
||||
* object is created, and the critical section is exited when the
|
||||
* CriticalSection object goes out of scope at the end of the method.
|
||||
*
|
||||
* Finer granularity is achieved by using local scope blocks.
|
||||
*
|
||||
* Class::Method ()
|
||||
* {
|
||||
* ...
|
||||
* {
|
||||
* CriticalSection cs (mutex);
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* Here, the critical section is entered partway through the method when the
|
||||
* CriticalSection object is created in the local scope block (the braces).
|
||||
* The critical section is exited when the CriticalSection object goes out of
|
||||
* scope at the end of block.
|
||||
*
|
||||
* @see SystemMutex
|
||||
*/
|
||||
class CriticalSection
|
||||
{
|
||||
public:
|
||||
CriticalSection (SystemMutex &mutex);
|
||||
~CriticalSection ();
|
||||
private:
|
||||
SystemMutex &m_mutex;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* SYSTEM_MUTEX_H */
|
||||
156
src/core/system-thread.h
Normal file
156
src/core/system-thread.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/* -*- 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 "callback.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class SystemThreadImpl;
|
||||
|
||||
/**
|
||||
* @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 navively 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.
|
||||
*/
|
||||
class SystemThread
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @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,
|
||||
*
|
||||
* MyClass myObject;
|
||||
* Ptr<SystemThread> st = Create<SystemThread> (
|
||||
* MakeCallback (&MyClass::MyMethod, &myObject));
|
||||
* st->Start ();
|
||||
*
|
||||
* The SystemThread is passed a callback that calls out to the function
|
||||
* MyClass::MyMethod. When this function is called, it is called as an
|
||||
* object method on the myObject object. Essentially what you are doing
|
||||
* is asking the SystemThread to call object->MyMethod () in a new thread
|
||||
* of execution.
|
||||
*
|
||||
* Remember that if you are invoking a callback on an object that is
|
||||
* managed by a smart pointer, you need to call PeekPointer.
|
||||
*
|
||||
* Ptr<MyClass> myPtr = Create<MyClass> ();
|
||||
* Ptr<SystemThread> st = Create<SystemThread> (
|
||||
* MakeCallback (&MyClass::MyMethod, PeekPointer (myPtr)));
|
||||
* st->Start ();
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* Increment the reference count. This method should not be called
|
||||
* by user code. Object instances are expected to be used in conjunction
|
||||
* of the Ptr template which would make calling Ref unecessary and
|
||||
* dangerous.
|
||||
*/
|
||||
inline void Ref (void) const;
|
||||
|
||||
/**
|
||||
* Decrement the reference count. This method should not be called
|
||||
* by user code. Object instances are expected to be used in conjunction
|
||||
* of the Ptr template which would make calling Ref unecessary and
|
||||
* dangerous.
|
||||
*/
|
||||
inline void Unref (void) const;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
private:
|
||||
SystemThreadImpl * m_impl;
|
||||
mutable uint32_t m_count;
|
||||
};
|
||||
|
||||
void
|
||||
SystemThread::Ref (void) const
|
||||
{
|
||||
m_count++;
|
||||
}
|
||||
|
||||
void
|
||||
SystemThread::Unref (void) const
|
||||
{
|
||||
m_count--;
|
||||
if (m_count == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
#endif /* SYSTEM_THREAD_H */
|
||||
|
||||
|
||||
212
src/core/unix-system-condition.cc
Normal file
212
src/core/unix-system-condition.cc
Normal file
@@ -0,0 +1,212 @@
|
||||
/* -*- 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 <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include "fatal-error.h"
|
||||
#include "system-condition.h"
|
||||
#include "log.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SystemCondition");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class SystemConditionPrivate {
|
||||
public:
|
||||
static const uint64_t NS_PER_SEC = (uint64_t)1000000000;
|
||||
|
||||
SystemConditionPrivate ();
|
||||
~SystemConditionPrivate ();
|
||||
|
||||
void SetCondition (bool condition);
|
||||
bool GetCondition (void);
|
||||
void Signal (void);
|
||||
void Broadcast (void);
|
||||
void Wait (void);
|
||||
bool TimedWait (uint64_t ns);
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_cond;
|
||||
bool m_condition;
|
||||
};
|
||||
|
||||
SystemConditionPrivate::SystemConditionPrivate ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
m_condition = false;
|
||||
|
||||
pthread_mutexattr_t mAttr;
|
||||
pthread_mutexattr_init (&mAttr);
|
||||
pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK_NP);
|
||||
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_NOARGS ();
|
||||
pthread_mutex_destroy (&m_mutex);
|
||||
pthread_cond_destroy (&m_cond);
|
||||
}
|
||||
|
||||
void
|
||||
SystemConditionPrivate::SetCondition (bool condition)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_condition = condition;
|
||||
}
|
||||
|
||||
bool
|
||||
SystemConditionPrivate::GetCondition (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_condition;
|
||||
}
|
||||
|
||||
void
|
||||
SystemConditionPrivate::Signal (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
pthread_mutex_lock (&m_mutex);
|
||||
pthread_cond_signal (&m_cond);
|
||||
pthread_mutex_unlock (&m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
SystemConditionPrivate::Broadcast (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
pthread_mutex_lock (&m_mutex);
|
||||
pthread_cond_broadcast (&m_cond);
|
||||
pthread_mutex_unlock (&m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
SystemConditionPrivate::Wait (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
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_NOARGS ();
|
||||
|
||||
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_NOARGS ();
|
||||
}
|
||||
|
||||
SystemCondition::~SystemCondition ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
delete m_priv;
|
||||
}
|
||||
|
||||
void
|
||||
SystemCondition::SetCondition (bool condition)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_priv->SetCondition (condition);
|
||||
}
|
||||
|
||||
bool
|
||||
SystemCondition::GetCondition (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_priv->GetCondition ();
|
||||
}
|
||||
|
||||
void
|
||||
SystemCondition::Signal (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_priv->Signal ();
|
||||
}
|
||||
|
||||
void
|
||||
SystemCondition::Broadcast (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_priv->Broadcast ();
|
||||
}
|
||||
|
||||
void
|
||||
SystemCondition::Wait (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_priv->Wait ();
|
||||
}
|
||||
|
||||
bool
|
||||
SystemCondition::TimedWait (uint64_t ns)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_priv->TimedWait (ns);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
131
src/core/unix-system-mutex.cc
Normal file
131
src/core/unix-system-mutex.cc
Normal file
@@ -0,0 +1,131 @@
|
||||
/* -*- 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 <pthread.h>
|
||||
#include <errno.h>
|
||||
#include "fatal-error.h"
|
||||
#include "system-mutex.h"
|
||||
#include "log.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SystemMutex");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class SystemMutexPrivate {
|
||||
public:
|
||||
SystemMutexPrivate ();
|
||||
~SystemMutexPrivate ();
|
||||
|
||||
void Lock (void);
|
||||
void Unlock (void);
|
||||
private:
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
|
||||
SystemMutexPrivate::SystemMutexPrivate ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init (&attr);
|
||||
//
|
||||
// Make this an error checking mutex. This will check to see if the current
|
||||
// thread already owns the mutex before trying to lock it. Instead of
|
||||
// deadlocking it returns an error. It will also check to make sure a thread
|
||||
// has previously called pthread_mutex_lock when it calls pthread_mutex_unlock.
|
||||
//
|
||||
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
|
||||
pthread_mutex_init (&m_mutex, &attr);
|
||||
}
|
||||
|
||||
SystemMutexPrivate::~SystemMutexPrivate()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
pthread_mutex_destroy (&m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
SystemMutexPrivate::Lock (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
int rc = pthread_mutex_lock (&m_mutex);
|
||||
if (rc != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("SystemMutexPrivate::Lock()"
|
||||
"pthread_mutex_lock failed: " << rc << " = \"" <<
|
||||
strerror(rc) << "\"");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SystemMutexPrivate::Unlock (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
int rc = pthread_mutex_unlock (&m_mutex);
|
||||
if (rc != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("SystemMutexPrivate::Unlock()"
|
||||
"pthread_mutex_unlock failed: " << rc << " = \"" <<
|
||||
strerror(rc) << "\"");
|
||||
}
|
||||
}
|
||||
|
||||
SystemMutex::SystemMutex()
|
||||
: m_priv (new SystemMutexPrivate ())
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
SystemMutex::~SystemMutex()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
delete m_priv;
|
||||
}
|
||||
|
||||
void
|
||||
SystemMutex::Lock()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_priv->Lock ();
|
||||
}
|
||||
|
||||
void
|
||||
SystemMutex::Unlock()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_priv->Unlock ();
|
||||
}
|
||||
|
||||
CriticalSection::CriticalSection (SystemMutex &mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_mutex.Lock ();
|
||||
}
|
||||
|
||||
CriticalSection::~CriticalSection ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_mutex.Unlock ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
138
src/core/unix-system-thread.cc
Normal file
138
src/core/unix-system-thread.cc
Normal file
@@ -0,0 +1,138 @@
|
||||
/* -*- 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 <pthread.h>
|
||||
#include "fatal-error.h"
|
||||
#include "system-thread.h"
|
||||
#include "log.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SystemThread");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
//
|
||||
// Private implementation class for the SystemThread class. The deal is
|
||||
// that we export the SystemThread class to the user. The header just
|
||||
// declares a class and its members. There is a forward declaration for
|
||||
// a private implementation class there and a member declaration. Thus
|
||||
// there is no knowledge of the implementation in the exported header.
|
||||
//
|
||||
// We provide an implementation class for each operating system. This is
|
||||
// the Unix implementation of the SystemThread.
|
||||
//
|
||||
// In order to use the SystemThread, you will include "system-thread.h" and
|
||||
// get the implementation by linking unix-system-thread.cc (if you are running
|
||||
// a Posix system).
|
||||
//
|
||||
class SystemThreadImpl
|
||||
{
|
||||
public:
|
||||
SystemThreadImpl (Callback<void> callback);
|
||||
|
||||
void Start (void);
|
||||
void Join (void);
|
||||
|
||||
private:
|
||||
static void *DoRun (void *arg);
|
||||
Callback<void> m_callback;
|
||||
pthread_t m_thread;
|
||||
void * m_ret;
|
||||
};
|
||||
|
||||
SystemThreadImpl::SystemThreadImpl (Callback<void> callback)
|
||||
: m_callback (callback)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
void
|
||||
SystemThreadImpl::Start (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
int rc = pthread_create (&m_thread, NULL, &SystemThreadImpl::DoRun,
|
||||
(void *)this);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
NS_FATAL_ERROR ("pthread_create failed: " << rc << "=\"" <<
|
||||
strerror(rc) << "\".");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SystemThreadImpl::Join (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
void *thread_return;
|
||||
int rc = pthread_join (m_thread, &thread_return);
|
||||
if (rc)
|
||||
{
|
||||
NS_FATAL_ERROR ("pthread_join failed: " << rc << "=\"" <<
|
||||
strerror(rc) << "\".");
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
SystemThreadImpl::DoRun (void *arg)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
SystemThreadImpl *self = static_cast<SystemThreadImpl *> (arg);
|
||||
self->m_callback ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Remember that we just export the delcaration of the SystemThread class to
|
||||
// the user. There is no code to implement the SystemThread methods. We
|
||||
// have to do that here. We just vector the calls to our implementation
|
||||
// class above.
|
||||
//
|
||||
SystemThread::SystemThread (Callback<void> callback)
|
||||
: m_impl (new SystemThreadImpl (callback)),
|
||||
m_count (1)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
SystemThread::~SystemThread()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
void
|
||||
SystemThread::Start (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_impl->Start ();
|
||||
}
|
||||
|
||||
void
|
||||
SystemThread::Join (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_impl->Join ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -21,10 +21,15 @@ def configure(conf):
|
||||
e.define = 'HAVE_SIGNAL_H'
|
||||
e.run()
|
||||
|
||||
e = conf.create_library_configurator()
|
||||
e.mandatory = False
|
||||
e.name = 'rt'
|
||||
e.define = 'HAVE_RT'
|
||||
e.uselib = 'RT'
|
||||
e.run()
|
||||
|
||||
conf.write_config_header('ns3/core-config.h')
|
||||
|
||||
|
||||
|
||||
def build(bld):
|
||||
core = bld.create_ns3_module('core')
|
||||
core.source = [
|
||||
@@ -60,6 +65,7 @@ def build(bld):
|
||||
'trace-source-accessor.cc',
|
||||
'config.cc',
|
||||
]
|
||||
core.uselib = 'RT'
|
||||
|
||||
if sys.platform == 'win32':
|
||||
core.source.extend([
|
||||
@@ -67,12 +73,18 @@ def build(bld):
|
||||
])
|
||||
else:
|
||||
core.source.extend([
|
||||
'unix-system-thread.cc',
|
||||
'unix-system-mutex.cc',
|
||||
'unix-system-condition.cc',
|
||||
'unix-system-wall-clock-ms.cc',
|
||||
])
|
||||
|
||||
headers = bld.create_obj('ns3header')
|
||||
headers.module = 'core'
|
||||
headers.source = [
|
||||
'system-mutex.h',
|
||||
'system-thread.h',
|
||||
'system-condition.h',
|
||||
'system-wall-clock-ms.h',
|
||||
'empty.h',
|
||||
'callback.h',
|
||||
|
||||
Reference in New Issue
Block a user