mirror of
https://github.com/GabsPuNs/Project-Zenith-Main.git
synced 2026-06-08 19:12:17 +00:00
337 lines
7.1 KiB
C++
337 lines
7.1 KiB
C++
#include "C4JThread.h"
|
|
|
|
std::vector<C4JThread*> 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<C4JThread *>(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<size;i++)
|
|
m_events[i] = CreateEvent(nullptr, (m_mode == e_modeManualClear), FALSE, nullptr );
|
|
}
|
|
|
|
C4JThread::EventArray::~EventArray()
|
|
{
|
|
if (m_events)
|
|
{
|
|
for (int i = 0; i < m_size; i++)
|
|
{
|
|
if (m_events[i] != nullptr)
|
|
CloseHandle(m_events[i]);
|
|
}
|
|
delete[] m_events;
|
|
}
|
|
}
|
|
|
|
void C4JThread::EventArray::Set(int index)
|
|
{
|
|
SetEvent(m_events[index]);
|
|
}
|
|
|
|
void C4JThread::EventArray::Clear(int index)
|
|
{
|
|
ResetEvent(m_events[index]);
|
|
}
|
|
|
|
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;
|
|
|
|
retVal = WaitForSingleObject(m_events[index], timeoutMs);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
DWORD C4JThread::EventArray::WaitForAll(int timeoutMs )
|
|
{
|
|
DWORD retVal;
|
|
|
|
retVal = WaitForMultipleObjects(m_size, m_events, true, timeoutMs);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
DWORD C4JThread::EventArray::WaitForAny(int timeoutMs )
|
|
{
|
|
return WaitForMultipleObjects(m_size, m_events, false, timeoutMs);
|
|
}
|
|
|
|
C4JThread::EventQueue::EventQueue( UpdateFunc* updateFunc, ThreadInitFunc threadInitFunc, const char* szThreadName)
|
|
{
|
|
m_updateFunc = updateFunc;
|
|
m_threadInitFunc = threadInitFunc;
|
|
strcpy(m_threadName, szThreadName);
|
|
m_thread = nullptr;
|
|
m_startEvent = nullptr;
|
|
m_finishedEvent = nullptr;
|
|
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 == 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<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))
|
|
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);
|
|
} |