1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/thread/WinThreads.cpp Mon Jul 09 16:10:23 2007 +0000
1.3 @@ -0,0 +1,318 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * ===============================================================
1.7 + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
1.8 + * ===============================================================
1.9 + *
1.10 + * This file is not open source and may not be copied without explicit
1.11 + * written permission of AlliedModders LLC. This file may not be redistributed
1.12 + * in whole or significant part.
1.13 + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
1.14 + *
1.15 + * Version: $Id$
1.16 + */
1.17 +
1.18 +#include "WinThreads.h"
1.19 +#include "ThreadWorker.h"
1.20 +
1.21 +IThreadWorker *WinThreader::MakeWorker(bool threaded)
1.22 +{
1.23 + if (threaded)
1.24 + {
1.25 + return new ThreadWorker(this, DEFAULT_THINK_TIME_MS);
1.26 + } else {
1.27 + return new BaseWorker();
1.28 + }
1.29 +}
1.30 +
1.31 +void WinThreader::DestroyWorker(IThreadWorker *pWorker)
1.32 +{
1.33 + delete pWorker;
1.34 +}
1.35 +
1.36 +void WinThreader::ThreadSleep(unsigned int ms)
1.37 +{
1.38 + Sleep((DWORD)ms);
1.39 +}
1.40 +
1.41 +IMutex *WinThreader::MakeMutex()
1.42 +{
1.43 + HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
1.44 +
1.45 + if (mutex == NULL)
1.46 + return NULL;
1.47 +
1.48 + WinMutex *pMutex = new WinMutex(mutex);
1.49 +
1.50 + return pMutex;
1.51 +}
1.52 +
1.53 +IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
1.54 +{
1.55 + ThreadParams defparams;
1.56 +
1.57 + defparams.flags = flags;
1.58 + defparams.prio = ThreadPrio_Normal;
1.59 +
1.60 + return MakeThread(pThread, &defparams);
1.61 +}
1.62 +
1.63 +void WinThreader::MakeThread(IThread *pThread)
1.64 +{
1.65 + ThreadParams defparams;
1.66 +
1.67 + defparams.flags = Thread_AutoRelease;
1.68 + defparams.prio = ThreadPrio_Normal;
1.69 +
1.70 + MakeThread(pThread, &defparams);
1.71 +}
1.72 +
1.73 +DWORD WINAPI Win32_ThreadGate(LPVOID param)
1.74 +{
1.75 + WinThreader::ThreadHandle *pHandle =
1.76 + reinterpret_cast<WinThreader::ThreadHandle *>(param);
1.77 +
1.78 + pHandle->m_run->RunThread(pHandle);
1.79 +
1.80 + ThreadParams params;
1.81 + EnterCriticalSection(&pHandle->m_crit);
1.82 + pHandle->m_state = Thread_Done;
1.83 + pHandle->GetParams(¶ms);
1.84 + LeaveCriticalSection(&pHandle->m_crit);
1.85 +
1.86 + pHandle->m_run->OnTerminate(pHandle, false);
1.87 + if (params.flags & Thread_AutoRelease)
1.88 + delete pHandle;
1.89 +
1.90 + return 0;
1.91 +}
1.92 +
1.93 +void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
1.94 +{
1.95 + max = ThreadPrio_Maximum;
1.96 + min = ThreadPrio_Minimum;
1.97 +}
1.98 +
1.99 +ThreadParams g_defparams;
1.100 +IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
1.101 +{
1.102 + if (params == NULL)
1.103 + params = &g_defparams;
1.104 +
1.105 + WinThreader::ThreadHandle *pHandle =
1.106 + new WinThreader::ThreadHandle(this, NULL, pThread, params);
1.107 +
1.108 + DWORD tid;
1.109 + pHandle->m_thread =
1.110 + CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
1.111 +
1.112 + if (!pHandle->m_thread)
1.113 + {
1.114 + delete pHandle;
1.115 + return NULL;
1.116 + }
1.117 +
1.118 + if (pHandle->m_params.prio != ThreadPrio_Normal)
1.119 + {
1.120 + pHandle->SetPriority(pHandle->m_params.prio);
1.121 + }
1.122 +
1.123 + if (!(pHandle->m_params.flags & Thread_CreateSuspended))
1.124 + {
1.125 + pHandle->Unpause();
1.126 + }
1.127 +
1.128 + return pHandle;
1.129 +}
1.130 +
1.131 +IEventSignal *WinThreader::MakeEventSignal()
1.132 +{
1.133 + HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
1.134 +
1.135 + if (!event)
1.136 + return NULL;
1.137 +
1.138 + WinEvent *pEvent = new WinEvent(event);
1.139 +
1.140 + return pEvent;
1.141 +}
1.142 +
1.143 +/*****************
1.144 + **** Mutexes ****
1.145 + *****************/
1.146 +
1.147 +WinThreader::WinMutex::~WinMutex()
1.148 +{
1.149 + if (m_mutex)
1.150 + {
1.151 + CloseHandle(m_mutex);
1.152 + m_mutex = NULL;
1.153 + }
1.154 +}
1.155 +
1.156 +bool WinThreader::WinMutex::TryLock()
1.157 +{
1.158 + if (!m_mutex)
1.159 + return false;
1.160 +
1.161 + if (WaitForSingleObject(m_mutex, 0) != WAIT_FAILED)
1.162 + return true;
1.163 +
1.164 + return false;
1.165 +}
1.166 +
1.167 +void WinThreader::WinMutex::Lock()
1.168 +{
1.169 + if (!m_mutex)
1.170 + return;
1.171 +
1.172 + WaitForSingleObject(m_mutex, INFINITE);
1.173 +}
1.174 +
1.175 +void WinThreader::WinMutex::Unlock()
1.176 +{
1.177 + if (!m_mutex)
1.178 + return;
1.179 +
1.180 + ReleaseMutex(m_mutex);
1.181 +}
1.182 +
1.183 +void WinThreader::WinMutex::DestroyThis()
1.184 +{
1.185 + delete this;
1.186 +}
1.187 +
1.188 +/******************
1.189 + * Thread Handles *
1.190 + ******************/
1.191 +
1.192 +WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) :
1.193 + m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
1.194 + m_state(Thread_Paused)
1.195 +{
1.196 + InitializeCriticalSection(&m_crit);
1.197 +}
1.198 +
1.199 +WinThreader::ThreadHandle::~ThreadHandle()
1.200 +{
1.201 + if (m_thread)
1.202 + {
1.203 + CloseHandle(m_thread);
1.204 + m_thread = NULL;
1.205 + }
1.206 + DeleteCriticalSection(&m_crit);
1.207 +}
1.208 +
1.209 +bool WinThreader::ThreadHandle::WaitForThread()
1.210 +{
1.211 + if (m_thread == NULL)
1.212 + return false;
1.213 +
1.214 + if (WaitForSingleObject(m_thread, INFINITE) != 0)
1.215 + return false;
1.216 +
1.217 + return true;
1.218 +}
1.219 +
1.220 +ThreadState WinThreader::ThreadHandle::GetState()
1.221 +{
1.222 + ThreadState state;
1.223 +
1.224 + EnterCriticalSection(&m_crit);
1.225 + state = m_state;
1.226 + LeaveCriticalSection(&m_crit);
1.227 +
1.228 + return state;
1.229 +}
1.230 +
1.231 +IThreadCreator *WinThreader::ThreadHandle::Parent()
1.232 +{
1.233 + return m_parent;
1.234 +}
1.235 +
1.236 +void WinThreader::ThreadHandle::DestroyThis()
1.237 +{
1.238 + if (m_params.flags & Thread_AutoRelease)
1.239 + return;
1.240 +
1.241 + delete this;
1.242 +}
1.243 +
1.244 +void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
1.245 +{
1.246 + if (!ptparams)
1.247 + return;
1.248 +
1.249 + *ptparams = m_params;
1.250 +}
1.251 +
1.252 +ThreadPriority WinThreader::ThreadHandle::GetPriority()
1.253 +{
1.254 + return m_params.prio;
1.255 +}
1.256 +
1.257 +bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
1.258 +{
1.259 + if (!m_thread)
1.260 + return false;
1.261 +
1.262 + BOOL res = FALSE;
1.263 +
1.264 + if (prio >= ThreadPrio_Maximum)
1.265 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
1.266 + else if (prio <= ThreadPrio_Minimum)
1.267 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
1.268 + else if (prio == ThreadPrio_Normal)
1.269 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
1.270 + else if (prio == ThreadPrio_High)
1.271 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
1.272 + else if (prio == ThreadPrio_Low)
1.273 + res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
1.274 +
1.275 + m_params.prio = prio;
1.276 +
1.277 + return (res != FALSE);
1.278 +}
1.279 +
1.280 +bool WinThreader::ThreadHandle::Unpause()
1.281 +{
1.282 + if (!m_thread)
1.283 + return false;
1.284 +
1.285 + if (m_state != Thread_Paused)
1.286 + return false;
1.287 +
1.288 + m_state = Thread_Running;
1.289 +
1.290 + if (ResumeThread(m_thread) == -1)
1.291 + {
1.292 + m_state = Thread_Paused;
1.293 + return false;
1.294 + }
1.295 +
1.296 + return true;
1.297 +}
1.298 +
1.299 +/*****************
1.300 + * EVENT SIGNALS *
1.301 + *****************/
1.302 +
1.303 +WinThreader::WinEvent::~WinEvent()
1.304 +{
1.305 + CloseHandle(m_event);
1.306 +}
1.307 +
1.308 +void WinThreader::WinEvent::Wait()
1.309 +{
1.310 + WaitForSingleObject(m_event, INFINITE);
1.311 +}
1.312 +
1.313 +void WinThreader::WinEvent::Signal()
1.314 +{
1.315 + SetEvent(m_event);
1.316 +}
1.317 +
1.318 +void WinThreader::WinEvent::DestroyThis()
1.319 +{
1.320 + delete this;
1.321 +}