core/thread/WinThreads.cpp
author Borja Ferrer <faluco@alliedmods.net>
Fri Jul 04 19:04:33 2008 +0000 (2008-07-04)
changeset 2155 3f1fd7ab3d86
parent 1952 b7aa2b626807
child 2289 44045ead61cd
permissions -rw-r--r--
fixed amb1801, IsFakeClient() wasn't working for TF2 causing false results and crashes
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
}