dvander@1084: /** dvander@1084: * vim: set ts=4 : dvander@1231: * ================================================================ dvander@1231: * SourceMod dvander@1231: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. dvander@1231: * ================================================================ dvander@1084: * dvander@1231: * This program is free software; you can redistribute it and/or dvander@1231: * modify it under the terms of the GNU General Public License, dvander@1231: * version 3.0, as published by the Free Software Foundation. dvander@1231: * dvander@1231: * This program is distributed in the hope that it will be useful, dvander@1231: * but WITHOUT ANY WARRANTY; without even the implied warranty of dvander@1231: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dvander@1231: * GNU General Public License for more details. dvander@1231: * dvander@1231: * You should have received a copy of the GNU General Public License dvander@1231: * along with this program. If not, see . dvander@1231: * dvander@1231: * As a special exception, AlliedModders LLC gives you permission to dvander@1231: * link the code of this program (as well as its derivative works) to dvander@1231: * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any dvander@1231: * Game MODs that run on software by the Valve Corporation. You must dvander@1231: * obey the GNU General Public License in all respects for all other dvander@1231: * code used. Additionally, AlliedModders LLC grants this exception dvander@1231: * to all derivative works. AlliedModders LLC defines further dvander@1231: * exceptions, found in LICENSE.txt (as of this writing, version dvander@1231: * JULY-31-2007), or . dvander@1084: * dvander@1084: * Version: $Id$ dvander@1084: */ dvander@1084: dvander@1087: #define _WIN32_WINNT 0x0400 dvander@1084: #include "WinThreads.h" dvander@1084: #include "ThreadWorker.h" dvander@1084: dvander@1090: IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) dvander@1084: { dvander@1084: if (threaded) dvander@1084: { dvander@1090: return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS); dvander@1084: } else { dvander@1090: return new BaseWorker(hooks); dvander@1084: } dvander@1084: } dvander@1084: dvander@1084: void WinThreader::DestroyWorker(IThreadWorker *pWorker) dvander@1084: { dvander@1084: delete pWorker; dvander@1084: } dvander@1084: dvander@1084: void WinThreader::ThreadSleep(unsigned int ms) dvander@1084: { dvander@1084: Sleep((DWORD)ms); dvander@1084: } dvander@1084: dvander@1084: IMutex *WinThreader::MakeMutex() dvander@1084: { dvander@1087: WinMutex *pMutex = new WinMutex(); dvander@1084: dvander@1084: return pMutex; dvander@1084: } dvander@1084: dvander@1084: IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags) dvander@1084: { dvander@1084: ThreadParams defparams; dvander@1084: dvander@1084: defparams.flags = flags; dvander@1084: defparams.prio = ThreadPrio_Normal; dvander@1084: dvander@1084: return MakeThread(pThread, &defparams); dvander@1084: } dvander@1084: dvander@1084: void WinThreader::MakeThread(IThread *pThread) dvander@1084: { dvander@1084: ThreadParams defparams; dvander@1084: dvander@1084: defparams.flags = Thread_AutoRelease; dvander@1084: defparams.prio = ThreadPrio_Normal; dvander@1084: dvander@1084: MakeThread(pThread, &defparams); dvander@1084: } dvander@1084: dvander@1084: DWORD WINAPI Win32_ThreadGate(LPVOID param) dvander@1084: { dvander@1084: WinThreader::ThreadHandle *pHandle = dvander@1084: reinterpret_cast(param); dvander@1084: dvander@1084: pHandle->m_run->RunThread(pHandle); dvander@1084: dvander@1084: ThreadParams params; dvander@1084: EnterCriticalSection(&pHandle->m_crit); dvander@1084: pHandle->m_state = Thread_Done; dvander@1084: pHandle->GetParams(¶ms); dvander@1084: LeaveCriticalSection(&pHandle->m_crit); dvander@1084: dvander@1084: pHandle->m_run->OnTerminate(pHandle, false); dvander@1084: if (params.flags & Thread_AutoRelease) dvander@1084: delete pHandle; dvander@1084: dvander@1084: return 0; dvander@1084: } dvander@1084: dvander@1084: void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) dvander@1084: { dvander@1084: max = ThreadPrio_Maximum; dvander@1084: min = ThreadPrio_Minimum; dvander@1084: } dvander@1084: dvander@1084: ThreadParams g_defparams; dvander@1084: IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params) dvander@1084: { dvander@1084: if (params == NULL) dvander@1084: params = &g_defparams; dvander@1084: dvander@1084: WinThreader::ThreadHandle *pHandle = dvander@1084: new WinThreader::ThreadHandle(this, NULL, pThread, params); dvander@1084: dvander@1084: DWORD tid; dvander@1084: pHandle->m_thread = dvander@1084: CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid); dvander@1084: dvander@1084: if (!pHandle->m_thread) dvander@1084: { dvander@1084: delete pHandle; dvander@1084: return NULL; dvander@1084: } dvander@1084: dvander@1084: if (pHandle->m_params.prio != ThreadPrio_Normal) dvander@1084: { dvander@1084: pHandle->SetPriority(pHandle->m_params.prio); dvander@1084: } dvander@1084: dvander@1084: if (!(pHandle->m_params.flags & Thread_CreateSuspended)) dvander@1084: { dvander@1084: pHandle->Unpause(); dvander@1084: } dvander@1084: dvander@1084: return pHandle; dvander@1084: } dvander@1084: dvander@1084: IEventSignal *WinThreader::MakeEventSignal() dvander@1084: { dvander@1084: HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL); dvander@1084: dvander@1084: if (!event) dvander@1084: return NULL; dvander@1084: dvander@1084: WinEvent *pEvent = new WinEvent(event); dvander@1084: dvander@1084: return pEvent; dvander@1084: } dvander@1084: dvander@1084: /***************** dvander@1084: **** Mutexes **** dvander@1084: *****************/ dvander@1084: dvander@1087: WinThreader::WinMutex::WinMutex() dvander@1087: { dvander@1087: InitializeCriticalSection(&m_crit); dvander@1087: } dvander@1087: dvander@1084: WinThreader::WinMutex::~WinMutex() dvander@1084: { dvander@1087: DeleteCriticalSection(&m_crit); dvander@1084: } dvander@1084: dvander@1084: bool WinThreader::WinMutex::TryLock() dvander@1084: { dvander@1087: return (TryEnterCriticalSection(&m_crit) != FALSE); dvander@1084: } dvander@1084: dvander@1084: void WinThreader::WinMutex::Lock() dvander@1084: { dvander@1087: EnterCriticalSection(&m_crit); dvander@1084: } dvander@1084: dvander@1084: void WinThreader::WinMutex::Unlock() dvander@1084: { dvander@1087: LeaveCriticalSection(&m_crit); dvander@1084: } dvander@1084: dvander@1084: void WinThreader::WinMutex::DestroyThis() dvander@1084: { dvander@1084: delete this; dvander@1084: } dvander@1084: dvander@1084: /****************** dvander@1084: * Thread Handles * dvander@1084: ******************/ dvander@1084: dvander@1084: WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) : dvander@1084: m_parent(parent), m_thread(hthread), m_run(run), m_params(*params), dvander@1084: m_state(Thread_Paused) dvander@1084: { dvander@1084: InitializeCriticalSection(&m_crit); dvander@1084: } dvander@1084: dvander@1084: WinThreader::ThreadHandle::~ThreadHandle() dvander@1084: { dvander@1084: if (m_thread) dvander@1084: { dvander@1084: CloseHandle(m_thread); dvander@1084: m_thread = NULL; dvander@1084: } dvander@1084: DeleteCriticalSection(&m_crit); dvander@1084: } dvander@1084: dvander@1084: bool WinThreader::ThreadHandle::WaitForThread() dvander@1084: { dvander@1084: if (m_thread == NULL) dvander@1084: return false; dvander@1084: dvander@1084: if (WaitForSingleObject(m_thread, INFINITE) != 0) dvander@1084: return false; dvander@1084: dvander@1084: return true; dvander@1084: } dvander@1084: dvander@1084: ThreadState WinThreader::ThreadHandle::GetState() dvander@1084: { dvander@1084: ThreadState state; dvander@1084: dvander@1084: EnterCriticalSection(&m_crit); dvander@1084: state = m_state; dvander@1084: LeaveCriticalSection(&m_crit); dvander@1084: dvander@1084: return state; dvander@1084: } dvander@1084: dvander@1084: IThreadCreator *WinThreader::ThreadHandle::Parent() dvander@1084: { dvander@1084: return m_parent; dvander@1084: } dvander@1084: dvander@1084: void WinThreader::ThreadHandle::DestroyThis() dvander@1084: { dvander@1084: if (m_params.flags & Thread_AutoRelease) dvander@1084: return; dvander@1084: dvander@1084: delete this; dvander@1084: } dvander@1084: dvander@1084: void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams) dvander@1084: { dvander@1084: if (!ptparams) dvander@1084: return; dvander@1084: dvander@1084: *ptparams = m_params; dvander@1084: } dvander@1084: dvander@1084: ThreadPriority WinThreader::ThreadHandle::GetPriority() dvander@1084: { dvander@1084: return m_params.prio; dvander@1084: } dvander@1084: dvander@1084: bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio) dvander@1084: { dvander@1084: if (!m_thread) dvander@1084: return false; dvander@1084: dvander@1084: BOOL res = FALSE; dvander@1084: dvander@1084: if (prio >= ThreadPrio_Maximum) dvander@1084: res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST); dvander@1084: else if (prio <= ThreadPrio_Minimum) dvander@1084: res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST); dvander@1084: else if (prio == ThreadPrio_Normal) dvander@1084: res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL); dvander@1084: else if (prio == ThreadPrio_High) dvander@1084: res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL); dvander@1084: else if (prio == ThreadPrio_Low) dvander@1084: res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL); dvander@1084: dvander@1084: m_params.prio = prio; dvander@1084: dvander@1084: return (res != FALSE); dvander@1084: } dvander@1084: dvander@1084: bool WinThreader::ThreadHandle::Unpause() dvander@1084: { dvander@1084: if (!m_thread) dvander@1084: return false; dvander@1084: dvander@1084: if (m_state != Thread_Paused) dvander@1084: return false; dvander@1084: dvander@1084: m_state = Thread_Running; dvander@1084: dvander@1084: if (ResumeThread(m_thread) == -1) dvander@1084: { dvander@1084: m_state = Thread_Paused; dvander@1084: return false; dvander@1084: } dvander@1084: dvander@1084: return true; dvander@1084: } dvander@1084: dvander@1084: /***************** dvander@1084: * EVENT SIGNALS * dvander@1084: *****************/ dvander@1084: dvander@1084: WinThreader::WinEvent::~WinEvent() dvander@1084: { dvander@1084: CloseHandle(m_event); dvander@1084: } dvander@1084: dvander@1084: void WinThreader::WinEvent::Wait() dvander@1084: { dvander@1084: WaitForSingleObject(m_event, INFINITE); dvander@1084: } dvander@1084: dvander@1084: void WinThreader::WinEvent::Signal() dvander@1084: { dvander@1084: SetEvent(m_event); dvander@1084: } dvander@1084: dvander@1084: void WinThreader::WinEvent::DestroyThis() dvander@1084: { dvander@1084: delete this; dvander@1084: }