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