core/thread/WinThreads.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1231 17badaf66ce4
child 1947 e73a1e51833b
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

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