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