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