diff -r 000000000000 -r c24a6fa957db core/thread/WinThreads.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/thread/WinThreads.cpp Sun Jul 06 04:49:55 2008 +0000 @@ -0,0 +1,320 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#define _WIN32_WINNT 0x0400 +#include "WinThreads.h" +#include "ThreadWorker.h" + +IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) +{ + if (threaded) + { + return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS); + } else { + return new BaseWorker(hooks); + } +} + +void WinThreader::DestroyWorker(IThreadWorker *pWorker) +{ + delete pWorker; +} + +void WinThreader::ThreadSleep(unsigned int ms) +{ + Sleep((DWORD)ms); +} + +IMutex *WinThreader::MakeMutex() +{ + WinMutex *pMutex = new WinMutex(); + + 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(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() +{ + InitializeCriticalSection(&m_crit); +} + +WinThreader::WinMutex::~WinMutex() +{ + DeleteCriticalSection(&m_crit); +} + +bool WinThreader::WinMutex::TryLock() +{ + return (TryEnterCriticalSection(&m_crit) != FALSE); +} + +void WinThreader::WinMutex::Lock() +{ + EnterCriticalSection(&m_crit); +} + +void WinThreader::WinMutex::Unlock() +{ + LeaveCriticalSection(&m_crit); +} + +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; +}