Merge branch 'next' of git.gitorious.org:fg/simgear into next
This commit is contained in:
commit
ed7f2df04e
@ -1487,6 +1487,14 @@
|
||||
RelativePath="..\..\simgear\threads\SGQueue.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\threads\SGThread.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\threads\SGThread.cxx"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Lib_sgstructure"
|
||||
|
@ -37,19 +37,20 @@ set(SOURCES
|
||||
simgear_component(io io "${SOURCES}" "${HEADERS}")
|
||||
|
||||
add_executable(test_sock socktest.cxx)
|
||||
target_link_libraries(test_sock sgio sgstructure sgdebug ${OPENTHREADS_LIBRARY})
|
||||
target_link_libraries(test_sock sgio sgstructure sgthreads sgdebug
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${RT_LIBRARY})
|
||||
|
||||
add_executable(test_http test_HTTP.cxx)
|
||||
target_link_libraries(test_http
|
||||
sgio sgstructure sgtiming sgmisc sgdebug
|
||||
${RT_LIBRARY}
|
||||
${OPENTHREADS_LIBRARY})
|
||||
sgio sgstructure sgthreads sgtiming sgmisc sgdebug
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${RT_LIBRARY})
|
||||
|
||||
add_test(http ${EXECUTABLE_OUTPUT_PATH}/test_http)
|
||||
|
||||
add_executable(httpget httpget.cxx)
|
||||
target_link_libraries(httpget
|
||||
sgio sgstructure sgtiming sgmisc sgdebug
|
||||
${RT_LIBRARY}
|
||||
${OPENTHREADS_LIBRARY})
|
||||
|
||||
sgio sgstructure sgthreads sgtiming sgmisc sgdebug
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${RT_LIBRARY})
|
||||
|
@ -61,21 +61,16 @@
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <OpenThreads/Thread>
|
||||
#include <OpenThreads/Mutex>
|
||||
#include <OpenThreads/Condition>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
|
||||
namespace {
|
||||
|
||||
class Resolver : public OpenThreads::Thread
|
||||
class Resolver : public SGThread
|
||||
{
|
||||
public:
|
||||
static Resolver* instance()
|
||||
{
|
||||
if (!static_instance) {
|
||||
OpenThreads::Thread::Init();
|
||||
|
||||
static_instance = new Resolver;
|
||||
atexit(&Resolver::cleanup);
|
||||
static_instance->start();
|
||||
@ -86,13 +81,21 @@ public:
|
||||
|
||||
static void cleanup()
|
||||
{
|
||||
static_instance->cancel();
|
||||
static_instance->shutdown();
|
||||
static_instance->join();
|
||||
}
|
||||
|
||||
Resolver()
|
||||
Resolver() :
|
||||
_done(false)
|
||||
{
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
// take the lock initially, thread will wait upon it once running
|
||||
_lock.lock();
|
||||
_done = true;
|
||||
_wait.signal();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
simgear::IPAddress* lookup(const string& host)
|
||||
@ -140,8 +143,8 @@ protected:
|
||||
*/
|
||||
virtual void run()
|
||||
{
|
||||
while (true) {
|
||||
_wait.wait(&_lock);
|
||||
_lock.lock();
|
||||
while (!_done) {
|
||||
AddressCache::iterator it;
|
||||
|
||||
for (it = _cache.begin(); it != _cache.end(); ++it) {
|
||||
@ -160,7 +163,9 @@ protected:
|
||||
_cache[h] = addr;
|
||||
} // of found un-resolved entry
|
||||
} // of un-resolved address iteration
|
||||
_wait.wait(_lock);
|
||||
} // of thread run loop
|
||||
_lock.unlock();
|
||||
}
|
||||
private:
|
||||
static Resolver* static_instance;
|
||||
@ -206,11 +211,12 @@ private:
|
||||
return ok;
|
||||
}
|
||||
|
||||
OpenThreads::Mutex _lock;
|
||||
OpenThreads::Condition _wait;
|
||||
SGMutex _lock;
|
||||
SGWaitCondition _wait;
|
||||
|
||||
typedef std::map<string, simgear::IPAddress*> AddressCache;
|
||||
AddressCache _cache;
|
||||
bool _done;
|
||||
};
|
||||
|
||||
Resolver* Resolver::static_instance = NULL;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "StringTable.hxx"
|
||||
|
||||
#include <OpenThreads/ScopedLock>
|
||||
#include <simgear/threads/SGGuard.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@ -8,8 +8,7 @@ using namespace std;
|
||||
|
||||
const string* StringTable::insert(const string& str)
|
||||
{
|
||||
using namespace OpenThreads;
|
||||
ScopedLock<Mutex> lock(_mutex);
|
||||
SGGuard<SGMutex> lock(_mutex);
|
||||
StringContainer::iterator it = _strings.insert(str).first;
|
||||
return &*it;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <OpenThreads/Mutex>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/identity.hpp>
|
||||
@ -21,7 +21,7 @@ class StringTable
|
||||
{
|
||||
const std::string* insert(const std::string& str);
|
||||
private:
|
||||
OpenThreads::Mutex _mutex;
|
||||
SGMutex _mutex;
|
||||
StringContainer _strings;
|
||||
};
|
||||
}
|
||||
|
@ -11,13 +11,12 @@
|
||||
#include <memory>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
#include <OpenThreads/Mutex>
|
||||
#include <OpenThreads/ScopedLock>
|
||||
|
||||
#include "commands.hxx"
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <simgear/threads/SGGuard.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
|
||||
@ -36,7 +35,7 @@ SGCommandMgr::~SGCommandMgr ()
|
||||
// no-op
|
||||
}
|
||||
|
||||
OpenThreads::Mutex SGCommandMgr::_instanceMutex;
|
||||
SGMutex SGCommandMgr::_instanceMutex;
|
||||
|
||||
SGCommandMgr*
|
||||
SGCommandMgr::instance()
|
||||
@ -45,7 +44,7 @@ SGCommandMgr::instance()
|
||||
if (mgr.get())
|
||||
return mgr.get();
|
||||
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_instanceMutex);
|
||||
SGGuard<SGMutex> lock(_instanceMutex);
|
||||
if (mgr.get())
|
||||
return mgr.get();
|
||||
|
||||
|
@ -17,8 +17,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <OpenThreads/Mutex>
|
||||
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <simgear/math/sg_types.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
@ -107,7 +106,7 @@ private:
|
||||
typedef std::map<std::string,command_t> command_map;
|
||||
command_map _commands;
|
||||
|
||||
static OpenThreads::Mutex _instanceMutex;
|
||||
static SGMutex _instanceMutex;
|
||||
|
||||
};
|
||||
|
||||
|
@ -5,9 +5,8 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <queue>
|
||||
#include <OpenThreads/Mutex>
|
||||
#include <OpenThreads/ScopedLock>
|
||||
#include <OpenThreads/Condition>
|
||||
#include "SGGuard.hxx"
|
||||
#include "SGThread.hxx"
|
||||
|
||||
/**
|
||||
* SGQueue defines an interface for a FIFO.
|
||||
@ -74,7 +73,7 @@ protected:
|
||||
/**
|
||||
* A simple thread safe queue. All access functions are guarded with a mutex.
|
||||
*/
|
||||
template<class T, class SGLOCK=OpenThreads::Mutex>
|
||||
template<class T>
|
||||
class SGLockedQueue : public SGQueue<T>
|
||||
{
|
||||
public:
|
||||
@ -95,7 +94,7 @@ public:
|
||||
* @return bool True if queue is empty, otherwisr false.
|
||||
*/
|
||||
virtual bool empty() {
|
||||
OpenThreads::ScopedLock<SGLOCK> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return this->fifo.empty();
|
||||
}
|
||||
|
||||
@ -105,7 +104,7 @@ public:
|
||||
* @param T object to add.
|
||||
*/
|
||||
virtual void push( const T& item ) {
|
||||
OpenThreads::ScopedLock<SGLOCK> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
this->fifo.push( item );
|
||||
}
|
||||
|
||||
@ -115,7 +114,7 @@ public:
|
||||
* @return T next available object.
|
||||
*/
|
||||
virtual T front() {
|
||||
OpenThreads::ScopedLock<SGLOCK> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
assert( ! this->fifo.empty() );
|
||||
T item = this->fifo.front();
|
||||
return item;
|
||||
@ -127,7 +126,7 @@ public:
|
||||
* @return T next available object.
|
||||
*/
|
||||
virtual T pop() {
|
||||
OpenThreads::ScopedLock<SGLOCK> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
//if (fifo.empty()) throw NoSuchElementException();
|
||||
assert( ! this->fifo.empty() );
|
||||
// if (fifo.empty())
|
||||
@ -146,7 +145,7 @@ public:
|
||||
* @return size_t size of queue.
|
||||
*/
|
||||
virtual size_t size() {
|
||||
OpenThreads::ScopedLock<SGLOCK> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return this->fifo.size();
|
||||
}
|
||||
|
||||
@ -155,7 +154,7 @@ private:
|
||||
/**
|
||||
* Mutex to serialise access.
|
||||
*/
|
||||
SGLOCK mutex;
|
||||
SGMutex mutex;
|
||||
|
||||
private:
|
||||
// Prevent copying.
|
||||
@ -185,7 +184,7 @@ public:
|
||||
*
|
||||
*/
|
||||
virtual bool empty() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return this->fifo.empty();
|
||||
}
|
||||
|
||||
@ -195,7 +194,7 @@ public:
|
||||
* @param T object to add.
|
||||
*/
|
||||
virtual void push( const T& item ) {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
this->fifo.push( item );
|
||||
not_empty.signal();
|
||||
}
|
||||
@ -207,7 +206,7 @@ public:
|
||||
* @return T next available object.
|
||||
*/
|
||||
virtual T front() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
|
||||
assert(this->fifo.empty() != true);
|
||||
//if (fifo.empty()) throw ??
|
||||
@ -223,10 +222,10 @@ public:
|
||||
* @return T next available object.
|
||||
*/
|
||||
virtual T pop() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
|
||||
while (this->fifo.empty())
|
||||
not_empty.wait(&mutex);
|
||||
not_empty.wait(mutex);
|
||||
|
||||
assert(this->fifo.empty() != true);
|
||||
//if (fifo.empty()) throw ??
|
||||
@ -242,7 +241,7 @@ public:
|
||||
* @return size_t size of queue.
|
||||
*/
|
||||
virtual size_t size() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return this->fifo.size();
|
||||
}
|
||||
|
||||
@ -251,12 +250,12 @@ private:
|
||||
/**
|
||||
* Mutex to serialise access.
|
||||
*/
|
||||
OpenThreads::Mutex mutex;
|
||||
SGMutex mutex;
|
||||
|
||||
/**
|
||||
* Condition to signal when queue not empty.
|
||||
*/
|
||||
OpenThreads::Condition not_empty;
|
||||
SGWaitCondition not_empty;
|
||||
|
||||
private:
|
||||
// Prevent copying.
|
||||
@ -287,7 +286,7 @@ public:
|
||||
*
|
||||
*/
|
||||
virtual void clear() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
this->queue.clear();
|
||||
}
|
||||
|
||||
@ -295,7 +294,7 @@ public:
|
||||
*
|
||||
*/
|
||||
virtual bool empty() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return this->queue.empty();
|
||||
}
|
||||
|
||||
@ -305,7 +304,7 @@ public:
|
||||
* @param T object to add.
|
||||
*/
|
||||
virtual void push_front( const T& item ) {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
this->queue.push_front( item );
|
||||
not_empty.signal();
|
||||
}
|
||||
@ -316,7 +315,7 @@ public:
|
||||
* @param T object to add.
|
||||
*/
|
||||
virtual void push_back( const T& item ) {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
this->queue.push_back( item );
|
||||
not_empty.signal();
|
||||
}
|
||||
@ -328,7 +327,7 @@ public:
|
||||
* @return T next available object.
|
||||
*/
|
||||
virtual T front() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
|
||||
assert(this->queue.empty() != true);
|
||||
//if (queue.empty()) throw ??
|
||||
@ -344,10 +343,10 @@ public:
|
||||
* @return T next available object.
|
||||
*/
|
||||
virtual T pop_front() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
|
||||
while (this->queue.empty())
|
||||
not_empty.wait(&mutex);
|
||||
not_empty.wait(mutex);
|
||||
|
||||
assert(this->queue.empty() != true);
|
||||
//if (queue.empty()) throw ??
|
||||
@ -364,10 +363,10 @@ public:
|
||||
* @return T next available object.
|
||||
*/
|
||||
virtual T pop_back() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
|
||||
while (this->queue.empty())
|
||||
not_empty.wait(&mutex);
|
||||
not_empty.wait(mutex);
|
||||
|
||||
assert(this->queue.empty() != true);
|
||||
//if (queue.empty()) throw ??
|
||||
@ -383,7 +382,7 @@ public:
|
||||
* @return size_t size of queue.
|
||||
*/
|
||||
virtual size_t size() {
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> g(mutex);
|
||||
SGGuard<SGMutex> g(mutex);
|
||||
return this->queue.size();
|
||||
}
|
||||
|
||||
@ -392,12 +391,12 @@ private:
|
||||
/**
|
||||
* Mutex to serialise access.
|
||||
*/
|
||||
OpenThreads::Mutex mutex;
|
||||
SGMutex mutex;
|
||||
|
||||
/**
|
||||
* Condition to signal when queue not empty.
|
||||
*/
|
||||
OpenThreads::Condition not_empty;
|
||||
SGWaitCondition not_empty;
|
||||
|
||||
private:
|
||||
// Prevent copying.
|
||||
|
@ -1,107 +1,410 @@
|
||||
#include <simgear/compiler.h>
|
||||
// SGThread - Simple pthread class wrappers.
|
||||
//
|
||||
// Written by Bernie Bright, started April 2001.
|
||||
//
|
||||
// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
|
||||
// Copyright (C) 2011 Mathias Froehlich
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
# include <time.h>
|
||||
#else
|
||||
# if defined ( sgi ) && !defined( __GNUC__ )
|
||||
// This works around a bug triggered when using MipsPro 7.4.1
|
||||
// and (at least) IRIX 6.5.20
|
||||
# include <iostream>
|
||||
# endif
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
#if _MSC_VER >= 1300
|
||||
# include <winsock2.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "SGThread.hxx"
|
||||
|
||||
void*
|
||||
start_handler( void* arg )
|
||||
#ifdef _WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// win32 threads
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <list>
|
||||
#include <windows.h>
|
||||
|
||||
struct SGThread::PrivateData {
|
||||
PrivateData() :
|
||||
_handle(INVALID_HANDLE_VALUE)
|
||||
{
|
||||
}
|
||||
~PrivateData()
|
||||
{
|
||||
if (_handle == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
CloseHandle(_handle);
|
||||
_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static DWORD WINAPI start_routine(LPVOID data)
|
||||
{
|
||||
SGThread* thread = reinterpret_cast<SGThread*>(data);
|
||||
thread->run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool start(SGThread& thread)
|
||||
{
|
||||
if (_handle != INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
_handle = CreateThread(0, 0, start_routine, &thread, 0, 0);
|
||||
if (_handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void join()
|
||||
{
|
||||
if (_handle == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
DWORD ret = WaitForSingleObject(_handle, 0);
|
||||
if (ret != WAIT_OBJECT_0)
|
||||
return;
|
||||
CloseHandle(_handle);
|
||||
_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
HANDLE _handle;
|
||||
};
|
||||
|
||||
struct SGMutex::PrivateData {
|
||||
PrivateData()
|
||||
{
|
||||
InitializeCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
DeleteCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
|
||||
}
|
||||
|
||||
void lock(void)
|
||||
{
|
||||
EnterCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
|
||||
}
|
||||
|
||||
void unlock(void)
|
||||
{
|
||||
LeaveCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
|
||||
}
|
||||
|
||||
CRITICAL_SECTION _criticalSection;
|
||||
};
|
||||
|
||||
struct SGWaitCondition::PrivateData {
|
||||
~PrivateData(void)
|
||||
{
|
||||
// The waiters list should be empty anyway
|
||||
_mutex.lock();
|
||||
while (!_pool.empty()) {
|
||||
CloseHandle(_pool.front());
|
||||
_pool.pop_front();
|
||||
}
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
void signal(void)
|
||||
{
|
||||
_mutex.lock();
|
||||
if (!_waiters.empty())
|
||||
SetEvent(_waiters.back());
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
void broadcast(void)
|
||||
{
|
||||
_mutex.lock();
|
||||
for (std::list<HANDLE>::iterator i = _waiters.begin(); i != _waiters.end(); ++i)
|
||||
SetEvent(*i);
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
bool wait(SGMutex::PrivateData& externalMutex, DWORD msec)
|
||||
{
|
||||
_mutex.lock();
|
||||
if (_pool.empty())
|
||||
_waiters.push_front(CreateEvent(NULL, FALSE, FALSE, NULL));
|
||||
else
|
||||
_waiters.splice(_waiters.begin(), _pool, _pool.begin());
|
||||
std::list<HANDLE>::iterator i = _waiters.begin();
|
||||
_mutex.unlock();
|
||||
|
||||
externalMutex.unlock();
|
||||
|
||||
DWORD result = WaitForSingleObject(*i, msec);
|
||||
|
||||
externalMutex.lock();
|
||||
|
||||
_mutex.lock();
|
||||
if (result != WAIT_OBJECT_0)
|
||||
result = WaitForSingleObject(*i, 0);
|
||||
_pool.splice(_pool.begin(), _waiters, i);
|
||||
_mutex.unlock();
|
||||
|
||||
return result == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
void wait(SGMutex::PrivateData& externalMutex)
|
||||
{
|
||||
wait(externalMutex, INFINITE);
|
||||
}
|
||||
|
||||
// Protect the list of waiters
|
||||
SGMutex::PrivateData _mutex;
|
||||
|
||||
std::list<HANDLE> _waiters;
|
||||
std::list<HANDLE> _pool;
|
||||
};
|
||||
|
||||
#else
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// posix threads
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <pthread.h>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct SGThread::PrivateData {
|
||||
PrivateData() :
|
||||
_started(false)
|
||||
{
|
||||
}
|
||||
~PrivateData()
|
||||
{
|
||||
// If we are still having a started thread and nobody waited,
|
||||
// now detach ...
|
||||
if (!_started)
|
||||
return;
|
||||
pthread_detach(_thread);
|
||||
}
|
||||
|
||||
static void *start_routine(void* data)
|
||||
{
|
||||
SGThread* thread = reinterpret_cast<SGThread*>(data);
|
||||
thread->run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool start(SGThread& thread)
|
||||
{
|
||||
if (_started)
|
||||
return false;
|
||||
|
||||
int ret = pthread_create(&_thread, 0, start_routine, &thread);
|
||||
if (0 != ret)
|
||||
return false;
|
||||
|
||||
_started = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void join()
|
||||
{
|
||||
if (!_started)
|
||||
return;
|
||||
|
||||
pthread_join(_thread, 0);
|
||||
_started = false;
|
||||
}
|
||||
|
||||
pthread_t _thread;
|
||||
bool _started;
|
||||
};
|
||||
|
||||
struct SGMutex::PrivateData {
|
||||
PrivateData()
|
||||
{
|
||||
int err = pthread_mutex_init(&_mutex, 0);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
int err = pthread_mutex_destroy(&_mutex);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
void lock(void)
|
||||
{
|
||||
int err = pthread_mutex_lock(&_mutex);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
void unlock(void)
|
||||
{
|
||||
int err = pthread_mutex_unlock(&_mutex);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
pthread_mutex_t _mutex;
|
||||
};
|
||||
|
||||
struct SGWaitCondition::PrivateData {
|
||||
PrivateData(void)
|
||||
{
|
||||
int err = pthread_cond_init(&_condition, NULL);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
~PrivateData(void)
|
||||
{
|
||||
int err = pthread_cond_destroy(&_condition);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
void signal(void)
|
||||
{
|
||||
int err = pthread_cond_signal(&_condition);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
void broadcast(void)
|
||||
{
|
||||
int err = pthread_cond_broadcast(&_condition);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
void wait(SGMutex::PrivateData& mutex)
|
||||
{
|
||||
int err = pthread_cond_wait(&_condition, &mutex._mutex);
|
||||
assert(err == 0);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
bool wait(SGMutex::PrivateData& mutex, unsigned msec)
|
||||
{
|
||||
struct timespec ts;
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
if (0 != clock_gettime(CLOCK_REALTIME, &ts))
|
||||
return false;
|
||||
#else
|
||||
struct timeval tv;
|
||||
if (0 != gettimeofday(&tv, NULL))
|
||||
return false;
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
#endif
|
||||
|
||||
ts.tv_nsec += 1000000*(msec % 1000);
|
||||
if (1000000000 <= ts.tv_nsec) {
|
||||
ts.tv_nsec -= 1000000000;
|
||||
ts.tv_sec += 1;
|
||||
}
|
||||
ts.tv_sec += msec / 1000;
|
||||
|
||||
int evalue = pthread_cond_timedwait(&_condition, &mutex._mutex, &ts);
|
||||
if (evalue == 0)
|
||||
return true;
|
||||
|
||||
assert(evalue == ETIMEDOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_cond_t _condition;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
SGThread::SGThread() :
|
||||
_privateData(new PrivateData)
|
||||
{
|
||||
SGThread* thr = static_cast<SGThread*>(arg);
|
||||
thr->run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SGThread::~SGThread()
|
||||
{
|
||||
delete _privateData;
|
||||
_privateData = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
SGThread::start()
|
||||
{
|
||||
return _privateData->start(*this);
|
||||
}
|
||||
|
||||
void
|
||||
SGThread::set_cancel( cancel_t mode )
|
||||
SGThread::join()
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CANCEL_DISABLE:
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, 0 );
|
||||
break;
|
||||
case CANCEL_DEFERRED:
|
||||
pthread_setcanceltype( PTHREAD_CANCEL_DEFERRED, 0 );
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, 0 );
|
||||
break;
|
||||
case CANCEL_IMMEDIATE:
|
||||
pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, 0 );
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, 0 );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_privateData->join();
|
||||
}
|
||||
|
||||
SGMutex::SGMutex() :
|
||||
_privateData(new PrivateData)
|
||||
{
|
||||
}
|
||||
|
||||
SGMutex::~SGMutex()
|
||||
{
|
||||
delete _privateData;
|
||||
_privateData = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SGMutex::lock()
|
||||
{
|
||||
_privateData->lock();
|
||||
}
|
||||
|
||||
void
|
||||
SGMutex::unlock()
|
||||
{
|
||||
_privateData->unlock();
|
||||
}
|
||||
|
||||
SGWaitCondition::SGWaitCondition() :
|
||||
_privateData(new PrivateData)
|
||||
{
|
||||
}
|
||||
|
||||
SGWaitCondition::~SGWaitCondition()
|
||||
{
|
||||
delete _privateData;
|
||||
_privateData = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SGWaitCondition::wait(SGMutex& mutex)
|
||||
{
|
||||
_privateData->wait(*mutex._privateData);
|
||||
}
|
||||
|
||||
bool
|
||||
SGMutex::trylock()
|
||||
SGWaitCondition::wait(SGMutex& mutex, unsigned msec)
|
||||
{
|
||||
int status = pthread_mutex_lock( &mutex );
|
||||
if (status == EBUSY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
assert( status == 0 );
|
||||
return true;
|
||||
return _privateData->wait(*mutex._privateData, msec);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
int gettimeofday(struct timeval* tp, void* tzp) {
|
||||
LARGE_INTEGER t;
|
||||
|
||||
if(QueryPerformanceCounter(&t)) {
|
||||
/* hardware supports a performance counter */
|
||||
LARGE_INTEGER f;
|
||||
QueryPerformanceFrequency(&f);
|
||||
tp->tv_sec = t.QuadPart/f.QuadPart;
|
||||
tp->tv_usec = ((float)t.QuadPart/f.QuadPart*1000*1000)
|
||||
- (tp->tv_sec*1000*1000);
|
||||
} else {
|
||||
/* hardware doesn't support a performance counter, so get the
|
||||
time in a more traditional way. */
|
||||
DWORD t;
|
||||
t = timeGetTime();
|
||||
tp->tv_sec = t / 1000;
|
||||
tp->tv_usec = t % 1000;
|
||||
}
|
||||
|
||||
/* 0 indicates that the call succeeded. */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
SGPthreadCond::wait( SGMutex& mutex, unsigned long ms )
|
||||
void
|
||||
SGWaitCondition::signal()
|
||||
{
|
||||
struct timeval now;
|
||||
::gettimeofday( &now, 0 );
|
||||
|
||||
// Wait time is now + ms milliseconds
|
||||
unsigned int sec = ms / 1000;
|
||||
unsigned int nsec = (ms % 1000) * 1000;
|
||||
struct timespec abstime;
|
||||
abstime.tv_sec = now.tv_sec + sec;
|
||||
abstime.tv_nsec = now.tv_usec*1000 + nsec;
|
||||
|
||||
int status = pthread_cond_timedwait( &cond, &mutex.mutex, &abstime );
|
||||
if (status == ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
assert( status == 0 );
|
||||
return true;
|
||||
_privateData->signal();
|
||||
}
|
||||
|
||||
void
|
||||
SGWaitCondition::broadcast()
|
||||
{
|
||||
_privateData->broadcast();
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Written by Bernie Bright, started April 2001.
|
||||
//
|
||||
// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
|
||||
// Copyright (C) 2011 Mathias Froehlich
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
@ -18,41 +19,18 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef SGTHREAD_HXX_INCLUDED
|
||||
#define SGTHREAD_HXX_INCLUDED 1
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
|
||||
class SGThread;
|
||||
|
||||
extern "C" {
|
||||
void* start_handler( void* );
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulate generic threading methods.
|
||||
* Users derive a class from SGThread and implement the run() member function.
|
||||
*/
|
||||
class SGThread
|
||||
{
|
||||
class SGThread {
|
||||
public:
|
||||
/**
|
||||
* SGThread cancelation modes.
|
||||
*/
|
||||
enum cancel_t
|
||||
{
|
||||
CANCEL_DISABLE = 0,
|
||||
CANCEL_DEFERRED,
|
||||
CANCEL_IMMEDIATE
|
||||
};
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a new thread object.
|
||||
* When a SGThread object is created it does not begin execution
|
||||
@ -62,18 +40,9 @@ public:
|
||||
|
||||
/**
|
||||
* Start the underlying thread of execution.
|
||||
* @param cpu An optional parameter to specify on which CPU to run this
|
||||
* thread (only supported on IRIX at this time).
|
||||
* @return Pthread error code if execution fails, otherwise returns 0.
|
||||
*/
|
||||
int start( unsigned cpu = 0 );
|
||||
|
||||
/**
|
||||
* Sends a cancellation request to the underlying thread. The target
|
||||
* thread will either ignore the request, honor it immediately or defer
|
||||
* it until it reaches a cancellation point.
|
||||
*/
|
||||
void cancel();
|
||||
bool start();
|
||||
|
||||
/**
|
||||
* Suspends the exection of the calling thread until this thread
|
||||
@ -89,82 +58,31 @@ protected:
|
||||
*/
|
||||
virtual ~SGThread();
|
||||
|
||||
/**
|
||||
* Set the threads cancellation mode.
|
||||
* @param mode The required cancellation mode.
|
||||
*/
|
||||
void set_cancel( cancel_t mode );
|
||||
|
||||
/**
|
||||
* All threads execute by deriving the run() method of SGThread.
|
||||
* If this function terminates then the thread also terminates.
|
||||
*/
|
||||
virtual void run() = 0;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Pthread thread identifier.
|
||||
*/
|
||||
pthread_t tid;
|
||||
|
||||
friend void* start_handler( void* );
|
||||
|
||||
private:
|
||||
// Disable copying.
|
||||
SGThread( const SGThread& );
|
||||
SGThread& operator=( const SGThread& );
|
||||
SGThread(const SGThread&);
|
||||
SGThread& operator=(const SGThread&);
|
||||
|
||||
struct PrivateData;
|
||||
PrivateData* _privateData;
|
||||
|
||||
friend struct PrivateData;
|
||||
};
|
||||
|
||||
inline
|
||||
SGThread::SGThread()
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
SGThread::~SGThread()
|
||||
{
|
||||
}
|
||||
|
||||
inline int
|
||||
SGThread::start( unsigned cpu )
|
||||
{
|
||||
int status = pthread_create( &tid, 0, start_handler, this );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
#if defined( sgi )
|
||||
if ( !status && !cpu )
|
||||
pthread_setrunon_np( cpu );
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
inline void
|
||||
SGThread::join()
|
||||
{
|
||||
int status = pthread_join( tid, 0 );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline void
|
||||
SGThread::cancel()
|
||||
{
|
||||
int status = pthread_cancel( tid );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
class SGWaitCondition;
|
||||
|
||||
/**
|
||||
* A mutex is used to protect a section of code such that at any time
|
||||
* only a single thread can execute the code.
|
||||
*/
|
||||
class SGMutex
|
||||
{
|
||||
friend class SGPthreadCond;
|
||||
|
||||
class SGMutex {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a new mutex.
|
||||
* Under Linux this is a 'fast' mutex.
|
||||
@ -186,86 +104,46 @@ public:
|
||||
* mutex is already locked and owned by the calling thread, the calling
|
||||
* thread is suspended until the mutex is unlocked, effectively causing
|
||||
* the calling thread to deadlock.
|
||||
*
|
||||
* @see SGMutex::trylock
|
||||
*/
|
||||
void lock();
|
||||
|
||||
/**
|
||||
* Try to lock the mutex for the current thread. Behaves like lock except
|
||||
* that it doesn't block the calling thread.
|
||||
* @return true if mutex was successfully locked, otherwise false.
|
||||
* @see SGMutex::lock
|
||||
*/
|
||||
bool trylock();
|
||||
|
||||
/**
|
||||
* Unlock this mutex.
|
||||
* It is assumed that the mutex is locked and owned by the calling thread.
|
||||
*/
|
||||
void unlock();
|
||||
|
||||
protected:
|
||||
private:
|
||||
struct PrivateData;
|
||||
PrivateData* _privateData;
|
||||
|
||||
/**
|
||||
* Pthread mutex.
|
||||
*/
|
||||
pthread_mutex_t mutex;
|
||||
friend class SGWaitCondition;
|
||||
};
|
||||
|
||||
inline SGMutex::SGMutex()
|
||||
{
|
||||
int status = pthread_mutex_init( &mutex, 0 );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline SGMutex::~SGMutex()
|
||||
{
|
||||
int status = pthread_mutex_destroy( &mutex );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline void SGMutex::lock()
|
||||
{
|
||||
int status = pthread_mutex_lock( &mutex );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline void SGMutex::unlock()
|
||||
{
|
||||
int status = pthread_mutex_unlock( &mutex );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
/**
|
||||
* A condition variable is a synchronization device that allows threads to
|
||||
* suspend execution until some predicate on shared data is satisfied.
|
||||
* A condition variable is always associated with a mutex to avoid race
|
||||
* conditions.
|
||||
*/
|
||||
class SGPthreadCond
|
||||
{
|
||||
class SGWaitCondition {
|
||||
public:
|
||||
/**
|
||||
* Create a new condition variable.
|
||||
*/
|
||||
SGPthreadCond();
|
||||
SGWaitCondition();
|
||||
|
||||
/**
|
||||
* Destroy the condition object.
|
||||
*/
|
||||
~SGPthreadCond();
|
||||
~SGWaitCondition();
|
||||
|
||||
/**
|
||||
* Wait for this condition variable to be signaled.
|
||||
*
|
||||
* @param SGMutex& reference to a locked mutex.
|
||||
*/
|
||||
void wait( SGMutex& );
|
||||
void wait(SGMutex&);
|
||||
|
||||
/**
|
||||
* Wait for this condition variable to be signaled for at most
|
||||
@ -276,7 +154,7 @@ public:
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
bool wait( SGMutex& mutex, unsigned long ms );
|
||||
bool wait(SGMutex& mutex, unsigned msec);
|
||||
|
||||
/**
|
||||
* Wake one thread waiting on this condition variable.
|
||||
@ -294,50 +172,11 @@ public:
|
||||
|
||||
private:
|
||||
// Disable copying.
|
||||
SGPthreadCond(const SGPthreadCond& );
|
||||
SGPthreadCond& operator=(const SGPthreadCond& );
|
||||
SGWaitCondition(const SGWaitCondition&);
|
||||
SGWaitCondition& operator=(const SGWaitCondition&);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* The Pthread conditon variable.
|
||||
*/
|
||||
pthread_cond_t cond;
|
||||
struct PrivateData;
|
||||
PrivateData* _privateData;
|
||||
};
|
||||
|
||||
inline SGPthreadCond::SGPthreadCond()
|
||||
{
|
||||
int status = pthread_cond_init( &cond, 0 );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline SGPthreadCond::~SGPthreadCond()
|
||||
{
|
||||
int status = pthread_cond_destroy( &cond );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline void SGPthreadCond::signal()
|
||||
{
|
||||
int status = pthread_cond_signal( &cond );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline void SGPthreadCond::broadcast()
|
||||
{
|
||||
int status = pthread_cond_broadcast( &cond );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
inline void SGPthreadCond::wait( SGMutex& mutex )
|
||||
{
|
||||
int status = pthread_cond_wait( &cond, &mutex.mutex );
|
||||
assert( status == 0 );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
#endif /* SGTHREAD_HXX_INCLUDED */
|
||||
|
Loading…
Reference in New Issue
Block a user