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