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