X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fthreads%2FSGThread.cxx;h=8e5c3a36ac3e69243e8b5f3283aaddbe6db7f03a;hb=5af8bb7c8e259f5bdda67beb87adcc453e0b32e7;hp=0d6f304cc86a379a9c402283b4a4c4b97eb02ecd;hpb=3fdeea7f6533226df79a3d435df9f13996e6f474;p=simgear.git diff --git a/simgear/threads/SGThread.cxx b/simgear/threads/SGThread.cxx index 0d6f304c..8e5c3a36 100644 --- a/simgear/threads/SGThread.cxx +++ b/simgear/threads/SGThread.cxx @@ -1,107 +1,410 @@ +// 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. +// + +#ifdef HAVE_CONFIG_H +# include +#endif + #include -#if defined(_MSC_VER) || defined(__MINGW32__) -# include +#include "SGThread.hxx" + +#ifdef _WIN32 + +///////////////////////////////////////////////////////////////////////////// +/// win32 threads +///////////////////////////////////////////////////////////////////////////// + +#include +#include + +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(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, INFINITE); + 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::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::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 _waiters; + std::list _pool; +}; + +#else +///////////////////////////////////////////////////////////////////////////// +/// posix threads +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +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(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 -# if defined ( sgi ) && !defined( __GNUC__ ) - // This works arounf a bug triggered when using MipsPro 7.4.1 - // and (at least) IRIX 6.5.20 -# include -# endif -# include + struct timeval tv; + if (0 != gettimeofday(&tv, NULL)) + return false; + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; #endif -#if _MSC_VER >= 1300 -# include "winsock2.h" + + 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 -#include "SGThread.hxx" +SGThread::SGThread() : + _privateData(new PrivateData) +{ +} + +SGThread::~SGThread() +{ + delete _privateData; + _privateData = 0; +} -void* -start_handler( void* arg ) +bool +SGThread::start() { - SGThread* thr = static_cast(arg); - thr->run(); - return 0; + 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(); } -bool -SGMutex::trylock() +SGMutex::SGMutex() : + _privateData(new PrivateData) { - int status = pthread_mutex_lock( &mutex ); - if (status == EBUSY) - { - return false; - } - assert( status == 0 ); - return true; } -#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; +SGMutex::~SGMutex() +{ + delete _privateData; + _privateData = 0; } -#endif -bool -SGPthreadCond::wait( SGMutex& mutex, unsigned long ms ) +void +SGMutex::lock() { - struct timeval now; - ::gettimeofday( &now, 0 ); + _privateData->lock(); +} - // 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; +void +SGMutex::unlock() +{ + _privateData->unlock(); +} - int status = pthread_cond_timedwait( &cond, &mutex.mutex, &abstime ); - if (status == ETIMEDOUT) - { - return false; - } +SGWaitCondition::SGWaitCondition() : + _privateData(new PrivateData) +{ +} + +SGWaitCondition::~SGWaitCondition() +{ + delete _privateData; + _privateData = 0; +} - assert( status == 0 ); - return true; +void +SGWaitCondition::wait(SGMutex& mutex) +{ + _privateData->wait(*mutex._privateData); } +bool +SGWaitCondition::wait(SGMutex& mutex, unsigned msec) +{ + return _privateData->wait(*mutex._privateData, msec); +} + +void +SGWaitCondition::signal() +{ + _privateData->signal(); +} + +void +SGWaitCondition::broadcast() +{ + _privateData->broadcast(); +}