aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/C4JThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.World/C4JThread.cpp')
-rw-r--r--Minecraft.World/C4JThread.cpp1100
1 files changed, 1100 insertions, 0 deletions
diff --git a/Minecraft.World/C4JThread.cpp b/Minecraft.World/C4JThread.cpp
new file mode 100644
index 00000000..4b9760c1
--- /dev/null
+++ b/Minecraft.World/C4JThread.cpp
@@ -0,0 +1,1100 @@
+#include "stdafx.h"
+
+
+#include "C4JThread.h"
+#ifdef __PSVITA__
+#include "..\Minecraft.Client\PSVita\PSVitaExtras\ShutdownManager.h"
+#include "..\Minecraft.Client\PSVita\PSVitaExtras\PSVitaTLSStorage.h"
+
+// AP - this comes from the low level user_malloc.c file used to overide the default memory functions. These must be called when a thread is started/stopped
+extern "C" {
+extern void user_registerthread();
+extern void user_removethread();
+}
+#else
+#include "..\Minecraft.Client\PS3\PS3Extras\ShutdownManager.h"
+
+#endif
+
+std::vector<C4JThread*> C4JThread::ms_threadList;
+CRITICAL_SECTION C4JThread::ms_threadListCS;
+
+#ifdef _XBOX_ONE
+ // 4J Stu - On XboxOne the main thread is not the one that does all the static init, so we have to set this up later
+C4JThread *C4JThread::m_mainThread = NULL;
+
+void C4JThread::StaticInit()
+{
+ m_mainThread = new C4JThread("Main thread");
+}
+#else
+C4JThread C4JThread::m_mainThread("Main thread");
+#endif
+
+#ifdef __ORBIS__
+__thread SceKernelCpumask C4JThread::m_oldAffinityMask;
+#endif
+
+
+#if __PSVITA__
+static SceInt32 g_DefaultCPU;
+static SceInt32 g_DefaultPriority;
+#endif
+
+C4JThread::C4JThread( C4JThreadStartFunc* startFunc, void* param, const char* threadName, int stackSize/* = 0*/ )
+{
+ m_startFunc = startFunc;
+ m_threadParam = param;
+ m_stackSize = stackSize;
+
+ // to match XBox, if the stack size is zero, use the default 64k
+ if(m_stackSize == 0)
+ m_stackSize = 65536 * 2;
+ // make sure it's at least 16K
+ if(m_stackSize < 16384)
+ m_stackSize = 16384;
+
+#ifdef __PS3__
+ sprintf(m_threadName, "(4J) %s", threadName );
+#else
+ sprintf_s(m_threadName,64, "(4J) %s", threadName );
+#endif
+
+ m_isRunning = false;
+ m_hasStarted = false;
+
+ m_exitCode = STILL_ACTIVE;
+
+#ifdef __PS3__
+ m_completionFlag = new Event(Event::e_modeManualClear);
+ m_threadID = 0;
+ m_lastSleepTime = 0;
+ m_priority = 1002; // main thread has priority 1001
+#elif defined __ORBIS__
+ m_completionFlag = new Event(Event::e_modeManualClear);
+ m_threadID = 0;
+ m_lastSleepTime = 0;
+ scePthreadAttrInit(&m_threadAttr);
+ int err = scePthreadAttrSetaffinity(&m_threadAttr, 63); // set the thread affinity to all cores to start with
+ assert(err == SCE_OK);
+ m_oldAffinityMask = 0;
+ m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT;
+#elif defined __PSVITA__
+ m_completionFlag = new Event(Event::e_modeManualClear);
+ m_threadID = 0;
+ m_lastSleepTime = 0;
+ m_priority = g_DefaultPriority;
+ //m_CPUMask = SCE_KERNEL_CPU_MASK_USER_ALL;
+
+ // AP - I had trouble getting the cpu to change once the thread was created so I've hard coded them here
+ // The main work division is...
+ // 0 - Main
+ // 1 - Chunk/Tile Update
+ // 2 - Server/Audio
+ // These three can sometimes consume ALL the CPU time so they are set to below average priority so as not to block other critical threads
+ int CPU = SCE_KERNEL_CPU_MASK_USER_ALL;
+ if( !strcmp(threadName, "Chunk update") )
+ {
+ CPU = SCE_KERNEL_CPU_MASK_USER_2;
+ m_priority = g_DefaultPriority + 1;
+ }
+ if( !strcmp(threadName, "Server" ) )
+ {
+ CPU = SCE_KERNEL_CPU_MASK_USER_1;
+ m_priority = g_DefaultPriority + 1;
+ }
+ // make sure Tile Update doesn't go on cpu 0 because it will hold up the main thread. And it can't go on cpu 1 because Chunk Update crashes.
+ if( !strcmp(threadName, "Tile update") )
+ {
+ CPU = SCE_KERNEL_CPU_MASK_USER_1;
+ }
+
+ m_threadID = sceKernelCreateThread(m_threadName, entryPoint, g_DefaultPriority, m_stackSize, 0, CPU, NULL);
+ app.DebugPrintf("***************************** start thread %s **************************\n", m_threadName);
+#else
+ m_threadID = 0;
+ m_threadHandle = 0;
+ m_threadHandle = CreateThread(NULL, m_stackSize, entryPoint, this, CREATE_SUSPENDED, &m_threadID);
+#endif
+ EnterCriticalSection(&ms_threadListCS);
+ ms_threadList.push_back(this);
+ LeaveCriticalSection(&ms_threadListCS);
+}
+
+// only used for the main thread
+C4JThread::C4JThread( const char* mainThreadName)
+{
+#ifdef __PSVITA__
+ user_registerthread();
+#endif
+
+ m_startFunc = NULL;
+ m_threadParam = NULL;
+ m_stackSize = 0;
+
+#ifdef __PS3__
+ sprintf(m_threadName, "(4J) %s", mainThreadName);
+#else
+ sprintf_s(m_threadName, 64, "(4J) %s", mainThreadName);
+#endif
+ m_isRunning = true;
+ m_hasStarted = true;
+ m_lastSleepTime = System::currentTimeMillis();
+
+ // should be the first thread to be created, so init the static critical section for the threadlist here
+ InitializeCriticalSection(&ms_threadListCS);
+
+
+#ifdef __PS3__
+ m_completionFlag = new Event(Event::e_modeManualClear);
+ sys_ppu_thread_get_id(&m_threadID);
+#elif defined __ORBIS__
+ m_completionFlag = new Event(Event::e_modeManualClear);
+ m_threadID = scePthreadSelf();
+ m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT;
+#elif defined __PSVITA__
+ m_completionFlag = new Event(Event::e_modeManualClear);
+ g_DefaultPriority = sceKernelGetThreadCurrentPriority();
+ m_threadID = sceKernelGetThreadId();
+ int err = sceKernelChangeThreadCpuAffinityMask(m_threadID, SCE_KERNEL_CPU_MASK_USER_0);
+// sceKernelChangeThreadPriority(m_threadID, g_DefaultPriority + 1);
+ g_DefaultCPU = SCE_KERNEL_CPU_MASK_USER_ALL;//sceKernelGetThreadCpuAffinityMask(m_threadID);
+#else
+ m_threadID = GetCurrentThreadId();
+ m_threadHandle = GetCurrentThread();
+#endif
+#ifdef _XBOX_ONE
+ SetThreadName(-1, m_threadName);
+#endif
+ EnterCriticalSection(&ms_threadListCS);
+ ms_threadList.push_back(this);
+ LeaveCriticalSection(&ms_threadListCS);
+}
+
+C4JThread::~C4JThread()
+{
+#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
+ delete m_completionFlag;
+#endif
+
+#if defined __ORBIS__
+ scePthreadJoin(m_threadID, NULL);
+#endif
+
+ EnterCriticalSection(&ms_threadListCS);
+
+ for( AUTO_VAR(it,ms_threadList.begin()); it != ms_threadList.end(); it++ )
+ {
+ if( (*it) == this )
+ {
+ ms_threadList.erase(it);
+ LeaveCriticalSection(&ms_threadListCS);
+ return;
+ }
+ }
+
+ LeaveCriticalSection(&ms_threadListCS);
+}
+
+#ifdef __PS3__
+void C4JThread::entryPoint(uint64_t param)
+{
+ C4JThread* pThread = (C4JThread*)param;
+ pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
+ pThread->m_completionFlag->Set();
+ pThread->m_isRunning = false;
+ sys_ppu_thread_exit(0);
+}
+#elif defined __ORBIS__
+void * C4JThread::entryPoint(void *param)
+{
+ C4JThread* pThread = (C4JThread*)param;
+ pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
+ pThread->m_completionFlag->Set();
+ pThread->m_isRunning = false;
+ scePthreadExit(NULL);
+}
+#elif defined __PSVITA__
+struct StrArg {
+ C4JThread* Thread;
+};
+
+SceInt32 C4JThread::entryPoint(SceSize argSize, void *pArgBlock)
+{
+ StrArg *strArg = (StrArg*)pArgBlock;
+ C4JThread* pThread = strArg->Thread;
+ user_registerthread();
+ pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
+ app.DebugPrintf("***************************** thread exit %s **************************\n", pThread->m_threadName);
+ pThread->m_completionFlag->Set();
+ pThread->m_isRunning = false;
+
+ // AP - make sure we clean up this thread's storage and memory
+ PSVitaTLSStorage::RemoveThread(pThread->m_threadID);
+ user_removethread();
+
+ sceKernelExitDeleteThread(NULL);
+
+ return pThread->m_exitCode;
+}
+#else
+DWORD WINAPI C4JThread::entryPoint(LPVOID lpParam)
+{
+ C4JThread* pThread = (C4JThread*)lpParam;
+ SetThreadName(-1, pThread->m_threadName);
+ pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
+ pThread->m_isRunning = false;
+ return pThread->m_exitCode;
+}
+#endif
+
+
+
+
+void C4JThread::Run()
+{
+#ifdef __PS3__
+ // prio specifies the priority value of the PPU thread within the range from 0 to 3071 where 0 is the highest.
+ // One of the following values is set to flags:
+ // 0 - non-joinable non-interrupt thread
+ // SYS_PPU_THREAD_CREATE_JOINABLE - Create a joinable thread
+ // SYS_PPU_THREAD_CREATE_INTERRUPT - Create an interrupt thread
+ uint64_t flags = 0;
+ int err = sys_ppu_thread_create(&m_threadID, entryPoint, (uint64_t)this, m_priority, m_stackSize, flags, m_threadName);
+#elif defined __ORBIS__
+ scePthreadAttrSetstacksize(&m_threadAttr, m_stackSize);
+ scePthreadAttrSetguardsize(&m_threadAttr, 1024);
+ int ret = scePthreadCreate(&m_threadID, &m_threadAttr, entryPoint, this, m_threadName);
+ assert( ret == SCE_OK );
+ scePthreadSetprio(m_threadID,m_priority);
+ scePthreadAttrDestroy(&m_threadAttr);
+#elif defined __PSVITA__
+ StrArg strArg = {this};
+// m_threadID = sceKernelCreateThread(m_threadName, entryPoint, m_priority, m_stackSize, 0, m_CPUMask, NULL);
+ sceKernelStartThread( m_threadID, sizeof(strArg), &strArg);
+#else
+ ResumeThread(m_threadHandle);
+#endif
+ m_lastSleepTime = System::currentTimeMillis();
+ m_isRunning = true;
+ m_hasStarted = true;
+}
+
+void C4JThread::SetProcessor( int proc )
+{
+#ifdef __PS3__
+ // does nothing since we only have the 1 processor
+#elif defined __ORBIS__
+ scePthreadAttrSetaffinity(&m_threadAttr, 1 << proc);
+#elif defined __PSVITA__
+ int Proc = proc >> 1; // convert from 360's 3 cores * 2 hardware threads to Vita's 3 cores
+ int Mask = SCE_KERNEL_CPU_MASK_USER_0 << Proc;
+ //m_CPUMask = Mask;
+// int err = sceKernelChangeThreadCpuAffinityMask(m_threadID, Mask);
+ int Newmask = sceKernelGetThreadCpuAffinityMask(m_threadID);
+ app.DebugPrintf("***************************** set thread proc %s %d %d %d **************************\n", m_threadName, proc, Mask, Newmask);
+#elif defined _DURANGO
+ SetThreadAffinityMask(m_threadHandle, 1 << proc );
+#else
+ XSetThreadProcessor( m_threadHandle, proc);
+#endif
+}
+
+void C4JThread::SetPriority( int priority )
+{
+#ifdef __PS3__
+ switch(priority)
+ {
+ case THREAD_PRIORITY_LOWEST: m_priority = 1003; break;
+ case THREAD_PRIORITY_BELOW_NORMAL: m_priority = 1002; break;
+ case THREAD_PRIORITY_NORMAL: m_priority = 1001; break; // same as main thread
+ case THREAD_PRIORITY_ABOVE_NORMAL: m_priority = 1000; break;
+ case THREAD_PRIORITY_HIGHEST: m_priority = 999; break;
+ }
+ if(m_threadID != 0)
+ sys_ppu_thread_set_priority(m_threadID, m_priority);
+ //int erro = sys_ppu_thread_set_priority(m_threadID, priority);
+#elif defined __ORBIS__
+
+ switch(priority)
+ {
+ case THREAD_PRIORITY_LOWEST: m_priority = SCE_KERNEL_PRIO_FIFO_LOWEST; break;
+ case THREAD_PRIORITY_BELOW_NORMAL: m_priority = SCE_KERNEL_PRIO_FIFO_LOWEST + ((SCE_KERNEL_PRIO_FIFO_DEFAULT-SCE_KERNEL_PRIO_FIFO_LOWEST)/2); break;
+ case THREAD_PRIORITY_NORMAL: m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT; break; // same as main thread
+ case THREAD_PRIORITY_ABOVE_NORMAL: m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT + ((SCE_KERNEL_PRIO_FIFO_HIGHEST-SCE_KERNEL_PRIO_FIFO_DEFAULT)/2); break;
+ case THREAD_PRIORITY_HIGHEST: m_priority = SCE_KERNEL_PRIO_FIFO_HIGHEST; break;
+ }
+
+ if( m_threadID != 0 )
+ {
+ scePthreadSetprio(m_threadID,m_priority);
+ }
+#elif defined __PSVITA__
+ int Mid = g_DefaultPriority;//(SCE_KERNEL_LOWEST_PRIORITY_USER + SCE_KERNEL_HIGHEST_PRIORITY_USER) / 2;
+ switch(priority)
+ {
+ case THREAD_PRIORITY_LOWEST:
+ m_priority = SCE_KERNEL_LOWEST_PRIORITY_USER;
+ break;
+ case THREAD_PRIORITY_BELOW_NORMAL:
+ m_priority = Mid + 1;
+ break;
+ case THREAD_PRIORITY_NORMAL:
+ m_priority = Mid;
+ break; // same as main thread
+ case THREAD_PRIORITY_ABOVE_NORMAL:
+ m_priority = Mid - 1;
+ break;
+ case THREAD_PRIORITY_HIGHEST:
+ m_priority = SCE_KERNEL_HIGHEST_PRIORITY_USER;
+ break;
+ }
+
+// sceKernelChangeThreadPriority(m_threadID, m_priority);
+ app.DebugPrintf("***************************** set thread prio %s %d %d **************************\n", m_threadName, priority, m_priority);
+#else
+ SetThreadPriority(m_threadHandle, priority);
+#endif // __PS3__
+}
+
+DWORD C4JThread::WaitForCompletion( int timeoutMs )
+{
+#ifdef __PS3__
+ if(timeoutMs == INFINITE)
+ timeoutMs = SYS_NO_TIMEOUT ;
+ return m_completionFlag->WaitForSignal(timeoutMs);
+#elif defined __ORBIS__
+ return m_completionFlag->WaitForSignal( timeoutMs );
+#elif defined __PSVITA__
+ return m_completionFlag->WaitForSignal( timeoutMs );
+/* SceUInt32 Timeout = timeoutMs * 1000;
+ SceInt32 err = sceKernelWaitThreadEnd(m_threadID, &m_exitCode, &Timeout);
+ if( err == 0 )
+ {
+ return m_exitCode;
+ }
+ else
+ {
+ if( err == SCE_KERNEL_ERROR_WAIT_TIMEOUT )
+ {
+ return WAIT_TIMEOUT;
+ }
+ else
+ {
+ // AP - not sure what to do here
+ return 0;
+ }
+ }*/
+
+// return m_exitCode;
+#else
+ return WaitForSingleObject(m_threadHandle, timeoutMs);
+#endif // __PS3__
+}
+
+int C4JThread::GetExitCode()
+{
+#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
+ return m_exitCode;
+#else
+ DWORD exitcode = 0;
+ GetExitCodeThread(m_threadHandle, &exitcode);
+
+ return *((int *)&exitcode);
+#endif
+}
+
+void C4JThread::Sleep( int millisecs )
+{
+#ifdef __PS3__
+ if(millisecs == 0)
+ {
+ // https://ps3.scedev.net/forums/thread/116470/
+ // "sys_timer_usleep(0) does not yield the CPU."
+ sys_ppu_thread_yield();
+ }
+ else
+ sys_timer_usleep(millisecs * 1000);
+#elif defined __ORBIS__
+ sceKernelUsleep(((SceKernelUseconds)millisecs) * 1000);
+#elif defined __PSVITA__
+ // 4J Stu - 0 is an error, so add a tiny sleep when we just want to yield
+ sceKernelDelayThread(millisecs * 1000 + 1);
+#else
+ ::Sleep(millisecs);
+#endif // __PS3__
+}
+
+C4JThread* C4JThread::getCurrentThread()
+{
+#ifdef __PS3__
+ sys_ppu_thread_t currThreadID;
+ sys_ppu_thread_get_id(&currThreadID);
+#elif defined __ORBIS__
+ ScePthread currThreadID = scePthreadSelf();
+#elif defined __PSVITA__
+ SceUID currThreadID = sceKernelGetThreadId();
+#else
+ DWORD currThreadID = GetCurrentThreadId();
+#endif //__PS3__
+ EnterCriticalSection(&ms_threadListCS);
+
+ for(int i=0;i<ms_threadList.size(); i++)
+ {
+ if(currThreadID == ms_threadList[i]->m_threadID)
+ {
+ LeaveCriticalSection(&ms_threadListCS);
+ return ms_threadList[i];
+ }
+ }
+
+ LeaveCriticalSection(&ms_threadListCS);
+
+ return NULL;
+}
+
+bool C4JThread::isMainThread()
+{
+#ifdef _XBOX_ONE
+ return getCurrentThread() == m_mainThread;
+#else
+ return getCurrentThread() == &m_mainThread;
+#endif
+}
+
+C4JThread::Event::Event(EMode mode/* = e_modeAutoClear*/)
+{
+ m_mode = mode;
+#ifdef __PS3__
+ sys_event_flag_attribute_t attr;
+ // default values taken from sys_event_flag_attribute_initialize
+ attr.attr_protocol = SYS_SYNC_PRIORITY;
+ attr.attr_pshared = SYS_SYNC_NOT_PROCESS_SHARED;
+ attr.key = 0;
+ attr.flags = 0;
+ attr.type = SYS_SYNC_WAITER_SINGLE;
+ attr.name[0] = '\0';
+ sys_event_flag_attribute_initialize(attr);
+
+ int err = sys_event_flag_create(&m_event, &attr, 0);
+
+#elif defined __ORBIS__
+ char name[1] = {0};
+ sceKernelCreateEventFlag( &m_event, name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
+#elif defined __PSVITA__
+ char name[1] = {0};
+ m_event = sceKernelCreateEventFlag( name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
+#else
+ m_event = CreateEvent( NULL, (m_mode == e_modeManualClear), FALSE, NULL );
+#endif //__PS3__
+}
+
+
+C4JThread::Event::~Event()
+{
+#ifdef __PS3__
+ sys_event_flag_destroy(m_event);
+#elif defined __ORBIS__
+ sceKernelDeleteEventFlag(m_event);
+#elif defined __PSVITA__
+ sceKernelDeleteEventFlag(m_event);
+#else
+ CloseHandle( m_event );
+#endif // __PS3__
+}
+
+
+void C4JThread::Event::Set()
+{
+#ifdef __PS3__
+ int err =sys_event_flag_set(m_event, 1);
+#elif defined __ORBIS__
+ sceKernelSetEventFlag(m_event, 1);
+#elif defined __PSVITA__
+ sceKernelSetEventFlag(m_event, 1);
+#else
+ SetEvent(m_event);
+#endif //__PS3__
+}
+
+void C4JThread::Event::Clear()
+{
+#ifdef __PS3__
+ int err =sys_event_flag_clear(m_event, ~(1));
+#elif defined __ORBIS__
+ sceKernelClearEventFlag(m_event, ~(1));
+#elif defined __PSVITA__
+ sceKernelClearEventFlag(m_event, ~1);
+#else
+ ResetEvent(m_event);
+#endif //__PS3__
+}
+
+DWORD C4JThread::Event::WaitForSignal( int timeoutMs )
+{
+#ifdef __PS3__
+ if(timeoutMs == INFINITE)
+ timeoutMs = SYS_NO_TIMEOUT ;
+ int timoutMicrosecs = timeoutMs * 1000;
+ uint32_t mode = SYS_EVENT_FLAG_WAIT_AND;
+ if(m_mode == e_modeAutoClear)
+ mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
+ int err = sys_event_flag_wait(m_event, 1, mode, 0, timoutMicrosecs);
+
+ switch(err)
+ {
+ case CELL_OK: return WAIT_OBJECT_0;
+ case ETIMEDOUT: return WAIT_TIMEOUT;
+ case ECANCELED: return WAIT_ABANDONED;
+ default: return WAIT_FAILED;
+ }
+
+#elif defined __ORBIS__
+ SceKernelUseconds timeoutMicrosecs;
+ SceKernelUseconds *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
+ }
+ int err = sceKernelWaitEventFlag(m_event, 1, waitMode, NULL, pTimeoutMicrosecs);
+ switch(err)
+ {
+ case SCE_OK: return WAIT_OBJECT_0;
+ case SCE_KERNEL_ERROR_ETIMEDOUT: return WAIT_TIMEOUT;
+ case SCE_KERNEL_ERROR_ECANCELED: return WAIT_ABANDONED;
+ default: return WAIT_FAILED;
+ }
+#elif defined __PSVITA__
+ SceUInt32 timeoutMicrosecs;
+ SceUInt32 *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceInt32)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
+ }
+ int err = sceKernelWaitEventFlag(m_event, 1, waitMode, NULL, pTimeoutMicrosecs);
+ switch(err)
+ {
+ case SCE_OK: return WAIT_OBJECT_0;
+ case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
+ case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
+ default: return WAIT_FAILED;
+ }
+#else
+ return WaitForSingleObject(m_event, timeoutMs);
+#endif // __PS3__
+}
+
+C4JThread::EventArray::EventArray( int size, EMode mode/* = e_modeAutoClear*/)
+{
+ assert(size<32);
+ m_size = size;
+ m_mode = mode;
+#ifdef __PS3__
+ sys_event_flag_attribute_t attr;
+ // default values taken from sys_event_flag_attribute_initialize
+ attr.attr_protocol = SYS_SYNC_PRIORITY;
+ attr.attr_pshared = SYS_SYNC_NOT_PROCESS_SHARED;
+ attr.key = 0;
+ attr.flags = 0;
+ attr.type = SYS_SYNC_WAITER_SINGLE;
+ attr.name[0] = '\0';
+ sys_event_flag_attribute_initialize(attr);
+ int err = sys_event_flag_create(&m_events, &attr, 0);
+ assert(err == CELL_OK);
+#elif defined __ORBIS__
+ char name[1] = {0};
+ sceKernelCreateEventFlag( &m_events, name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
+#elif defined __PSVITA__
+ char name[1] = {0};
+ m_events = sceKernelCreateEventFlag( name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
+#else
+ m_events = new HANDLE[size];
+ for(int i=0;i<size;i++)
+ {
+ m_events[i] = CreateEvent(NULL, (m_mode == e_modeManualClear), FALSE, NULL );
+ }
+#endif // __PS3__
+}
+
+
+void C4JThread::EventArray::Set(int index)
+{
+#ifdef __PS3__
+ int err =sys_event_flag_set(m_events, 1<<index);
+ assert(err == CELL_OK);
+#elif defined __ORBIS__
+ sceKernelSetEventFlag(m_events, 1<<index);
+#elif defined __PSVITA__
+ sceKernelSetEventFlag(m_events, 1<<index);
+#else
+ SetEvent(m_events[index]);
+#endif //__PS3__
+}
+
+void C4JThread::EventArray::Clear(int index)
+{
+#ifdef __PS3__
+ int err =sys_event_flag_clear(m_events, ~(1<<index));
+ assert(err == CELL_OK);
+#elif defined __ORBIS__
+ sceKernelClearEventFlag(m_events, ~(1<<index));
+#elif defined __PSVITA__
+ sceKernelClearEventFlag(m_events, ~(1<<index));
+#else
+ ResetEvent(m_events[index]);
+#endif //__PS3__
+}
+
+void C4JThread::EventArray::SetAll()
+{
+ for(int i=0;i<m_size;i++)
+ Set(i);
+}
+
+void C4JThread::EventArray::ClearAll()
+{
+ for(int i=0;i<m_size;i++)
+ Clear(i);
+}
+
+DWORD C4JThread::EventArray::WaitForSingle(int index, int timeoutMs )
+{
+ DWORD retVal;
+#ifdef __PS3__
+ int timeoutMicrosecs;
+ if(timeoutMs == INFINITE)
+ timeoutMicrosecs = SYS_NO_TIMEOUT;
+ else
+ timeoutMicrosecs = timeoutMs * 1000;
+ uint32_t mode = SYS_EVENT_FLAG_WAIT_AND;
+ if(m_mode == e_modeAutoClear)
+ mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
+
+ int err = sys_event_flag_wait(m_events, 1<<index, mode, 0, timeoutMicrosecs);
+
+ switch(err)
+ {
+ case CELL_OK:
+ retVal = WAIT_OBJECT_0;
+ break;
+ case ETIMEDOUT:
+ retVal = WAIT_TIMEOUT;
+ break;
+ case ECANCELED:
+ retVal = WAIT_ABANDONED;
+ break;
+ default:
+ assert(0);
+ retVal = WAIT_FAILED;
+ break;
+ }
+#elif defined __ORBIS__
+ SceKernelUseconds timeoutMicrosecs;
+ SceKernelUseconds *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
+ }
+ uint64_t resultPat;
+ int err = sceKernelWaitEventFlag(m_events, 1<<index, waitMode, &resultPat, pTimeoutMicrosecs);
+ assert(err != SCE_KERNEL_ERROR_ETIMEDOUT);
+ switch(err)
+ {
+ case SCE_OK:
+ retVal = WAIT_OBJECT_0;
+ break;
+ case SCE_KERNEL_ERROR_ETIMEDOUT:
+ retVal = WAIT_TIMEOUT;
+ break;
+ case SCE_KERNEL_ERROR_ECANCELED:
+ retVal = WAIT_ABANDONED;
+ break;
+ default:
+ retVal = WAIT_FAILED;
+ break;
+ }
+#elif defined __PSVITA__
+ SceUInt32 timeoutMicrosecs;
+ SceUInt32 *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
+ }
+ int err = sceKernelWaitEventFlag(m_events, 1<<index, waitMode, NULL, pTimeoutMicrosecs);
+ switch(err)
+ {
+ case SCE_OK: return WAIT_OBJECT_0;
+ case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
+ case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
+ default: return WAIT_FAILED;
+ }
+#else
+ retVal = WaitForSingleObject(m_events[index], timeoutMs);
+#endif // __PS3__
+
+ return retVal;
+}
+
+DWORD C4JThread::EventArray::WaitForAll(int timeoutMs )
+{
+ DWORD retVal;
+#ifdef __PS3__
+ if(timeoutMs == INFINITE)
+ timeoutMs = SYS_NO_TIMEOUT ;
+ int timoutMicrosecs = timeoutMs * 1000;
+ unsigned int bitmask = 0;
+ for(int i=0;i<m_size;i++)
+ bitmask |= (1<<i);
+
+ uint32_t mode = SYS_EVENT_FLAG_WAIT_AND;
+ if(m_mode == e_modeAutoClear)
+ mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
+
+ int err = sys_event_flag_wait(m_events, bitmask, mode, 0, timoutMicrosecs);
+
+ switch(err)
+ {
+ case CELL_OK:
+ retVal = WAIT_OBJECT_0;
+ break;
+ case ETIMEDOUT:
+ retVal = WAIT_TIMEOUT;
+ break;
+ case ECANCELED:
+ retVal = WAIT_ABANDONED;
+ break;
+ default:
+ assert(0);
+ retVal = WAIT_FAILED;
+ break;
+ }
+
+#elif defined __ORBIS__
+ SceKernelUseconds timeoutMicrosecs;
+ SceKernelUseconds *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ unsigned int bitmask = 0;
+ for(int i=0;i<m_size;i++)
+ bitmask |= (1<<i);
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
+ }
+ int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
+ switch(err)
+ {
+ case SCE_OK:
+ retVal = WAIT_OBJECT_0;
+ break;
+ case SCE_KERNEL_ERROR_ETIMEDOUT:
+ retVal = WAIT_TIMEOUT;
+ break;
+ case SCE_KERNEL_ERROR_ECANCELED:
+ retVal = WAIT_ABANDONED;
+ break;
+ default:
+ retVal = WAIT_FAILED;
+ break;
+ }
+#elif defined __PSVITA__
+ SceUInt32 timeoutMicrosecs;
+ SceUInt32 *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ unsigned int bitmask = 0;
+ for(int i=0;i<m_size;i++)
+ bitmask |= (1<<i);
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
+ }
+ int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
+ switch(err)
+ {
+ case SCE_OK: return WAIT_OBJECT_0;
+ case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
+ case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
+ default: return WAIT_FAILED;
+ }
+#else
+ retVal = WaitForMultipleObjects(m_size, m_events, true, timeoutMs);
+#endif // __PS3__
+
+ return retVal;
+}
+
+DWORD C4JThread::EventArray::WaitForAny(int timeoutMs )
+{
+#ifdef __PS3__
+ if(timeoutMs == INFINITE)
+ timeoutMs = SYS_NO_TIMEOUT ;
+ int timoutMicrosecs = timeoutMs * 1000;
+ unsigned int bitmask = 0;
+ for(int i=0;i<m_size;i++)
+ bitmask |= (1<<i);
+
+ uint32_t mode = SYS_EVENT_FLAG_WAIT_OR;
+ if(m_mode == e_modeAutoClear)
+ mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
+
+ int err = sys_event_flag_wait(m_events, bitmask, mode, 0, timoutMicrosecs);
+
+ switch(err)
+ {
+ case CELL_OK: return WAIT_OBJECT_0;
+ case ETIMEDOUT: return WAIT_TIMEOUT;
+ case ECANCELED: return WAIT_ABANDONED;
+ default:
+ assert(0);
+ return WAIT_FAILED;
+ }
+
+#elif defined __ORBIS__
+ SceKernelUseconds timeoutMicrosecs;
+ SceKernelUseconds *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ unsigned int bitmask = 0;
+ for(int i=0;i<m_size;i++)
+ bitmask |= (1<<i);
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_OR;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
+ }
+ int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
+ switch(err)
+ {
+ case SCE_OK: return WAIT_OBJECT_0;
+ case SCE_KERNEL_ERROR_ETIMEDOUT: return WAIT_TIMEOUT;
+ case SCE_KERNEL_ERROR_ECANCELED: return WAIT_ABANDONED;
+ default: return WAIT_FAILED;
+ }
+#elif defined __PSVITA__
+ SceUInt32 timeoutMicrosecs;
+ SceUInt32 *pTimeoutMicrosecs;
+ if( timeoutMs == INFINITE )
+ {
+ pTimeoutMicrosecs = NULL;
+ }
+ else
+ {
+ timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000;
+ pTimeoutMicrosecs = &timeoutMicrosecs;
+ }
+ unsigned int bitmask = 0;
+ for(int i=0;i<m_size;i++)
+ bitmask |= (1<<i);
+ uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_OR;
+ if(m_mode == e_modeAutoClear)
+ {
+ waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
+ }
+ int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
+ switch(err)
+ {
+ case SCE_OK: return WAIT_OBJECT_0;
+ case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
+ case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
+ default: return WAIT_FAILED;
+ }
+#else
+ return WaitForMultipleObjects(m_size, m_events, false, timeoutMs);
+#endif // __PS3__
+}
+
+#ifdef __PS3__
+void C4JThread::EventArray::Cancel()
+{
+ sys_event_flag_cancel(m_events, NULL);
+}
+#endif
+
+
+
+
+C4JThread::EventQueue::EventQueue( UpdateFunc* updateFunc, ThreadInitFunc threadInitFunc, const char* szThreadName)
+{
+ m_updateFunc = updateFunc;
+ m_threadInitFunc = threadInitFunc;
+ strcpy(m_threadName, szThreadName);
+ m_thread = NULL;
+ m_startEvent = NULL;
+ m_finishedEvent = NULL;
+ m_processor = -1;
+ m_priority = THREAD_PRIORITY_HIGHEST+1;
+}
+
+void C4JThread::EventQueue::init()
+{
+ m_startEvent = new C4JThread::EventArray(1);
+ m_finishedEvent = new C4JThread::Event();
+ InitializeCriticalSection(&m_critSect);
+ m_thread = new C4JThread(threadFunc, this, m_threadName);
+ if(m_processor >= 0)
+ m_thread->SetProcessor(m_processor);
+ if(m_priority != THREAD_PRIORITY_HIGHEST+1)
+ m_thread->SetPriority(m_priority);
+ m_thread->Run();
+}
+
+void C4JThread::EventQueue::sendEvent( Level* pLevel )
+{
+ if(m_thread == NULL)
+ init();
+ EnterCriticalSection(&m_critSect);
+ m_queue.push(pLevel);
+ m_startEvent->Set(0);
+ m_finishedEvent->Clear();
+ LeaveCriticalSection(&m_critSect);
+}
+
+void C4JThread::EventQueue::waitForFinish()
+{
+ if(m_thread == NULL)
+ init();
+ EnterCriticalSection(&m_critSect);
+ if(m_queue.empty())
+ {
+ LeaveCriticalSection((&m_critSect));
+ return;
+ }
+ LeaveCriticalSection((&m_critSect));
+ m_finishedEvent->WaitForSignal(INFINITE);
+}
+
+int C4JThread::EventQueue::threadFunc( void* lpParam )
+{
+ EventQueue* p = (EventQueue*)lpParam;
+ p->threadPoll();
+ return 0;
+}
+
+void C4JThread::EventQueue::threadPoll()
+{
+ ShutdownManager::HasStarted(ShutdownManager::eEventQueueThreads, m_startEvent);
+
+ if(m_threadInitFunc)
+ m_threadInitFunc();
+
+ while(ShutdownManager::ShouldRun(ShutdownManager::eEventQueueThreads))
+ {
+
+ DWORD err = m_startEvent->WaitForAny(INFINITE);
+ if(err == WAIT_OBJECT_0)
+ {
+ bool bListEmpty = true;
+ do
+ {
+ EnterCriticalSection(&m_critSect);
+ void* updateParam = m_queue.front();
+ LeaveCriticalSection(&m_critSect);
+
+ m_updateFunc(updateParam);
+
+ EnterCriticalSection(&m_critSect);
+ m_queue.pop();
+ bListEmpty = m_queue.empty();
+ if(bListEmpty)
+ {
+ m_finishedEvent->Set();
+ }
+ LeaveCriticalSection(&m_critSect);
+
+ } while(!bListEmpty);
+ }
+ };
+
+ ShutdownManager::HasFinished(ShutdownManager::eEventQueueThreads);
+}
+
+
+#ifdef __ORBIS__
+
+void C4JThread::PushAffinityAllCores()
+{
+ assert(m_oldAffinityMask == 0);
+ int err;
+ ScePthread currThreadID = scePthreadSelf();
+ err = scePthreadGetaffinity(currThreadID, &m_oldAffinityMask);
+ assert(err == SCE_OK);
+ err = scePthreadSetaffinity(currThreadID, 63);
+ assert(err == SCE_OK);
+
+
+}
+
+void C4JThread::PopAffinity()
+{
+ int err;
+ ScePthread currThreadID = scePthreadSelf();
+ err = scePthreadSetaffinity(currThreadID, m_oldAffinityMask);
+ m_oldAffinityMask = 0;
+ assert(err == SCE_OK);
+}
+
+#endif // __ORBIS__ \ No newline at end of file