core/logic/thread/WinThreads.cpp
author David Anderson <dvander@alliedmods.net>
Mon Aug 19 20:58:02 2013 -0700 (2013-08-19)
changeset 4025 542dde661d5c
parent 2726 c96f3fab8211
permissions -rw-r--r--
Rewrite IThreader implementation around new synchronization primitives (bug 5862, r=fyren).
dvander@2726
     1
/**
dvander@4025
     2
 * vim: set ts=4 sw=4 tw=99 noet:
dvander@2726
     3
 * =============================================================================
dvander@2726
     4
 * SourceMod
dvander@2726
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2726
     6
 * =============================================================================
dvander@2726
     7
 *
dvander@2726
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2726
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2726
    10
 * Free Software Foundation.
dvander@2726
    11
 * 
dvander@2726
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2726
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2726
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2726
    15
 * details.
dvander@2726
    16
 *
dvander@2726
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2726
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2726
    19
 *
dvander@2726
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2726
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2726
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2726
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2726
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2726
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2726
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2726
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2726
    28
 *
dvander@2726
    29
 * Version: $Id$
dvander@2726
    30
 */
dvander@2726
    31
dvander@2726
    32
#define _WIN32_WINNT 0x0400
dvander@2726
    33
#include "WinThreads.h"
dvander@2726
    34
#include "ThreadWorker.h"
dvander@2726
    35
dvander@2726
    36
IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
dvander@2726
    37
{
dvander@2726
    38
	if (threaded)
dvander@2726
    39
	{
dvander@2726
    40
		return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
dvander@2726
    41
	} else {
dvander@2726
    42
		return new BaseWorker(hooks);
dvander@2726
    43
	}
dvander@2726
    44
}
dvander@2726
    45
dvander@2726
    46
void WinThreader::DestroyWorker(IThreadWorker *pWorker)
dvander@2726
    47
{
dvander@2726
    48
	delete pWorker;
dvander@2726
    49
}
dvander@2726
    50
dvander@2726
    51
void WinThreader::ThreadSleep(unsigned int ms)
dvander@2726
    52
{
dvander@2726
    53
	Sleep((DWORD)ms);
dvander@2726
    54
}
dvander@2726
    55
dvander@2726
    56
IMutex *WinThreader::MakeMutex()
dvander@2726
    57
{
dvander@4025
    58
	return new CompatMutex();
dvander@2726
    59
}
dvander@2726
    60
dvander@2726
    61
IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
dvander@2726
    62
{
dvander@2726
    63
	ThreadParams defparams;
dvander@2726
    64
dvander@2726
    65
	defparams.flags = flags;
dvander@2726
    66
	defparams.prio = ThreadPrio_Normal;
dvander@2726
    67
dvander@2726
    68
	return MakeThread(pThread, &defparams);
dvander@2726
    69
}
dvander@2726
    70
dvander@2726
    71
void WinThreader::MakeThread(IThread *pThread)
dvander@2726
    72
{
dvander@2726
    73
	ThreadParams defparams;
dvander@2726
    74
dvander@2726
    75
	defparams.flags = Thread_AutoRelease;
dvander@2726
    76
	defparams.prio = ThreadPrio_Normal;
dvander@2726
    77
dvander@2726
    78
	MakeThread(pThread, &defparams);
dvander@2726
    79
}
dvander@2726
    80
dvander@4025
    81
void WinThreader::ThreadHandle::Run()
dvander@2726
    82
{
dvander@4025
    83
	// Wait for an unpause if necessary.
dvander@4025
    84
	{
dvander@4025
    85
		ke::AutoLock lock(&suspend_);
dvander@4025
    86
		if (m_state == Thread_Paused)
dvander@4025
    87
			suspend_.Wait();
dvander@4025
    88
	}
dvander@4025
    89
	
dvander@4025
    90
	m_run->RunThread(this);
dvander@4025
    91
	m_state = Thread_Done;
dvander@4025
    92
	m_run->OnTerminate(this, false);
dvander@4025
    93
	if (m_params.flags & Thread_AutoRelease)
dvander@4025
    94
		delete this;
dvander@2726
    95
}
dvander@2726
    96
dvander@2726
    97
void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
dvander@2726
    98
{
dvander@2726
    99
	max = ThreadPrio_Maximum;
dvander@2726
   100
	min = ThreadPrio_Minimum;
dvander@2726
   101
}
dvander@2726
   102
dvander@2726
   103
ThreadParams g_defparams;
dvander@2726
   104
IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
dvander@2726
   105
{
dvander@2726
   106
	if (params == NULL)
dvander@2726
   107
		params = &g_defparams;
dvander@2726
   108
dvander@4025
   109
	ke::AutoPtr<ThreadHandle> pHandle(new ThreadHandle(this, pThread, params));
dvander@2726
   110
dvander@4025
   111
	pHandle->m_thread = new ke::Thread(pHandle, "SourceMod");
dvander@4025
   112
	if (!pHandle->m_thread->Succeeded())
dvander@2726
   113
		return NULL;
dvander@2726
   114
dvander@2726
   115
	if (pHandle->m_params.prio != ThreadPrio_Normal)
dvander@2726
   116
		pHandle->SetPriority(pHandle->m_params.prio);
dvander@2726
   117
dvander@4025
   118
	if (!(params->flags & Thread_CreateSuspended))
dvander@2726
   119
		pHandle->Unpause();
dvander@2726
   120
dvander@4025
   121
	return pHandle.take();
dvander@2726
   122
}
dvander@2726
   123
dvander@2726
   124
IEventSignal *WinThreader::MakeEventSignal()
dvander@2726
   125
{
dvander@4025
   126
	return new CompatCondVar();
dvander@2726
   127
}
dvander@2726
   128
dvander@2726
   129
/******************
dvander@2726
   130
 * Thread Handles *
dvander@2726
   131
 ******************/
dvander@2726
   132
dvander@4025
   133
WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) : 
dvander@4025
   134
	m_parent(parent), m_run(run), m_params(*params),
dvander@2726
   135
	m_state(Thread_Paused)
dvander@2726
   136
{
dvander@2726
   137
}
dvander@2726
   138
dvander@2726
   139
WinThreader::ThreadHandle::~ThreadHandle()
dvander@2726
   140
{
dvander@2726
   141
}
dvander@2726
   142
dvander@2726
   143
bool WinThreader::ThreadHandle::WaitForThread()
dvander@2726
   144
{
dvander@4025
   145
	if (!m_thread)
dvander@2726
   146
		return false;
dvander@2726
   147
dvander@4025
   148
	m_thread->Join();
dvander@2726
   149
	return true;
dvander@2726
   150
}
dvander@2726
   151
dvander@2726
   152
ThreadState WinThreader::ThreadHandle::GetState()
dvander@2726
   153
{
dvander@4025
   154
	return m_state;
dvander@2726
   155
}
dvander@2726
   156
dvander@2726
   157
IThreadCreator *WinThreader::ThreadHandle::Parent()
dvander@2726
   158
{
dvander@2726
   159
	return m_parent;
dvander@2726
   160
}
dvander@2726
   161
dvander@2726
   162
void WinThreader::ThreadHandle::DestroyThis()
dvander@2726
   163
{
dvander@2726
   164
	if (m_params.flags & Thread_AutoRelease)
dvander@2726
   165
		return;
dvander@2726
   166
dvander@2726
   167
	delete this;
dvander@2726
   168
}
dvander@2726
   169
dvander@2726
   170
void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
dvander@2726
   171
{
dvander@2726
   172
	if (!ptparams)
dvander@2726
   173
		return;
dvander@2726
   174
dvander@2726
   175
	*ptparams = m_params;
dvander@2726
   176
}
dvander@2726
   177
dvander@2726
   178
ThreadPriority WinThreader::ThreadHandle::GetPriority()
dvander@2726
   179
{
dvander@2726
   180
	return m_params.prio;
dvander@2726
   181
}
dvander@2726
   182
dvander@2726
   183
bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
dvander@2726
   184
{
dvander@2726
   185
	BOOL res = FALSE;
dvander@2726
   186
dvander@2726
   187
	if (prio >= ThreadPrio_Maximum)
dvander@4025
   188
		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_HIGHEST);
dvander@2726
   189
	else if (prio <= ThreadPrio_Minimum)
dvander@4025
   190
		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_LOWEST);
dvander@2726
   191
	else if (prio == ThreadPrio_Normal)
dvander@4025
   192
		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_NORMAL);
dvander@2726
   193
	else if (prio == ThreadPrio_High)
dvander@4025
   194
		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_ABOVE_NORMAL);
dvander@2726
   195
	else if (prio == ThreadPrio_Low)
dvander@4025
   196
		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_BELOW_NORMAL);
dvander@2726
   197
dvander@2726
   198
	m_params.prio = prio;
dvander@2726
   199
dvander@2726
   200
	return (res != FALSE);
dvander@2726
   201
}
dvander@2726
   202
dvander@2726
   203
bool WinThreader::ThreadHandle::Unpause()
dvander@2726
   204
{
dvander@2726
   205
	if (m_state != Thread_Paused)
dvander@2726
   206
		return false;
dvander@2726
   207
dvander@4025
   208
	ke::AutoLock lock(&suspend_);
dvander@2726
   209
	m_state = Thread_Running;
dvander@4025
   210
	suspend_.Notify();
dvander@2726
   211
	return true;
dvander@2726
   212
}