299 lines
5.4 KiB
C++
299 lines
5.4 KiB
C++
// vim: set ts=4 sw=4 tw=99 noet:
|
|
//
|
|
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
// Copyright (C) The AMX Mod X Development Team.
|
|
//
|
|
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
// https://alliedmods.net/amxmodx-license
|
|
|
|
#include "WinThreads.h"
|
|
|
|
void WinThreader::ThreadSleep(unsigned int ms)
|
|
{
|
|
Sleep((DWORD)ms);
|
|
}
|
|
|
|
IMutex *WinThreader::MakeMutex()
|
|
{
|
|
HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
|
|
|
|
if (mutex == NULL)
|
|
return NULL;
|
|
|
|
WinMutex *pMutex = new WinMutex(mutex);
|
|
|
|
return pMutex;
|
|
}
|
|
|
|
IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
|
{
|
|
ThreadParams defparams;
|
|
|
|
defparams.flags = flags;
|
|
defparams.prio = ThreadPrio_Normal;
|
|
|
|
return MakeThread(pThread, &defparams);
|
|
}
|
|
|
|
void WinThreader::MakeThread(IThread *pThread)
|
|
{
|
|
ThreadParams defparams;
|
|
|
|
defparams.flags = Thread_AutoRelease;
|
|
defparams.prio = ThreadPrio_Normal;
|
|
|
|
MakeThread(pThread, &defparams);
|
|
}
|
|
|
|
DWORD WINAPI Win32_ThreadGate(LPVOID param)
|
|
{
|
|
WinThreader::ThreadHandle *pHandle =
|
|
reinterpret_cast<WinThreader::ThreadHandle *>(param);
|
|
|
|
pHandle->m_run->RunThread(pHandle);
|
|
|
|
ThreadParams params;
|
|
EnterCriticalSection(&pHandle->m_crit);
|
|
pHandle->m_state = Thread_Done;
|
|
pHandle->GetParams(¶ms);
|
|
LeaveCriticalSection(&pHandle->m_crit);
|
|
|
|
pHandle->m_run->OnTerminate(pHandle, false);
|
|
if (params.flags & Thread_AutoRelease)
|
|
delete pHandle;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
|
{
|
|
max = ThreadPrio_Maximum;
|
|
min = ThreadPrio_Minimum;
|
|
}
|
|
|
|
ThreadParams g_defparams;
|
|
IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
|
{
|
|
if (params == NULL)
|
|
params = &g_defparams;
|
|
|
|
WinThreader::ThreadHandle *pHandle =
|
|
new WinThreader::ThreadHandle(this, NULL, pThread, params);
|
|
|
|
DWORD tid;
|
|
pHandle->m_thread =
|
|
CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
|
|
|
|
if (!pHandle->m_thread)
|
|
{
|
|
delete pHandle;
|
|
return NULL;
|
|
}
|
|
|
|
if (pHandle->m_params.prio != ThreadPrio_Normal)
|
|
{
|
|
pHandle->SetPriority(pHandle->m_params.prio);
|
|
}
|
|
|
|
if (!(pHandle->m_params.flags & Thread_CreateSuspended))
|
|
{
|
|
pHandle->Unpause();
|
|
}
|
|
|
|
return pHandle;
|
|
}
|
|
|
|
IEventSignal *WinThreader::MakeEventSignal()
|
|
{
|
|
HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (!event)
|
|
return NULL;
|
|
|
|
WinEvent *pEvent = new WinEvent(event);
|
|
|
|
return pEvent;
|
|
}
|
|
|
|
/*****************
|
|
**** Mutexes ****
|
|
*****************/
|
|
|
|
WinThreader::WinMutex::~WinMutex()
|
|
{
|
|
if (m_mutex)
|
|
{
|
|
CloseHandle(m_mutex);
|
|
m_mutex = NULL;
|
|
}
|
|
}
|
|
|
|
bool WinThreader::WinMutex::TryLock()
|
|
{
|
|
if (!m_mutex)
|
|
return false;
|
|
|
|
if (WaitForSingleObject(m_mutex, 0) != WAIT_FAILED)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void WinThreader::WinMutex::Lock()
|
|
{
|
|
if (!m_mutex)
|
|
return;
|
|
|
|
WaitForSingleObject(m_mutex, INFINITE);
|
|
}
|
|
|
|
void WinThreader::WinMutex::Unlock()
|
|
{
|
|
if (!m_mutex)
|
|
return;
|
|
|
|
ReleaseMutex(m_mutex);
|
|
}
|
|
|
|
void WinThreader::WinMutex::DestroyThis()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
/******************
|
|
* Thread Handles *
|
|
******************/
|
|
|
|
WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) :
|
|
m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
|
|
m_state(Thread_Paused)
|
|
{
|
|
InitializeCriticalSection(&m_crit);
|
|
}
|
|
|
|
WinThreader::ThreadHandle::~ThreadHandle()
|
|
{
|
|
if (m_thread)
|
|
{
|
|
CloseHandle(m_thread);
|
|
m_thread = NULL;
|
|
}
|
|
DeleteCriticalSection(&m_crit);
|
|
}
|
|
|
|
bool WinThreader::ThreadHandle::WaitForThread()
|
|
{
|
|
if (m_thread == NULL)
|
|
return false;
|
|
|
|
if (WaitForSingleObject(m_thread, INFINITE) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
ThreadState WinThreader::ThreadHandle::GetState()
|
|
{
|
|
ThreadState state;
|
|
|
|
EnterCriticalSection(&m_crit);
|
|
state = m_state;
|
|
LeaveCriticalSection(&m_crit);
|
|
|
|
return state;
|
|
}
|
|
|
|
IThreadCreator *WinThreader::ThreadHandle::Parent()
|
|
{
|
|
return m_parent;
|
|
}
|
|
|
|
void WinThreader::ThreadHandle::DestroyThis()
|
|
{
|
|
if (m_params.flags & Thread_AutoRelease)
|
|
return;
|
|
|
|
delete this;
|
|
}
|
|
|
|
void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
|
|
{
|
|
if (!ptparams)
|
|
return;
|
|
|
|
*ptparams = m_params;
|
|
}
|
|
|
|
ThreadPriority WinThreader::ThreadHandle::GetPriority()
|
|
{
|
|
return m_params.prio;
|
|
}
|
|
|
|
bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
|
|
{
|
|
if (!m_thread)
|
|
return false;
|
|
|
|
BOOL res = FALSE;
|
|
|
|
if (prio >= ThreadPrio_Maximum)
|
|
res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
|
|
else if (prio <= ThreadPrio_Minimum)
|
|
res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
|
|
else if (prio == ThreadPrio_Normal)
|
|
res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
|
|
else if (prio == ThreadPrio_High)
|
|
res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
|
|
else if (prio == ThreadPrio_Low)
|
|
res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
|
|
|
|
m_params.prio = prio;
|
|
|
|
return (res != FALSE);
|
|
}
|
|
|
|
bool WinThreader::ThreadHandle::Unpause()
|
|
{
|
|
if (!m_thread)
|
|
return false;
|
|
|
|
if (m_state != Thread_Paused)
|
|
return false;
|
|
|
|
m_state = Thread_Running;
|
|
|
|
if (ResumeThread(m_thread) == -1)
|
|
{
|
|
m_state = Thread_Paused;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*****************
|
|
* EVENT SIGNALS *
|
|
*****************/
|
|
|
|
WinThreader::WinEvent::~WinEvent()
|
|
{
|
|
CloseHandle(m_event);
|
|
}
|
|
|
|
void WinThreader::WinEvent::Wait()
|
|
{
|
|
WaitForSingleObject(m_event, INFINITE);
|
|
}
|
|
|
|
void WinThreader::WinEvent::Signal()
|
|
{
|
|
SetEvent(m_event);
|
|
}
|
|
|
|
void WinThreader::WinEvent::DestroyThis()
|
|
{
|
|
delete this;
|
|
}
|
|
|