1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/logic/thread/WinThreads.cpp Wed May 13 21:55:50 2009 -0400
1.3 @@ -0,0 +1,320 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#define _WIN32_WINNT 0x0400
1.36 +#include "WinThreads.h"
1.37 +#include "ThreadWorker.h"
1.38 +
1.39 +IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
1.40 +{
1.41 + if (threaded)
1.42 + {
1.43 + return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
1.44 + } else {
1.45 + return new BaseWorker(hooks);
1.46 + }
1.47 +}
1.48 +
1.49 +void WinThreader::DestroyWorker(IThreadWorker *pWorker)
1.50 +{
1.51 + delete pWorker;
1.52 +}
1.53 +
1.54 +void WinThreader::ThreadSleep(unsigned int ms)
1.55 +{
1.56 + Sleep((DWORD)ms);
1.57 +}
1.58 +
1.59 +IMutex *WinThreader::MakeMutex()
1.60 +{
1.61 + WinMutex *pMutex = new WinMutex();
1.62 +
1.63 + return pMutex;
1.64 +}
1.65 +
1.66 +IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
1.67 +{
1.68 + ThreadParams defparams;
1.69 +
1.70 + defparams.flags = flags;
1.71 + defparams.prio = ThreadPrio_Normal;
1.72 +
1.73 + return MakeThread(pThread, &defparams);
1.74 +}
1.75 +
1.76 +void WinThreader::MakeThread(IThread *pThread)
1.77 +{
1.78 + ThreadParams defparams;
1.79 +
1.80 + defparams.flags = Thread_AutoRelease;
1.81 + defparams.prio = ThreadPrio_Normal;
1.82 +
1.83 + MakeThread(pThread, &defparams);
1.84 +}
1.85 +
1.86 +DWORD WINAPI Win32_ThreadGate(LPVOID param)
1.87 +{
1.88 + WinThreader::ThreadHandle *pHandle =
1.89 + reinterpret_cast<WinThreader::ThreadHandle *>(param);
1.90 +
1.91 + pHandle->m_run->RunThread(pHandle);
1.92 +
1.93 + ThreadParams params;
1.94 + EnterCriticalSection(&pHandle->m_crit);
1.95 + pHandle->m_state = Thread_Done;
1.96 + pHandle->GetParams(¶ms);
1.97 + LeaveCriticalSection(&pHandle->m_crit);
1.98 +
1.99 + pHandle->m_run->OnTerminate(pHandle, false);
1.100 + if (params.flags & Thread_AutoRelease)
1.101 + delete pHandle;
1.102 +
1.103 + return 0;
1.104 +}
1.105 +
1.106 +void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
1.107 +{
1.108 + max = ThreadPrio_Maximum;
1.109 + min = ThreadPrio_Minimum;
1.110 +}
1.111 +
1.112 +ThreadParams g_defparams;
1.113 +IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
1.114 +{
1.115 + if (params == NULL)
1.116 + params = &g_defparams;
1.117 +
1.118 + WinThreader::ThreadHandle *pHandle =
1.119 + new WinThreader::ThreadHandle(this, NULL, pThread, params);
1.120 +
1.121 + DWORD tid;
1.122 + pHandle->m_thread =
1.123 + CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
1.124 +
1.125 + if (!pHandle->m_thread)
1.126 + {
1.127 + delete pHandle;
1.128 + return NULL;
1.129 + }
1.130 +
1.131 + if (pHandle->m_params.prio != ThreadPrio_Normal)
1.132 + {
1.133 + pHandle->SetPriority(pHandle->m_params.prio);
1.134 + }
1.135 +
1.136 + if (!(pHandle->m_params.flags & Thread_CreateSuspended))
1.137 + {
1.138 + pHandle->Unpause();
1.139 + }
1.140 +
1.141 + return pHandle;
1.142 +}
1.143 +
1.144 +IEventSignal *WinThreader::MakeEventSignal()
1.145 +{
1.146 + HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
1.147 +
1.148 + if (!event)
1.149 + return NULL;
1.150 +
1.151 + WinEvent *pEvent = new WinEvent(event);
1.152 +
1.153 + return pEvent;
1.154 +}
1.155 +
1.156 +/*****************
1.157 + **** Mutexes ****
1.158 + *****************/
1.159 +
1.160 +WinThreader::WinMutex::WinMutex()
1.161 +{
1.162 + InitializeCriticalSection(&m_crit);
1.163 +}
1.164 +
1.165 +WinThreader::WinMutex::~WinMutex()
1.166 +{
1.167 + DeleteCriticalSection(&m_crit);
1.168 +}
1.169 +
1.170 +bool WinThreader::WinMutex::TryLock()
1.171 +{
1.172 + return (TryEnterCriticalSection(&m_crit) != FALSE);
1.173 +}
1.174 +
1.175 +void WinThreader::WinMutex::Lock()
1.176 +{
1.177 + EnterCriticalSection(&m_crit);
1.178 +}
1.179 +
1.180 +void WinThreader::WinMutex::Unlock()
1.181 +{
1.182 + LeaveCriticalSection(&m_crit);
1.183 +}
1.184 +
1.185 +void WinThreader::WinMutex::DestroyThis()
1.186 +{
1.187 + delete this;
1.188 +}
1.189 +
1.190 +/******************
1.191 + * Thread Handles *
1.192 + ******************/
1.193 +
1.194 +WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) :
1.195 + m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
1.196 + m_state(Thread_Paused)
1.197 +{
1.198 + InitializeCriticalSection(&m_crit);
1.199 +}
1.200 +
1.201 +WinThreader::ThreadHandle::~ThreadHandle()
1.202 +{
1.203 + if (m_thread)
1.204 + {
1.205 + CloseHandle(m_thread);
1.206 + m_thread = NULL;
1.207 + }
1.208 + DeleteCriticalSection(&m_crit);
1.209 +}
1.210 +
1.211 +bool WinThreader::ThreadHandle::WaitForThread()
1.212 +{
1.213 + if (m_thread == NULL)
1.214 + return false;
1.215 +
1.216 + if (WaitForSingleObject(m_thread, INFINITE) != 0)
1.217 + return false;
1.218 +
1.219 + return true;
1.220 +}
1.221 +
1.222 +ThreadState WinThreader::ThreadHandle::GetState()
1.223 +{
1.224 + ThreadState state;
1.225 +
1.226 + EnterCriticalSection(&m_crit);
1.227 + state = m_state;
1.228 + LeaveCriticalSection(&m_crit);
1.229 +
1.230 + return state;
1.231 +}
1.232 +
1.233 +IThreadCreator *WinThreader::ThreadHandle::Parent()
1.234 +{
1.235 + return m_parent;
1.236 +}
1.237 +
1.238 +void WinThreader::ThreadHandle::DestroyThis()
1.239 +{
1.240 + if (m_params.flags & Thread_AutoRelease)
1.241 + return;
1.242 +
1.243 + delete this;
1.244 +}
1.245 +
1.246 +void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
1.247 +{
1.248 + if (!ptparams)
1.249 + return;
1.250 +
1.251 + *ptparams = m_params;
1.252 +}
1.253 +
1.254 +ThreadPriority WinThreader::ThreadHandle::GetPriority()
1.255 +{
1.256 + return m_params.prio;
1.257 +}
1.258 +
1.259 +bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
1.260 +{
1.261 + if (!m_thread)
1.262 + return false;
1.263 +
1.264 + BOOL res = FALSE;
1.265 +
1.266 + if (prio >= ThreadPrio_Maximum)
1.267 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
1.268 + else if (prio <= ThreadPrio_Minimum)
1.269 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
1.270 + else if (prio == ThreadPrio_Normal)
1.271 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
1.272 + else if (prio == ThreadPrio_High)
1.273 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
1.274 + else if (prio == ThreadPrio_Low)
1.275 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
1.276 +
1.277 + m_params.prio = prio;
1.278 +
1.279 + return (res != FALSE);
1.280 +}
1.281 +
1.282 +bool WinThreader::ThreadHandle::Unpause()
1.283 +{
1.284 + if (!m_thread)
1.285 + return false;
1.286 +
1.287 + if (m_state != Thread_Paused)
1.288 + return false;
1.289 +
1.290 + m_state = Thread_Running;
1.291 +
1.292 + if (ResumeThread(m_thread) == -1)
1.293 + {
1.294 + m_state = Thread_Paused;
1.295 + return false;
1.296 + }
1.297 +
1.298 + return true;
1.299 +}
1.300 +
1.301 +/*****************
1.302 + * EVENT SIGNALS *
1.303 + *****************/
1.304 +
1.305 +WinThreader::WinEvent::~WinEvent()
1.306 +{
1.307 + CloseHandle(m_event);
1.308 +}
1.309 +
1.310 +void WinThreader::WinEvent::Wait()
1.311 +{
1.312 + WaitForSingleObject(m_event, INFINITE);
1.313 +}
1.314 +
1.315 +void WinThreader::WinEvent::Signal()
1.316 +{
1.317 + SetEvent(m_event);
1.318 +}
1.319 +
1.320 +void WinThreader::WinEvent::DestroyThis()
1.321 +{
1.322 + delete this;
1.323 +}