From 2325055b5b5f8bae65418fb134f44b718f3c17c4 Mon Sep 17 00:00:00 2001 From: holoeye-photonics Date: Wed, 26 Apr 2017 14:15:47 +0200 Subject: [PATCH 1/2] The oxygine engine uses POSIX threads under Windows which is a handy library but sadly under LGPL so we cannot link it statically. Since C++ 11 there are official implementations std::mutex, std::thread and std::conditional_variable. So I put those in which gets rid of POSIX threads under Windows which resolves our licensing issue. There is a define OX_CPP11THREADS that needs to be set in order to enable the use of the stdlib classes. --- oxygine/src/ThreadLoader.cpp | 14 ++++- oxygine/src/ThreadLoader.h | 15 ++++- oxygine/src/core/Mutex.cpp | 71 ++++++++++++++++----- oxygine/src/core/Mutex.h | 43 ++++++++++++- oxygine/src/core/ThreadDispatcher.cpp | 75 ++++++++++++++++++++++- oxygine/src/core/ThreadDispatcher.h | 31 +++++++++- oxygine/src/core/ZipFileSystem.cpp | 20 +++--- oxygine/src/core/ZipFileSystem.h | 4 +- oxygine/src/core/oxygine.cpp | 18 +++++- oxygine/src/res/CreateResourceContext.cpp | 5 +- 10 files changed, 258 insertions(+), 38 deletions(-) diff --git a/oxygine/src/ThreadLoader.cpp b/oxygine/src/ThreadLoader.cpp index 4e887ed77..8eddf6e3b 100644 --- a/oxygine/src/ThreadLoader.cpp +++ b/oxygine/src/ThreadLoader.cpp @@ -7,14 +7,23 @@ namespace oxygine { +#if OX_CPP11THREADS + ThreadLoader::ThreadLoader(): _thread(_staticThreadFunc, this), _threadDone(false) +#else ThreadLoader::ThreadLoader(): _thread(pthread_self()), _threadDone(false) +#endif { } ThreadLoader::~ThreadLoader() { +#if OX_CPP11THREADS + if(_thread.get_id() != std::this_thread::get_id()) + _thread.join(); +#else if (!pthread_equal(_thread, pthread_self())) pthread_join(_thread, 0); +#endif } @@ -122,11 +131,12 @@ namespace oxygine _load(); getStage()->addTween(TweenDummy(), 100)->addDoneCallback(CLOSURE(this, &ThreadLoader::loaded)); #else - + #if !OX_CPP11THREADS pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_create(&_thread, &attr, _staticThreadFunc, this); + #endif #endif } -} \ No newline at end of file +} diff --git a/oxygine/src/ThreadLoader.h b/oxygine/src/ThreadLoader.h index 103dc3c8a..7c7f0469b 100644 --- a/oxygine/src/ThreadLoader.h +++ b/oxygine/src/ThreadLoader.h @@ -1,7 +1,13 @@ #pragma once #include "oxygine-include.h" #include "EventDispatcher.h" -#include "pthread.h" + +#if OX_CPP11THREADS + #include +#else + #include "pthread.h" +#endif + #include "core/ThreadDispatcher.h" #include #include "Event.h" @@ -44,7 +50,12 @@ namespace oxygine void loaded(Event*); void _load(); +#if OX_CPP11THREADS + std::thread _thread; +#else pthread_t _thread; +#endif + volatile bool _threadDone; typedef std::list resources; @@ -58,4 +69,4 @@ namespace oxygine funcs _funcs; #endif }; -} \ No newline at end of file +} diff --git a/oxygine/src/core/Mutex.cpp b/oxygine/src/core/Mutex.cpp index 212370775..dce1535cb 100644 --- a/oxygine/src/core/Mutex.cpp +++ b/oxygine/src/core/Mutex.cpp @@ -1,38 +1,79 @@ #include "Mutex.h" #include "ox_debug.h" -#include "pthread.h" +#if OX_CPP11THREADS + #include +#else + #include "pthread.h" +#endif namespace oxygine { - Mutex::Mutex(bool recursive) + Mutex::Mutex() { - if (recursive) - { - pthread_mutexattr_t mta; - pthread_mutexattr_init(&mta); - pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); - - pthread_mutex_init(&_handle, &mta); - } - else - { - pthread_mutex_init(&_handle, 0); - } +#if !OX_CPP11THREADS + pthread_mutex_init(&_handle, 0); +#endif } Mutex::~Mutex() { +#if !OX_CPP11THREADS pthread_mutex_destroy(&_handle); +#endif } void Mutex::lock() { +#if OX_CPP11THREADS + _mutex.lock(); +#else pthread_mutex_lock(&_handle); +#endif } void Mutex::unlock() { +#if OX_CPP11THREADS + _mutex.unlock(); +#else + pthread_mutex_unlock(&_handle); +#endif + } + + MutexRecursive::MutexRecursive() + { +#if !OX_CPP11THREADS + pthread_mutexattr_t mta; + pthread_mutexattr_init(&mta); + pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_init(&_handle, &mta); +#endif + } + + MutexRecursive::~MutexRecursive() + { +#if !OX_CPP11THREADS + pthread_mutex_destroy(&_handle); +#endif + } + + void MutexRecursive::lock() + { +#if OX_CPP11THREADS + _mutex.lock(); +#else + pthread_mutex_lock(&_handle); +#endif + } + + void MutexRecursive::unlock() + { +#if OX_CPP11THREADS + _mutex.unlock(); +#else pthread_mutex_unlock(&_handle); +#endif } -} \ No newline at end of file +} diff --git a/oxygine/src/core/Mutex.h b/oxygine/src/core/Mutex.h index b99bb7930..86b86e78b 100644 --- a/oxygine/src/core/Mutex.h +++ b/oxygine/src/core/Mutex.h @@ -1,18 +1,24 @@ #pragma once #include "oxygine-include.h" +#if OX_CPP11THREADS + #include +#else + #if defined(_WIN32) && !defined(__MINGW32__) typedef struct pthread_mutex_t_* pthread_mutex_t; #else # include "pthread.h" #endif +#endif + namespace oxygine { class Mutex { public: - Mutex(bool recursive = false); + Mutex(); ~Mutex(); void lock(); @@ -22,8 +28,33 @@ namespace oxygine Mutex(const Mutex&) {} void operator = (const Mutex&) {} +#if OX_CPP11THREADS + std::mutex _mutex; +#else + pthread_mutex_t _handle; + //void *_handle; +#endif + }; + + class MutexRecursive + { + public: + MutexRecursive(); + ~MutexRecursive(); + + void lock(); + void unlock(); + + private: + MutexRecursive(const MutexRecursive&) {} + void operator = (const MutexRecursive&) {} + +#if OX_CPP11THREADS + std::recursive_mutex _mutex; +#else pthread_mutex_t _handle; //void *_handle; +#endif }; class MutexAutoLock @@ -35,4 +66,14 @@ namespace oxygine private: Mutex& _m; }; + + class MutexRecursiveAutoLock + { + public: + MutexRecursiveAutoLock(MutexRecursive& m): _m(m) {_m.lock();} + ~MutexRecursiveAutoLock() {_m.unlock();} + + private: + MutexRecursive& _m; + }; } diff --git a/oxygine/src/core/ThreadDispatcher.cpp b/oxygine/src/core/ThreadDispatcher.cpp index e987aa876..2176feb1c 100644 --- a/oxygine/src/core/ThreadDispatcher.cpp +++ b/oxygine/src/core/ThreadDispatcher.cpp @@ -1,6 +1,10 @@ #include "ThreadDispatcher.h" #include "log.h" -#include "pthread.h" + +#if !OX_CPP11THREADS + #include "pthread.h" +#endif + #include "Mutex.h" namespace oxygine @@ -18,7 +22,21 @@ namespace oxygine #endif +#if OX_CPP11THREADS + MutexPthreadLock::MutexPthreadLock(std::unique_lock& l, bool lock) : _lock(l), _locked(false) + { + if(lock && !_lock.owns_lock()) + { + _lock.lock(); + _locked = true; + } + } + MutexPthreadLock::~MutexPthreadLock() + { + _lock.unlock(); + } +#else MutexPthreadLock::MutexPthreadLock(pthread_mutex_t& m, bool lock) : _mutex(m), _locked(lock) { if (_locked) @@ -29,10 +47,16 @@ namespace oxygine { pthread_mutex_unlock(&_mutex); } +#endif +#if OX_CPP11THREADS + ThreadDispatcher::ThreadDispatcher(): _mutex(_mutexInternal), _id(0), _result(0) +#else ThreadDispatcher::ThreadDispatcher(): _id(0), _result(0) +#endif { #ifndef OX_NO_MT + #if !OX_CPP11THREADS pthread_cond_init(&_cond, 0); pthread_mutexattr_t attr; @@ -40,6 +64,7 @@ namespace oxygine pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&_mutex, &attr); + #endif #endif _events.reserve(10); } @@ -47,8 +72,15 @@ namespace oxygine ThreadDispatcher::~ThreadDispatcher() { #ifndef OX_NO_MT + #if OX_CPP11THREADS + if(_mutex.owns_lock()) + _mutex.unlock(); + + //_cond.notify_all(); + #else pthread_mutex_destroy(&_mutex); pthread_cond_destroy(&_cond); + #endif #endif } @@ -58,7 +90,11 @@ namespace oxygine _replyLast(0); while (_events.empty()) + #if OX_CPP11THREADS + _cond.wait(_mutex); + #else pthread_cond_wait(&_cond, &_mutex); + #endif #endif } @@ -191,10 +227,19 @@ namespace oxygine LOGDN("replying to id=%d", _last._id); #ifndef OX_NO_MT + #if OX_CPP11THREADS + _cond.notify_all(); + #else //pthread_cond_signal(&_cond); pthread_cond_broadcast(&_cond); + #endif #endif + +#if OX_CPP11THREADS + _cond.wait(_mutex); +#else pthread_cond_wait(&_cond, &_mutex); +#endif } } @@ -206,15 +251,28 @@ namespace oxygine { LOGDN("ThreadMessages::waiting reply... _replyingTo=%d myid=%d", _replyingTo, id); #ifndef OX_NO_MT + #if OX_CPP11THREADS + _cond.notify_one(); + #else pthread_cond_signal(&_cond); + #endif #endif + +#if OX_CPP11THREADS + _cond.wait(_mutex); +#else pthread_cond_wait(&_cond, &_mutex); +#endif } while (_replyingTo != id); _last.need_reply = false; #ifndef OX_NO_MT + #if OX_CPP11THREADS + _cond.notify_one(); + #else pthread_cond_signal(&_cond); + #endif #endif } @@ -281,7 +339,11 @@ namespace oxygine msg._id = ++_id; _events.push_back(msg); #ifndef OX_NO_MT + #if OX_CPP11THREADS + _cond.notify_one(); + #else pthread_cond_signal(&_cond); + #endif #endif } @@ -367,11 +429,20 @@ namespace oxygine std::vector& ThreadDispatcher::lockMessages() { +#if OX_CPP11THREADS + _mutex.lock(); +#else pthread_mutex_lock(&_mutex); +#endif + return _events; } void ThreadDispatcher::unlockMessages() { +#if OX_CPP11THREADS + _mutex.unlock(); +#else pthread_mutex_unlock(&_mutex); +#endif } -} \ No newline at end of file +} diff --git a/oxygine/src/core/ThreadDispatcher.h b/oxygine/src/core/ThreadDispatcher.h index 91198a71f..125baa848 100644 --- a/oxygine/src/core/ThreadDispatcher.h +++ b/oxygine/src/core/ThreadDispatcher.h @@ -3,6 +3,11 @@ #include #include +#if OX_CPP11THREADS + #include + #include +#else + #if defined(_WIN32) && !defined(__MINGW32__) typedef struct pthread_mutex_t_* pthread_mutex_t; typedef struct pthread_cond_t_* pthread_cond_t; @@ -10,8 +15,22 @@ typedef struct pthread_cond_t_* pthread_cond_t; # include "pthread.h" #endif +#endif + namespace oxygine { +#if OX_CPP11THREADS + class MutexPthreadLock + { + public: + MutexPthreadLock(std::unique_lock& l, bool lock = true); + ~MutexPthreadLock(); + + protected: + std::unique_lock& _lock; + bool _locked; + }; +#else class MutexPthreadLock { public: @@ -22,6 +41,8 @@ namespace oxygine pthread_mutex_t& _mutex; bool _locked; }; +#endif + /* class TDMessage { @@ -131,9 +152,15 @@ namespace oxygine void _popMessageNoCB(message&); void _replyLast(void* val); - +#if OX_CPP11THREADS + // TODO: This should be a std::recursive_mutex considering the original code but std::condition_variable only supports a normal std::mutex + std::mutex _mutexInternal; + std::unique_lock _mutex; + std::condition_variable _cond; +#else pthread_mutex_t _mutex; pthread_cond_t _cond; +#endif typedef std::vector messages; messages _events; @@ -146,4 +173,4 @@ namespace oxygine typedef ThreadDispatcher ThreadMessages; -} \ No newline at end of file +} diff --git a/oxygine/src/core/ZipFileSystem.cpp b/oxygine/src/core/ZipFileSystem.cpp index 83c8e0073..0d9240aa5 100644 --- a/oxygine/src/core/ZipFileSystem.cpp +++ b/oxygine/src/core/ZipFileSystem.cpp @@ -40,7 +40,7 @@ namespace oxygine return true; } - Zips::Zips(): _sort(false), _lock(true) + Zips::Zips(): _sort(false) { } @@ -74,7 +74,7 @@ namespace oxygine void Zips::add(const unsigned char* data, unsigned int size) { - MutexAutoLock al(_lock); + MutexRecursiveAutoLock al(_lock); zlib_filefunc_def ff; fill_memory_filefunc(&ff); @@ -98,7 +98,7 @@ namespace oxygine void Zips::add(std::vector& data) { - MutexAutoLock al(_lock); + MutexRecursiveAutoLock al(_lock); zlib_filefunc_def ff; fill_memory_filefunc(&ff); @@ -163,7 +163,7 @@ namespace oxygine void Zips::add(const char* name) { - MutexAutoLock al(_lock); + MutexRecursiveAutoLock al(_lock); zlib_filefunc_def zpfs; memset(&zpfs, 0, sizeof(zpfs)); @@ -205,13 +205,13 @@ namespace oxygine bool Zips::isExists(const char* name) { - MutexAutoLock al(_lock); + MutexRecursiveAutoLock al(_lock); return getEntryByName(name) != 0; } bool Zips::read(const char* name, file::buffer& bf) { - MutexAutoLock al(_lock); + MutexRecursiveAutoLock al(_lock); const file_entry* entry = getEntryByName(name); if (!entry) @@ -221,13 +221,13 @@ namespace oxygine bool Zips::read(const file_entry* entry, file::buffer& bf) { - MutexAutoLock al(_lock); + MutexRecursiveAutoLock al(_lock); return readEntry(entry, bf); } void Zips::reset() { - MutexAutoLock al(_lock); + MutexRecursiveAutoLock al(_lock); for (zips::iterator i = _zps.begin(); i != _zps.end(); ++i) { zpitem& f = *i; @@ -456,7 +456,7 @@ namespace oxygine FileSystem::status ZipFileSystem::_open(const char* file, const char* mode, error_policy ep, file::fileHandle*& fh) { - MutexAutoLock lock(_zips._lock); + MutexRecursiveAutoLock lock(_zips._lock); const file_entry* entry = _zips.getEntryByName(file); if (entry) @@ -497,4 +497,4 @@ namespace oxygine return status_error; } } -} \ No newline at end of file +} diff --git a/oxygine/src/core/ZipFileSystem.h b/oxygine/src/core/ZipFileSystem.h index aa315bc4f..cea174e49 100644 --- a/oxygine/src/core/ZipFileSystem.h +++ b/oxygine/src/core/ZipFileSystem.h @@ -61,7 +61,7 @@ namespace oxygine typedef std::vector zips; zips _zps; - Mutex _lock; + MutexRecursive _lock; }; bool read(file_entry* entry, file::buffer& bf); @@ -94,4 +94,4 @@ namespace oxygine }; } -} \ No newline at end of file +} diff --git a/oxygine/src/core/oxygine.cpp b/oxygine/src/core/oxygine.cpp index 6ddc3f2c2..39eb8ca61 100644 --- a/oxygine/src/core/oxygine.cpp +++ b/oxygine/src/core/oxygine.cpp @@ -55,7 +55,11 @@ #include "ios/ios.h" #endif -#include "pthread.h" +#if OX_CPP11THREADS + #include +#else + #include "pthread.h" +#endif #ifdef OXYGINE_SDL extern "C" @@ -100,7 +104,11 @@ namespace oxygine spEventDispatcher _dispatcher; +#if OX_CPP11THREADS + static std::thread::id _mainThread; +#else static pthread_t _mainThread; +#endif #ifdef __S3E__ @@ -222,7 +230,11 @@ namespace oxygine #ifdef OX_NO_MT return true; #else + #if OX_CPP11THREADS + return _mainThread == std::this_thread::get_id(); + #else return pthread_equal(_mainThread, pthread_self()) != 0; + #endif #endif } @@ -443,7 +455,11 @@ namespace oxygine { #ifndef OX_NO_MT + #if OX_CPP11THREADS + _mainThread = std::this_thread::get_id(); + #else _mainThread = pthread_self(); + #endif #endif if (!_dispatcher) diff --git a/oxygine/src/res/CreateResourceContext.cpp b/oxygine/src/res/CreateResourceContext.cpp index 3c0838d3c..498b8070a 100644 --- a/oxygine/src/res/CreateResourceContext.cpp +++ b/oxygine/src/res/CreateResourceContext.cpp @@ -3,7 +3,10 @@ #include "Image.h" #include "core/ThreadDispatcher.h" #include "core/oxygine.h" -#include "pthread.h" + +#if !OX_CPP11THREADS + #include "pthread.h" +#endif namespace oxygine { From 0a02143be301c734ce6139ab877c988cc51f026e Mon Sep 17 00:00:00 2001 From: holoeye-photonics Date: Tue, 2 May 2017 15:18:42 +0200 Subject: [PATCH 2/2] Add own condition class so the recursive stdlib mutex can be used with a condition. --- oxygine/src/core/ThreadDispatcher.cpp | 24 +++++++++------- oxygine/src/core/ThreadDispatcher.h | 41 ++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/oxygine/src/core/ThreadDispatcher.cpp b/oxygine/src/core/ThreadDispatcher.cpp index 2176feb1c..e14e55a4d 100644 --- a/oxygine/src/core/ThreadDispatcher.cpp +++ b/oxygine/src/core/ThreadDispatcher.cpp @@ -1,7 +1,9 @@ #include "ThreadDispatcher.h" #include "log.h" -#if !OX_CPP11THREADS +#if OX_CPP11THREADS + #include +#else #include "pthread.h" #endif @@ -9,11 +11,15 @@ namespace oxygine { -#if 0 +#if OX_DEBUGTHREADING static size_t threadID() { + #if OX_CPP11THREADS + return std::this_thread::get_id().hash(); + #else pthread_t pt = pthread_self(); return ((size_t*)(&pt))[0]; + #endif } #define LOGDN(format, ...) log::messageln("ThreadMessages(%lu)::" format, threadID(), __VA_ARGS__) @@ -23,9 +29,9 @@ namespace oxygine #endif #if OX_CPP11THREADS - MutexPthreadLock::MutexPthreadLock(std::unique_lock& l, bool lock) : _lock(l), _locked(false) + MutexPthreadLock::MutexPthreadLock(std::recursive_mutex& l, bool lock) : _lock(l), _locked(false) { - if(lock && !_lock.owns_lock()) + if(lock) { _lock.lock(); _locked = true; @@ -34,7 +40,8 @@ namespace oxygine MutexPthreadLock::~MutexPthreadLock() { - _lock.unlock(); + if(_locked) + _lock.unlock(); } #else MutexPthreadLock::MutexPthreadLock(pthread_mutex_t& m, bool lock) : _mutex(m), _locked(lock) @@ -50,7 +57,7 @@ namespace oxygine #endif #if OX_CPP11THREADS - ThreadDispatcher::ThreadDispatcher(): _mutex(_mutexInternal), _id(0), _result(0) + ThreadDispatcher::ThreadDispatcher(): _id(0), _result(0) #else ThreadDispatcher::ThreadDispatcher(): _id(0), _result(0) #endif @@ -73,10 +80,7 @@ namespace oxygine { #ifndef OX_NO_MT #if OX_CPP11THREADS - if(_mutex.owns_lock()) - _mutex.unlock(); - - //_cond.notify_all(); + _cond.notify_all(); #else pthread_mutex_destroy(&_mutex); pthread_cond_destroy(&_cond); diff --git a/oxygine/src/core/ThreadDispatcher.h b/oxygine/src/core/ThreadDispatcher.h index 125baa848..84d1f969c 100644 --- a/oxygine/src/core/ThreadDispatcher.h +++ b/oxygine/src/core/ThreadDispatcher.h @@ -5,7 +5,8 @@ #if OX_CPP11THREADS #include - #include + #include + #include #else #if defined(_WIN32) && !defined(__MINGW32__) @@ -23,11 +24,11 @@ namespace oxygine class MutexPthreadLock { public: - MutexPthreadLock(std::unique_lock& l, bool lock = true); + MutexPthreadLock(std::recursive_mutex& l, bool lock = true); ~MutexPthreadLock(); protected: - std::unique_lock& _lock; + std::recursive_mutex& _lock; bool _locked; }; #else @@ -153,10 +154,36 @@ namespace oxygine void _replyLast(void* val); #if OX_CPP11THREADS - // TODO: This should be a std::recursive_mutex considering the original code but std::condition_variable only supports a normal std::mutex - std::mutex _mutexInternal; - std::unique_lock _mutex; - std::condition_variable _cond; + std::recursive_mutex _mutex; + + class + { + private: + std::atomic_uint _in, _out; + + public: + void wait(std::recursive_mutex &mutex) + { + mutex.unlock(); + + const unsigned int ticket = ++_in; + + while(_out < ticket) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + mutex.lock(); + } + + void notify_all() + { + _out = _in; + } + + void notify_one() + { + _out++; + } + } _cond; #else pthread_mutex_t _mutex; pthread_cond_t _cond;