core/thread/WinThreads.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2289 44045ead61cd
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 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 }