core/thread/WinThreads.cpp
author Michael McKoy <ferret99gt@gmail.com>
Wed Aug 08 23:26:42 2007 +0000 (2007-08-08)
changeset 1280 13c62962a9ef
parent 1231 17badaf66ce4
child 1330 ab94316bb52b
permissions -rw-r--r--
Corrected filename in header of basefuncommands.sp
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or 
     9  * modify it under the terms of the GNU General Public License, 
    10  * version 3.0, as published by the Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to 
    21  * link the code of this program (as well as its derivative works) to 
    22  * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
    23  * Game MODs that run on software by the Valve Corporation.  You must 
    24  * obey the GNU General Public License in all respects for all other 
    25  * code used. Additionally, AlliedModders LLC grants this exception 
    26  * to all derivative works. AlliedModders LLC defines further 
    27  * exceptions, found in LICENSE.txt (as of this writing, version 
    28  * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #define _WIN32_WINNT 0x0400
    34 #include "WinThreads.h"
    35 #include "ThreadWorker.h"
    36 
    37 IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
    38 {
    39 	if (threaded)
    40 	{
    41 		return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
    42 	} else {
    43 		return new BaseWorker(hooks);
    44 	}
    45 }
    46 
    47 void WinThreader::DestroyWorker(IThreadWorker *pWorker)
    48 {
    49 	delete pWorker;
    50 }
    51 
    52 void WinThreader::ThreadSleep(unsigned int ms)
    53 {
    54 	Sleep((DWORD)ms);
    55 }
    56 
    57 IMutex *WinThreader::MakeMutex()
    58 {
    59 	WinMutex *pMutex = new WinMutex();
    60 
    61 	return pMutex;
    62 }
    63 
    64 IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
    65 {
    66 	ThreadParams defparams;
    67 
    68 	defparams.flags = flags;
    69 	defparams.prio = ThreadPrio_Normal;
    70 
    71 	return MakeThread(pThread, &defparams);
    72 }
    73 
    74 void WinThreader::MakeThread(IThread *pThread)
    75 {
    76 	ThreadParams defparams;
    77 
    78 	defparams.flags = Thread_AutoRelease;
    79 	defparams.prio = ThreadPrio_Normal;
    80 
    81 	MakeThread(pThread, &defparams);
    82 }
    83 
    84 DWORD WINAPI Win32_ThreadGate(LPVOID param)
    85 {
    86 	WinThreader::ThreadHandle *pHandle = 
    87 		reinterpret_cast<WinThreader::ThreadHandle *>(param);
    88 
    89 	pHandle->m_run->RunThread(pHandle);
    90 
    91 	ThreadParams params;
    92 	EnterCriticalSection(&pHandle->m_crit);
    93 	pHandle->m_state = Thread_Done;
    94 	pHandle->GetParams(&params);
    95 	LeaveCriticalSection(&pHandle->m_crit);
    96 
    97 	pHandle->m_run->OnTerminate(pHandle, false);
    98 	if (params.flags & Thread_AutoRelease)
    99 		delete pHandle;
   100 
   101 	return 0;
   102 }
   103 
   104 void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
   105 {
   106 	max = ThreadPrio_Maximum;
   107 	min = ThreadPrio_Minimum;
   108 }
   109 
   110 ThreadParams g_defparams;
   111 IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
   112 {
   113 	if (params == NULL)
   114 		params = &g_defparams;
   115 
   116 	WinThreader::ThreadHandle *pHandle = 
   117 		new WinThreader::ThreadHandle(this, NULL, pThread, params);
   118 
   119 	DWORD tid;
   120 	pHandle->m_thread = 
   121 		CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
   122 
   123 	if (!pHandle->m_thread)
   124 	{
   125 		delete pHandle;
   126 		return NULL;
   127 	}
   128 
   129 	if (pHandle->m_params.prio != ThreadPrio_Normal)
   130 	{
   131 		pHandle->SetPriority(pHandle->m_params.prio);
   132 	}
   133 
   134 	if (!(pHandle->m_params.flags & Thread_CreateSuspended))
   135 	{
   136 		pHandle->Unpause();
   137 	}
   138 
   139 	return pHandle;
   140 }
   141 
   142 IEventSignal *WinThreader::MakeEventSignal()
   143 {
   144 	HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
   145 
   146 	if (!event)
   147 		return NULL;
   148 
   149 	WinEvent *pEvent = new WinEvent(event);
   150 
   151 	return pEvent;
   152 }
   153 
   154 /*****************
   155  **** Mutexes ****
   156  *****************/
   157 
   158 WinThreader::WinMutex::WinMutex()
   159 {
   160 	InitializeCriticalSection(&m_crit);
   161 }
   162 
   163 WinThreader::WinMutex::~WinMutex()
   164 {
   165 	DeleteCriticalSection(&m_crit);
   166 }
   167 
   168 bool WinThreader::WinMutex::TryLock()
   169 {
   170 	return (TryEnterCriticalSection(&m_crit) != FALSE);
   171 }
   172 
   173 void WinThreader::WinMutex::Lock()
   174 {
   175 	EnterCriticalSection(&m_crit);
   176 }
   177 
   178 void WinThreader::WinMutex::Unlock()
   179 {
   180 	LeaveCriticalSection(&m_crit);
   181 }
   182 
   183 void WinThreader::WinMutex::DestroyThis()
   184 {
   185 	delete this;
   186 }
   187 
   188 /******************
   189  * Thread Handles *
   190  ******************/
   191 
   192 WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) : 
   193 	m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
   194 	m_state(Thread_Paused)
   195 {
   196 	InitializeCriticalSection(&m_crit);
   197 }
   198 
   199 WinThreader::ThreadHandle::~ThreadHandle()
   200 {
   201 	if (m_thread)
   202 	{
   203 		CloseHandle(m_thread);
   204 		m_thread = NULL;
   205 	}
   206 	DeleteCriticalSection(&m_crit);
   207 }
   208 
   209 bool WinThreader::ThreadHandle::WaitForThread()
   210 {
   211 	if (m_thread == NULL)
   212 		return false;
   213 
   214 	if (WaitForSingleObject(m_thread, INFINITE) != 0)
   215 		return false;
   216 
   217 	return true;
   218 }
   219 
   220 ThreadState WinThreader::ThreadHandle::GetState()
   221 {
   222 	ThreadState state;
   223 
   224 	EnterCriticalSection(&m_crit);
   225 	state = m_state;
   226 	LeaveCriticalSection(&m_crit);
   227 
   228 	return state;
   229 }
   230 
   231 IThreadCreator *WinThreader::ThreadHandle::Parent()
   232 {
   233 	return m_parent;
   234 }
   235 
   236 void WinThreader::ThreadHandle::DestroyThis()
   237 {
   238 	if (m_params.flags & Thread_AutoRelease)
   239 		return;
   240 
   241 	delete this;
   242 }
   243 
   244 void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
   245 {
   246 	if (!ptparams)
   247 		return;
   248 
   249 	*ptparams = m_params;
   250 }
   251 
   252 ThreadPriority WinThreader::ThreadHandle::GetPriority()
   253 {
   254 	return m_params.prio;
   255 }
   256 
   257 bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
   258 {
   259 	if (!m_thread)
   260 		return false;
   261 
   262 	BOOL res = FALSE;
   263 
   264 	if (prio >= ThreadPrio_Maximum)
   265 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
   266 	else if (prio <= ThreadPrio_Minimum)
   267 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
   268 	else if (prio == ThreadPrio_Normal)
   269 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
   270 	else if (prio == ThreadPrio_High)
   271 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
   272 	else if (prio == ThreadPrio_Low)
   273 		res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
   274 
   275 	m_params.prio = prio;
   276 
   277 	return (res != FALSE);
   278 }
   279 
   280 bool WinThreader::ThreadHandle::Unpause()
   281 {
   282 	if (!m_thread)
   283 		return false;
   284 
   285 	if (m_state != Thread_Paused)
   286 		return false;
   287 
   288 	m_state = Thread_Running;
   289 
   290 	if (ResumeThread(m_thread) == -1)
   291 	{
   292 		m_state = Thread_Paused;
   293 		return false;
   294 	}
   295 
   296 	return true;
   297 }
   298 
   299 /*****************
   300  * EVENT SIGNALS *
   301  *****************/
   302 
   303 WinThreader::WinEvent::~WinEvent()
   304 {
   305 	CloseHandle(m_event);
   306 }
   307 
   308 void WinThreader::WinEvent::Wait()
   309 {
   310 	WaitForSingleObject(m_event, INFINITE);
   311 }
   312 
   313 void WinThreader::WinEvent::Signal()
   314 {
   315 	SetEvent(m_event);
   316 }
   317 
   318 void WinThreader::WinEvent::DestroyThis()
   319 {
   320 	delete this;
   321 }