#ifndef THREADING_H #define THREADING_H #if !defined(PSP) && !defined(QT_CONFIG) && !(__cplusplus > 199711L) && !(_MSC_VER >= 1700) #include #ifdef WIN32 #pragma warning (push) #pragma warning (disable : 4244) #endif #include #ifdef WIN32 #pragma warning (pop) #endif #include #elif defined(PSP) #include #include #include "pspthreadman.h" #include "../include/DebugRoutines.h" #include "../include/JLogger.h" namespace boost { /** ** PSP specific variant of a boost mutex & scoped_lock */ template struct unique_lock { unique_lock(Mutex& inMutex) : mMutex(&inMutex) { mMutex->lock(); } ~unique_lock() { mMutex->unlock(); } Mutex* mMutex; }; class mutex { public: typedef unique_lock scoped_lock; mutex() { mID = sceKernelCreateSema("Unnamed", 0, 1, 1, 0); } ~mutex() { sceKernelDeleteSema(mID); } void lock() { int result = sceKernelWaitSema(mID, 1, 0); if (result < 0) { LOG("Semaphore error on lock acquire, mutex id: "); LOG((char*)mID); } } void unlock() { int result = sceKernelSignalSema(mID, 1); if (result < 0) { LOG("Semaphore error on lock release, mutex id: "); LOG((char*)mID); } } int mID; private: mutex(mutex const&); mutex& operator=(mutex const&); }; class recursive_mutex { public: typedef unique_lock scoped_lock; recursive_mutex() : mRecursionCount(0) { mID = sceKernelCreateSema("Unnamed", 0, 1, 1, 0); } ~recursive_mutex() { sceKernelDeleteSema(mID); } void lock() { int currentThreadID = sceKernelGetThreadId(); if (!try_recursive_lock(currentThreadID)) { int result = sceKernelWaitSema(mID, 1, 0); if (result < 0) { LOG("Semaphore error on lock acquire, mutex id: "); LOG((char*)mID); } else { mThreadID = currentThreadID; mRecursionCount = 1; } } } void unlock() { if(!--mRecursionCount) { mThreadID = 0; int result = sceKernelSignalSema(mID, 1); if (result < 0) { LOG("Semaphore error on lock release, mutex id: "); LOG((char*)mID); } } } int mID; int mThreadID; volatile int mRecursionCount; private: recursive_mutex(recursive_mutex const&); recursive_mutex& operator=(recursive_mutex const&); bool try_recursive_lock(int inThreadID) { if (mThreadID == inThreadID) { ++mRecursionCount; return true; } return false; } }; /** ** Emulating boost::thread configuration glue, with some shortcuts ** This detail namespace is a distillation of boost's thread.hpp, thread_data.hpp. */ namespace detail { struct thread_data_base { thread_data_base() { } virtual ~thread_data_base() { } virtual void run() = 0; }; typedef boost::shared_ptr thread_data_ptr; template class thread_data : public detail::thread_data_base { public: thread_data(F f_) : f(f_) { } void run() { f(); } private: F f; void operator=(thread_data&); thread_data(thread_data&); }; } //namespace detail /** ** A simplistic implementation of boost::thread, using pspsdk calls for the thread invocation. ** ** The intent of its usage is this form only: ** mWorkerThread = boost::thread(ThreadProc, this); ** where ThreadProc is a static member function of the 'this' class,eg: ** static void FOO::ThreadProc(void* inParam) ** { ** FOO* instance = reinterpret_cast(inParam); ** // now you have class instance data available... ** } ** ** Any other variant of a thread proc with more than one param is unimplemented. */ class thread { /* ** Helper class for sceKernelStartThread, which passes args by value, not by reference ** We use this struct to wrap any pointers that we want to pass to the worker thread. */ struct CallbackData { CallbackData(detail::thread_data_ptr inThreadInfo) : mThreadInfo(inThreadInfo) { } detail::thread_data_ptr mThreadInfo; }; public: thread() { } template thread(F f, A1 a1) : mThreadInfo(make_thread_info(boost::bind(boost::type(), f, a1))) { LOG("Calling bind on threadproc func"); CallbackData callbackData(mThreadInfo); LOG("Creating SCE Thread"); mThreadProcID = sceKernelCreateThread( typeid(a1).name(), thread::ThreadProc, 0x15, 0x40000, PSP_THREAD_ATTR_USER, NULL); if (mThreadProcID > 0) { sceKernelStartThread(mThreadProcID, sizeof(CallbackData), &callbackData); } } ~thread() { } void join() { sceKernelTerminateDeleteThread(mThreadProcID); } private: static int ThreadProc(SceSize args, void *inParam) { LOG("Entering thread::ThreadProc"); CallbackData* callbackData = reinterpret_cast(inParam); if (callbackData) { callbackData->mThreadInfo->run(); } return 0; } template static inline detail::thread_data_ptr make_thread_info(F f) { return detail::thread_data_ptr(new detail::thread_data(f)); } detail::thread_data_ptr mThreadInfo; SceUID mThreadProcID; }; namespace posix_time { typedef unsigned int milliseconds; } /** ** boost's platform neutral sleep call. */ namespace this_thread { inline void sleep(boost::posix_time::milliseconds const& time) { sceKernelDelayThread(time * 1000); } } } #elif defined(QT_CONFIG) && (__cplusplus <= 199711L) #include #include #include #include "../include/JLogger.h" namespace boost { template struct unique_lock { unique_lock(Mutex& inMutex) : mMutex(&inMutex) { mMutex->lock(); } ~unique_lock() { mMutex->unlock(); } Mutex* mMutex; }; class mutex { public: typedef unique_lock scoped_lock; mutex() : mQMutex() { } ~mutex() { } void lock() { mQMutex.lock(); } void unlock() { mQMutex.unlock(); } QMutex mQMutex; private: mutex(mutex const&); mutex& operator=(mutex const&); }; class recursive_mutex { public: typedef unique_lock scoped_lock; recursive_mutex() : mQMutex(QMutex::Recursive) { } ~recursive_mutex() { } void lock() { mQMutex.lock(); } void unlock() { mQMutex.unlock(); } QMutex mQMutex; private: recursive_mutex(recursive_mutex const&); recursive_mutex& operator=(recursive_mutex const&); }; /** ** Emulating boost::thread configuration glue, with some shortcuts ** This detail namespace is a distillation of boost's thread.hpp, thread_data.hpp. */ namespace detail { struct thread_data_base { thread_data_base() { } virtual ~thread_data_base() { } virtual void run() = 0; }; typedef QSharedPointer thread_data_ptr; template class thread_data : public detail::thread_data_base { public: thread_data(F f_, A1 a1_) : f(f_), a1(a1_) { } void run() { f(a1); } private: F f; A1 a1; void operator=(thread_data&); thread_data(thread_data&); }; } //namespace detail class threadImpl : public QThread { detail::thread_data_ptr mThreadInfo; public: threadImpl(detail::thread_data_ptr threadInfo) : mThreadInfo(threadInfo) { setTerminationEnabled(); }; static void mymsleep(unsigned long msecs) { QThread* currentThread = QThread::currentThread(); if(currentThread) currentThread->msleep(msecs); } protected: void run() { LOG("Entering thread::run"); mThreadInfo->run(); } }; /** ** A simplistic implementation of boost::thread, using QThread. ** */ class thread { /* ** Helper class for sceKernelStartThread, which passes args by value, not by reference ** We use this struct to wrap any pointers that we want to pass to the worker thread. */ struct CallbackData { CallbackData(detail::thread_data_ptr inThreadInfo) : mThreadInfo(inThreadInfo) { } detail::thread_data_ptr mThreadInfo; }; public: thread() { } template thread(F f, A1 a1) : mThreadInfo(make_thread_info(f, a1)) { mpThread = new threadImpl(mThreadInfo); LOG("Calling start func"); mpThread->start(QThread::LowPriority); } ~thread() { } void join() { mpThread->terminate(); } private: template static inline detail::thread_data_ptr make_thread_info(F f, A1 a1) { return detail::thread_data_ptr(new detail::thread_data(f, a1)); } detail::thread_data_ptr mThreadInfo; threadImpl* mpThread; }; namespace posix_time { typedef unsigned int milliseconds; } /** ** boost's platform neutral sleep call. */ namespace this_thread { inline void sleep(boost::posix_time::milliseconds const& time) { threadImpl::mymsleep(time); } } } #elif (__cplusplus > 199711L) || (_MSC_VER >= 1700) #include #include namespace boost { typedef std::thread thread; template struct unique_lock { unique_lock(Mutex& inMutex) : mMutex(&inMutex) { mMutex->lock(); } ~unique_lock() { mMutex->unlock(); } Mutex* mMutex; }; class mutex { public: typedef unique_lock scoped_lock; mutex() : mQMutex() { } ~mutex() { } void lock() { mQMutex.lock(); } void unlock() { mQMutex.unlock(); } std::mutex mQMutex; private: mutex(mutex const&); mutex& operator=(mutex const&); }; namespace posix_time { typedef unsigned int milliseconds; } /** ** boost's platform neutral sleep call. */ namespace this_thread { inline void sleep(boost::posix_time::milliseconds const& time) { std::this_thread::sleep_for(std::chrono::milliseconds(time)); } } } #endif #endif // THREADING_H