617 lines
13 KiB
C++
617 lines
13 KiB
C++
#ifndef THREADING_H
|
|
#define THREADING_H
|
|
|
|
#if !defined(PSP) && !defined(QT_CONFIG) && !(__cplusplus > 199711L) && !(_MSC_VER >= 1700)
|
|
#include <boost/date_time.hpp>
|
|
|
|
#ifdef WIN32
|
|
#pragma warning (push)
|
|
#pragma warning (disable : 4244)
|
|
#endif
|
|
#include <boost/thread.hpp>
|
|
#ifdef WIN32
|
|
#pragma warning (pop)
|
|
#endif
|
|
|
|
#include <boost/thread/mutex.hpp>
|
|
#elif defined(PSP)
|
|
#include <boost/bind.hpp>
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
#include "pspthreadman.h"
|
|
|
|
#include "../include/DebugRoutines.h"
|
|
#include "../include/JLogger.h"
|
|
|
|
namespace boost
|
|
{
|
|
/**
|
|
** PSP specific variant of a boost mutex & scoped_lock
|
|
*/
|
|
|
|
template <class Mutex>
|
|
struct unique_lock
|
|
{
|
|
unique_lock(Mutex& inMutex) : mMutex(&inMutex)
|
|
{
|
|
mMutex->lock();
|
|
}
|
|
|
|
~unique_lock()
|
|
{
|
|
mMutex->unlock();
|
|
}
|
|
|
|
Mutex* mMutex;
|
|
};
|
|
|
|
class mutex
|
|
{
|
|
public:
|
|
|
|
typedef unique_lock<mutex> 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<recursive_mutex> 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<detail::thread_data_base> thread_data_ptr;
|
|
|
|
template<typename F>
|
|
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<FOO*>(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 <class F,class A1>
|
|
thread(F f, A1 a1) : mThreadInfo(make_thread_info(boost::bind(boost::type<void>(), 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<CallbackData* >(inParam);
|
|
if (callbackData)
|
|
{
|
|
callbackData->mThreadInfo->run();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template<typename F>
|
|
static inline detail::thread_data_ptr make_thread_info(F f)
|
|
{
|
|
return detail::thread_data_ptr(new detail::thread_data<F>(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 <QMutex>
|
|
#include <QThread>
|
|
|
|
#include <boost/bind.hpp>
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
#include "../include/JLogger.h"
|
|
|
|
namespace boost
|
|
{
|
|
template <class Mutex>
|
|
struct unique_lock
|
|
{
|
|
unique_lock(Mutex& inMutex) : mMutex(&inMutex)
|
|
{
|
|
mMutex->lock();
|
|
}
|
|
|
|
~unique_lock()
|
|
{
|
|
mMutex->unlock();
|
|
}
|
|
|
|
Mutex* mMutex;
|
|
};
|
|
|
|
class mutex
|
|
{
|
|
public:
|
|
|
|
typedef unique_lock<mutex> 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<recursive_mutex> 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 boost::shared_ptr<detail::thread_data_base> thread_data_ptr;
|
|
|
|
template<typename F>
|
|
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
|
|
|
|
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 <class F,class A1>
|
|
thread(F f, A1 a1) : mThreadInfo(make_thread_info(boost::bind(boost::type<void>(), f, a1)))
|
|
{
|
|
mpThread = new threadImpl(mThreadInfo);
|
|
LOG("Calling start func");
|
|
mpThread->start(QThread::LowPriority);
|
|
}
|
|
|
|
~thread()
|
|
{
|
|
}
|
|
|
|
void join()
|
|
{
|
|
mpThread->terminate();
|
|
}
|
|
|
|
private:
|
|
template<typename F>
|
|
static inline detail::thread_data_ptr make_thread_info(F f)
|
|
{
|
|
return detail::thread_data_ptr(new detail::thread_data<F>(f));
|
|
}
|
|
|
|
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 <thread>
|
|
#include <mutex>
|
|
|
|
namespace boost
|
|
{
|
|
typedef std::thread thread;
|
|
|
|
template <class Mutex>
|
|
struct unique_lock
|
|
{
|
|
unique_lock(Mutex& inMutex) : mMutex(&inMutex)
|
|
{
|
|
mMutex->lock();
|
|
}
|
|
|
|
~unique_lock()
|
|
{
|
|
mMutex->unlock();
|
|
}
|
|
|
|
Mutex* mMutex;
|
|
};
|
|
|
|
class mutex
|
|
{
|
|
public:
|
|
|
|
typedef unique_lock<mutex> 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
|