#include "C4JThread.h" std::vector C4JThread::ms_threadList; CRITICAL_SECTION C4JThread::ms_threadListCS; C4JThread C4JThread::m_mainThread("Main thread"); 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; sprintf_s(m_threadName,64, "(4J) %s", threadName ); m_isRunning = false; m_hasStarted = false; m_exitCode = STILL_ACTIVE; m_threadID = 0; m_threadHandle = 0; m_threadHandle = CreateThread(nullptr, m_stackSize, entryPoint, this, CREATE_SUSPENDED, &m_threadID); EnterCriticalSection(&ms_threadListCS); ms_threadList.push_back(this); LeaveCriticalSection(&ms_threadListCS); } // only used for the main thread C4JThread::C4JThread( const char* mainThreadName) { m_startFunc = nullptr; m_threadParam = nullptr; m_stackSize = 0; sprintf_s(m_threadName, 64, "(4J) %s", mainThreadName); 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); m_threadID = GetCurrentThreadId(); m_threadHandle = GetCurrentThread(); EnterCriticalSection(&ms_threadListCS); ms_threadList.push_back(this); LeaveCriticalSection(&ms_threadListCS); } C4JThread::~C4JThread() { EnterCriticalSection(&ms_threadListCS); std::erase(ms_threadList, this); LeaveCriticalSection(&ms_threadListCS); if (m_threadHandle != nullptr && m_threadHandle != (HANDLE)-2) { CloseHandle(m_threadHandle); m_threadHandle = nullptr; } } DWORD WINAPI C4JThread::entryPoint(LPVOID lpParam) { C4JThread* pThread = static_cast(lpParam); SetThreadName(-1, pThread->m_threadName); pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam); pThread->m_isRunning = false; return pThread->m_exitCode; } void C4JThread::Run() { ResumeThread(m_threadHandle); m_lastSleepTime = System::currentTimeMillis(); m_isRunning = true; m_hasStarted = true; } void C4JThread::SetProcessor( int proc ) { SetThreadIdealProcessor(m_threadHandle, proc ); } void C4JThread::SetPriority( int priority ) { SetThreadPriority(m_threadHandle, priority); } DWORD C4JThread::WaitForCompletion( int timeoutMs ) { return WaitForSingleObject(m_threadHandle, timeoutMs); } int C4JThread::GetExitCode() { DWORD exitcode = 0; GetExitCodeThread(m_threadHandle, &exitcode); return *((int *)&exitcode); } void C4JThread::Sleep( int millisecs ) { ::Sleep(millisecs); } C4JThread* C4JThread::getCurrentThread() { DWORD currThreadID = GetCurrentThreadId(); C4JThread* result = nullptr; EnterCriticalSection(&ms_threadListCS); auto it = std::find_if(ms_threadList.begin(), ms_threadList.end(), [currThreadID](C4JThread* t) { return t->m_threadID == currThreadID; }); if (it != ms_threadList.end()) result = *it; LeaveCriticalSection(&ms_threadListCS); return result; } bool C4JThread::isMainThread() { return getCurrentThread() == &m_mainThread; } C4JThread::Event::Event(EMode mode/* = e_modeAutoClear*/) { m_mode = mode; m_event = CreateEvent( nullptr, (m_mode == e_modeManualClear), FALSE, nullptr ); } C4JThread::Event::~Event() { CloseHandle( m_event ); } void C4JThread::Event::Set() { SetEvent(m_event); } void C4JThread::Event::Clear() { ResetEvent(m_event); } DWORD C4JThread::Event::WaitForSignal( int timeoutMs ) { return WaitForSingleObject(m_event, timeoutMs); } C4JThread::EventArray::EventArray( int size, EMode mode/* = e_modeAutoClear*/) { assert(size<32); m_size = size; m_mode = mode; m_events = new HANDLE[size]; for(int i=0;i= 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 == nullptr) 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 == nullptr) 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 = static_cast(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)) while(true) { 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); }