core/thread/WinThreads.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jul 09 16:10:23 2007 +0000 (2007-07-09)
changeset 1084 241c1b9b4048
child 1087 a7ee64117faf
permissions -rw-r--r--
added threader to core (not used yet)
dvander@1084
     1
/**
dvander@1084
     2
 * vim: set ts=4 :
dvander@1084
     3
 * ===============================================================
dvander@1084
     4
 * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@1084
     5
 * ===============================================================
dvander@1084
     6
 *
dvander@1084
     7
 * This file is not open source and may not be copied without explicit
dvander@1084
     8
 * written permission of AlliedModders LLC.  This file may not be redistributed 
dvander@1084
     9
 * in whole or significant part.
dvander@1084
    10
 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
dvander@1084
    11
 *
dvander@1084
    12
 * Version: $Id$
dvander@1084
    13
 */
dvander@1084
    14
dvander@1084
    15
#include "WinThreads.h"
dvander@1084
    16
#include "ThreadWorker.h"
dvander@1084
    17
dvander@1084
    18
IThreadWorker *WinThreader::MakeWorker(bool threaded)
dvander@1084
    19
{
dvander@1084
    20
	if (threaded)
dvander@1084
    21
	{
dvander@1084
    22
		return new ThreadWorker(this, DEFAULT_THINK_TIME_MS);
dvander@1084
    23
	} else {
dvander@1084
    24
		return new BaseWorker();
dvander@1084
    25
	}
dvander@1084
    26
}
dvander@1084
    27
dvander@1084
    28
void WinThreader::DestroyWorker(IThreadWorker *pWorker)
dvander@1084
    29
{
dvander@1084
    30
	delete pWorker;
dvander@1084
    31
}
dvander@1084
    32
dvander@1084
    33
void WinThreader::ThreadSleep(unsigned int ms)
dvander@1084
    34
{
dvander@1084
    35
	Sleep((DWORD)ms);
dvander@1084
    36
}
dvander@1084
    37
dvander@1084
    38
IMutex *WinThreader::MakeMutex()
dvander@1084
    39
{
dvander@1084
    40
	HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
dvander@1084
    41
dvander@1084
    42
	if (mutex == NULL)
dvander@1084
    43
		return NULL;
dvander@1084
    44
dvander@1084
    45
	WinMutex *pMutex = new WinMutex(mutex);
dvander@1084
    46
dvander@1084
    47
	return pMutex;
dvander@1084
    48
}
dvander@1084
    49
dvander@1084
    50
IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
dvander@1084
    51
{
dvander@1084
    52
	ThreadParams defparams;
dvander@1084
    53
dvander@1084
    54
	defparams.flags = flags;
dvander@1084
    55
	defparams.prio = ThreadPrio_Normal;
dvander@1084
    56
dvander@1084
    57
	return MakeThread(pThread, &defparams);
dvander@1084
    58
}
dvander@1084
    59
dvander@1084
    60
void WinThreader::MakeThread(IThread *pThread)
dvander@1084
    61
{
dvander@1084
    62
	ThreadParams defparams;
dvander@1084
    63
dvander@1084
    64
	defparams.flags = Thread_AutoRelease;
dvander@1084
    65
	defparams.prio = ThreadPrio_Normal;
dvander@1084
    66
dvander@1084
    67
	MakeThread(pThread, &defparams);
dvander@1084
    68
}
dvander@1084
    69
dvander@1084
    70
DWORD WINAPI Win32_ThreadGate(LPVOID param)
dvander@1084
    71
{
dvander@1084
    72
	WinThreader::ThreadHandle *pHandle = 
dvander@1084
    73
		reinterpret_cast<WinThreader::ThreadHandle *>(param);
dvander@1084
    74
dvander@1084
    75
	pHandle->m_run->RunThread(pHandle);
dvander@1084
    76
dvander@1084
    77
	ThreadParams params;
dvander@1084
    78
	EnterCriticalSection(&pHandle->m_crit);
dvander@1084
    79
	pHandle->m_state = Thread_Done;
dvander@1084
    80
	pHandle->GetParams(&params);
dvander@1084
    81
	LeaveCriticalSection(&pHandle->m_crit);
dvander@1084
    82
dvander@1084
    83
	pHandle->m_run->OnTerminate(pHandle, false);
dvander@1084
    84
	if (params.flags & Thread_AutoRelease)
dvander@1084
    85
		delete pHandle;
dvander@1084
    86
dvander@1084
    87
	return 0;
dvander@1084
    88
}
dvander@1084
    89
dvander@1084
    90
void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
dvander@1084
    91
{
dvander@1084
    92
	max = ThreadPrio_Maximum;
dvander@1084
    93
	min = ThreadPrio_Minimum;
dvander@1084
    94
}
dvander@1084
    95
dvander@1084
    96
ThreadParams g_defparams;
dvander@1084
    97
IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
dvander@1084
    98
{
dvander@1084
    99
	if (params == NULL)
dvander@1084
   100
		params = &g_defparams;
dvander@1084
   101
dvander@1084
   102
	WinThreader::ThreadHandle *pHandle = 
dvander@1084
   103
		new WinThreader::ThreadHandle(this, NULL, pThread, params);
dvander@1084
   104
dvander@1084
   105
	DWORD tid;
dvander@1084
   106
	pHandle->m_thread = 
dvander@1084
   107
		CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
dvander@1084
   108
dvander@1084
   109
	if (!pHandle->m_thread)
dvander@1084
   110
	{
dvander@1084
   111
		delete pHandle;
dvander@1084
   112
		return NULL;
dvander@1084
   113
	}
dvander@1084
   114
dvander@1084
   115
	if (pHandle->m_params.prio != ThreadPrio_Normal)
dvander@1084
   116
	{
dvander@1084
   117
		pHandle->SetPriority(pHandle->m_params.prio);
dvander@1084
   118
	}
dvander@1084
   119
dvander@1084
   120
	if (!(pHandle->m_params.flags & Thread_CreateSuspended))
dvander@1084
   121
	{
dvander@1084
   122
		pHandle->Unpause();
dvander@1084
   123
	}
dvander@1084
   124
dvander@1084
   125
	return pHandle;
dvander@1084
   126
}
dvander@1084
   127
dvander@1084
   128
IEventSignal *WinThreader::MakeEventSignal()
dvander@1084
   129
{
dvander@1084
   130
	HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
dvander@1084
   131
dvander@1084
   132
	if (!event)
dvander@1084
   133
		return NULL;
dvander@1084
   134
dvander@1084
   135
	WinEvent *pEvent = new WinEvent(event);
dvander@1084
   136
dvander@1084
   137
	return pEvent;
dvander@1084
   138
}
dvander@1084
   139
dvander@1084
   140
/*****************
dvander@1084
   141
 **** Mutexes ****
dvander@1084
   142
 *****************/
dvander@1084
   143
dvander@1084
   144
WinThreader::WinMutex::~WinMutex()
dvander@1084
   145
{
dvander@1084
   146
	if (m_mutex)
dvander@1084
   147
	{
dvander@1084
   148
		CloseHandle(m_mutex);
dvander@1084
   149
		m_mutex = NULL;
dvander@1084
   150
	}
dvander@1084
   151
}
dvander@1084
   152
dvander@1084
   153
bool WinThreader::WinMutex::TryLock()
dvander@1084
   154
{
dvander@1084
   155
	if (!m_mutex)
dvander@1084
   156
		return false;
dvander@1084
   157
dvander@1084
   158
	if (WaitForSingleObject(m_mutex, 0) != WAIT_FAILED)
dvander@1084
   159
		return true;
dvander@1084
   160
dvander@1084
   161
	return false;
dvander@1084
   162
}
dvander@1084
   163
dvander@1084
   164
void WinThreader::WinMutex::Lock()
dvander@1084
   165
{
dvander@1084
   166
	if (!m_mutex)
dvander@1084
   167
		return;
dvander@1084
   168
dvander@1084
   169
	WaitForSingleObject(m_mutex, INFINITE);
dvander@1084
   170
}
dvander@1084
   171
dvander@1084
   172
void WinThreader::WinMutex::Unlock()
dvander@1084
   173
{
dvander@1084
   174
	if (!m_mutex)
dvander@1084
   175
		return;
dvander@1084
   176
dvander@1084
   177
	ReleaseMutex(m_mutex);
dvander@1084
   178
}
dvander@1084
   179
dvander@1084
   180
void WinThreader::WinMutex::DestroyThis()
dvander@1084
   181
{
dvander@1084
   182
	delete this;
dvander@1084
   183
}
dvander@1084
   184
dvander@1084
   185
/******************
dvander@1084
   186
 * Thread Handles *
dvander@1084
   187
 ******************/
dvander@1084
   188
dvander@1084
   189
WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) : 
dvander@1084
   190
	m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
dvander@1084
   191
	m_state(Thread_Paused)
dvander@1084
   192
{
dvander@1084
   193
	InitializeCriticalSection(&m_crit);
dvander@1084
   194
}
dvander@1084
   195
dvander@1084
   196
WinThreader::ThreadHandle::~ThreadHandle()
dvander@1084
   197
{
dvander@1084
   198
	if (m_thread)
dvander@1084
   199
	{
dvander@1084
   200
		CloseHandle(m_thread);
dvander@1084
   201
		m_thread = NULL;
dvander@1084
   202
	}
dvander@1084
   203
	DeleteCriticalSection(&m_crit);
dvander@1084
   204
}
dvander@1084
   205
dvander@1084
   206
bool WinThreader::ThreadHandle::WaitForThread()
dvander@1084
   207
{
dvander@1084
   208
	if (m_thread == NULL)
dvander@1084
   209
		return false;
dvander@1084
   210
dvander@1084
   211
	if (WaitForSingleObject(m_thread, INFINITE) != 0)
dvander@1084
   212
		return false;
dvander@1084
   213
dvander@1084
   214
	return true;
dvander@1084
   215
}
dvander@1084
   216
dvander@1084
   217
ThreadState WinThreader::ThreadHandle::GetState()
dvander@1084
   218
{
dvander@1084
   219
	ThreadState state;
dvander@1084
   220
dvander@1084
   221
	EnterCriticalSection(&m_crit);
dvander@1084
   222
	state = m_state;
dvander@1084
   223
	LeaveCriticalSection(&m_crit);
dvander@1084
   224
dvander@1084
   225
	return state;
dvander@1084
   226
}
dvander@1084
   227
dvander@1084
   228
IThreadCreator *WinThreader::ThreadHandle::Parent()
dvander@1084
   229
{
dvander@1084
   230
	return m_parent;
dvander@1084
   231
}
dvander@1084
   232
dvander@1084
   233
void WinThreader::ThreadHandle::DestroyThis()
dvander@1084
   234
{
dvander@1084
   235
	if (m_params.flags & Thread_AutoRelease)
dvander@1084
   236
		return;
dvander@1084
   237
dvander@1084
   238
	delete this;
dvander@1084
   239
}
dvander@1084
   240
dvander@1084
   241
void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
dvander@1084
   242
{
dvander@1084
   243
	if (!ptparams)
dvander@1084
   244
		return;
dvander@1084
   245
dvander@1084
   246
	*ptparams = m_params;
dvander@1084
   247
}
dvander@1084
   248
dvander@1084
   249
ThreadPriority WinThreader::ThreadHandle::GetPriority()
dvander@1084
   250
{
dvander@1084
   251
	return m_params.prio;
dvander@1084
   252
}
dvander@1084
   253
dvander@1084
   254
bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
dvander@1084
   255
{
dvander@1084
   256
	if (!m_thread)
dvander@1084
   257
		return false;
dvander@1084
   258
dvander@1084
   259
	BOOL res = FALSE;
dvander@1084
   260
dvander@1084
   261
	if (prio >= ThreadPrio_Maximum)
dvander@1084
   262
		res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
dvander@1084
   263
	else if (prio <= ThreadPrio_Minimum)
dvander@1084
   264
		res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
dvander@1084
   265
	else if (prio == ThreadPrio_Normal)
dvander@1084
   266
		res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
dvander@1084
   267
	else if (prio == ThreadPrio_High)
dvander@1084
   268
		res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
dvander@1084
   269
	else if (prio == ThreadPrio_Low)
dvander@1084
   270
		res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
dvander@1084
   271
dvander@1084
   272
	m_params.prio = prio;
dvander@1084
   273
dvander@1084
   274
	return (res != FALSE);
dvander@1084
   275
}
dvander@1084
   276
dvander@1084
   277
bool WinThreader::ThreadHandle::Unpause()
dvander@1084
   278
{
dvander@1084
   279
	if (!m_thread)
dvander@1084
   280
		return false;
dvander@1084
   281
dvander@1084
   282
	if (m_state != Thread_Paused)
dvander@1084
   283
		return false;
dvander@1084
   284
dvander@1084
   285
	m_state = Thread_Running;
dvander@1084
   286
dvander@1084
   287
	if (ResumeThread(m_thread) == -1)
dvander@1084
   288
	{
dvander@1084
   289
		m_state = Thread_Paused;
dvander@1084
   290
		return false;
dvander@1084
   291
	}
dvander@1084
   292
dvander@1084
   293
	return true;
dvander@1084
   294
}
dvander@1084
   295
dvander@1084
   296
/*****************
dvander@1084
   297
 * EVENT SIGNALS *
dvander@1084
   298
 *****************/
dvander@1084
   299
dvander@1084
   300
WinThreader::WinEvent::~WinEvent()
dvander@1084
   301
{
dvander@1084
   302
	CloseHandle(m_event);
dvander@1084
   303
}
dvander@1084
   304
dvander@1084
   305
void WinThreader::WinEvent::Wait()
dvander@1084
   306
{
dvander@1084
   307
	WaitForSingleObject(m_event, INFINITE);
dvander@1084
   308
}
dvander@1084
   309
dvander@1084
   310
void WinThreader::WinEvent::Signal()
dvander@1084
   311
{
dvander@1084
   312
	SetEvent(m_event);
dvander@1084
   313
}
dvander@1084
   314
dvander@1084
   315
void WinThreader::WinEvent::DestroyThis()
dvander@1084
   316
{
dvander@1084
   317
	delete this;
dvander@1084
   318
}