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