core/thread/WinThreads.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jul 12 16:57:26 2007 +0000 (2007-07-12)
changeset 1090 5c54e353c019
parent 1087 a7ee64117faf
child 1231 17badaf66ce4
permissions -rw-r--r--
- added callback functionality to IThreadWorker
- added exposure of IThreader to sample sdk
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #define _WIN32_WINNT 0x0400
    16 #include "WinThreads.h"
    17 #include "ThreadWorker.h"
    18 
    19 IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
    20 {
    21 	if (threaded)
    22 	{
    23 		return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
    24 	} else {
    25 		return new BaseWorker(hooks);
    26 	}
    27 }
    28 
    29 void WinThreader::DestroyWorker(IThreadWorker *pWorker)
    30 {
    31 	delete pWorker;
    32 }
    33 
    34 void WinThreader::ThreadSleep(unsigned int ms)
    35 {
    36 	Sleep((DWORD)ms);
    37 }
    38 
    39 IMutex *WinThreader::MakeMutex()
    40 {
    41 	WinMutex *pMutex = new WinMutex();
    42 
    43 	return pMutex;
    44 }
    45 
    46 IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
    47 {
    48 	ThreadParams defparams;
    49 
    50 	defparams.flags = flags;
    51 	defparams.prio = ThreadPrio_Normal;
    52 
    53 	return MakeThread(pThread, &defparams);
    54 }
    55 
    56 void WinThreader::MakeThread(IThread *pThread)
    57 {
    58 	ThreadParams defparams;
    59 
    60 	defparams.flags = Thread_AutoRelease;
    61 	defparams.prio = ThreadPrio_Normal;
    62 
    63 	MakeThread(pThread, &defparams);
    64 }
    65 
    66 DWORD WINAPI Win32_ThreadGate(LPVOID param)
    67 {
    68 	WinThreader::ThreadHandle *pHandle = 
    69 		reinterpret_cast<WinThreader::ThreadHandle *>(param);
    70 
    71 	pHandle->m_run->RunThread(pHandle);
    72 
    73 	ThreadParams params;
    74 	EnterCriticalSection(&pHandle->m_crit);
    75 	pHandle->m_state = Thread_Done;
    76 	pHandle->GetParams(&params);
    77 	LeaveCriticalSection(&pHandle->m_crit);
    78 
    79 	pHandle->m_run->OnTerminate(pHandle, false);
    80 	if (params.flags & Thread_AutoRelease)
    81 		delete pHandle;
    82 
    83 	return 0;
    84 }
    85 
    86 void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
    87 {
    88 	max = ThreadPrio_Maximum;
    89 	min = ThreadPrio_Minimum;
    90 }
    91 
    92 ThreadParams g_defparams;
    93 IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
    94 {
    95 	if (params == NULL)
    96 		params = &g_defparams;
    97 
    98 	WinThreader::ThreadHandle *pHandle = 
    99 		new WinThreader::ThreadHandle(this, NULL, pThread, params);
   100 
   101 	DWORD tid;
   102 	pHandle->m_thread = 
   103 		CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
   104 
   105 	if (!pHandle->m_thread)
   106 	{
   107 		delete pHandle;
   108 		return NULL;
   109 	}
   110 
   111 	if (pHandle->m_params.prio != ThreadPrio_Normal)
   112 	{
   113 		pHandle->SetPriority(pHandle->m_params.prio);
   114 	}
   115 
   116 	if (!(pHandle->m_params.flags & Thread_CreateSuspended))
   117 	{
   118 		pHandle->Unpause();
   119 	}
   120 
   121 	return pHandle;
   122 }
   123 
   124 IEventSignal *WinThreader::MakeEventSignal()
   125 {
   126 	HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
   127 
   128 	if (!event)
   129 		return NULL;
   130 
   131 	WinEvent *pEvent = new WinEvent(event);
   132 
   133 	return pEvent;
   134 }
   135 
   136 /*****************
   137  **** Mutexes ****
   138  *****************/
   139 
   140 WinThreader::WinMutex::WinMutex()
   141 {
   142 	InitializeCriticalSection(&m_crit);
   143 }
   144 
   145 WinThreader::WinMutex::~WinMutex()
   146 {
   147 	DeleteCriticalSection(&m_crit);
   148 }
   149 
   150 bool WinThreader::WinMutex::TryLock()
   151 {
   152 	return (TryEnterCriticalSection(&m_crit) != FALSE);
   153 }
   154 
   155 void WinThreader::WinMutex::Lock()
   156 {
   157 	EnterCriticalSection(&m_crit);
   158 }
   159 
   160 void WinThreader::WinMutex::Unlock()
   161 {
   162 	LeaveCriticalSection(&m_crit);
   163 }
   164 
   165 void WinThreader::WinMutex::DestroyThis()
   166 {
   167 	delete this;
   168 }
   169 
   170 /******************
   171  * Thread Handles *
   172  ******************/
   173 
   174 WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) : 
   175 	m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
   176 	m_state(Thread_Paused)
   177 {
   178 	InitializeCriticalSection(&m_crit);
   179 }
   180 
   181 WinThreader::ThreadHandle::~ThreadHandle()
   182 {
   183 	if (m_thread)
   184 	{
   185 		CloseHandle(m_thread);
   186 		m_thread = NULL;
   187 	}
   188 	DeleteCriticalSection(&m_crit);
   189 }
   190 
   191 bool WinThreader::ThreadHandle::WaitForThread()
   192 {
   193 	if (m_thread == NULL)
   194 		return false;
   195 
   196 	if (WaitForSingleObject(m_thread, INFINITE) != 0)
   197 		return false;
   198 
   199 	return true;
   200 }
   201 
   202 ThreadState WinThreader::ThreadHandle::GetState()
   203 {
   204 	ThreadState state;
   205 
   206 	EnterCriticalSection(&m_crit);
   207 	state = m_state;
   208 	LeaveCriticalSection(&m_crit);
   209 
   210 	return state;
   211 }
   212 
   213 IThreadCreator *WinThreader::ThreadHandle::Parent()
   214 {
   215 	return m_parent;
   216 }
   217 
   218 void WinThreader::ThreadHandle::DestroyThis()
   219 {
   220 	if (m_params.flags & Thread_AutoRelease)
   221 		return;
   222 
   223 	delete this;
   224 }
   225 
   226 void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
   227 {
   228 	if (!ptparams)
   229 		return;
   230 
   231 	*ptparams = m_params;
   232 }
   233 
   234 ThreadPriority WinThreader::ThreadHandle::GetPriority()
   235 {
   236 	return m_params.prio;
   237 }
   238 
   239 bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
   240 {
   241 	if (!m_thread)
   242 		return false;
   243 
   244 	BOOL res = FALSE;
   245 
   246 	if (prio >= ThreadPrio_Maximum)
   247 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
   248 	else if (prio <= ThreadPrio_Minimum)
   249 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
   250 	else if (prio == ThreadPrio_Normal)
   251 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
   252 	else if (prio == ThreadPrio_High)
   253 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
   254 	else if (prio == ThreadPrio_Low)
   255 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
   256 
   257 	m_params.prio = prio;
   258 
   259 	return (res != FALSE);
   260 }
   261 
   262 bool WinThreader::ThreadHandle::Unpause()
   263 {
   264 	if (!m_thread)
   265 		return false;
   266 
   267 	if (m_state != Thread_Paused)
   268 		return false;
   269 
   270 	m_state = Thread_Running;
   271 
   272 	if (ResumeThread(m_thread) == -1)
   273 	{
   274 		m_state = Thread_Paused;
   275 		return false;
   276 	}
   277 
   278 	return true;
   279 }
   280 
   281 /*****************
   282  * EVENT SIGNALS *
   283  *****************/
   284 
   285 WinThreader::WinEvent::~WinEvent()
   286 {
   287 	CloseHandle(m_event);
   288 }
   289 
   290 void WinThreader::WinEvent::Wait()
   291 {
   292 	WaitForSingleObject(m_event, INFINITE);
   293 }
   294 
   295 void WinThreader::WinEvent::Signal()
   296 {
   297 	SetEvent(m_event);
   298 }
   299 
   300 void WinThreader::WinEvent::DestroyThis()
   301 {
   302 	delete this;
   303 }