core/thread/BaseWorker.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@1084
    33
#include "BaseWorker.h"
dvander@1084
    34
dvander@1090
    35
BaseWorker::BaseWorker(IThreadWorkerCallbacks *hooks) : 
dvander@1084
    36
	m_perFrame(SM_DEFAULT_THREADS_PER_FRAME),
dvander@1090
    37
	m_state(Worker_Stopped),
dvander@1090
    38
	m_pHooks(hooks)
dvander@1084
    39
{
dvander@1084
    40
}
dvander@1084
    41
dvander@1084
    42
BaseWorker::~BaseWorker()
dvander@1084
    43
{
dvander@1084
    44
	if (m_state != Worker_Stopped || m_state != Worker_Invalid)
dvander@1084
    45
		Stop(true);
dvander@1084
    46
dvander@1084
    47
	if (m_ThreadQueue.size())
dvander@1084
    48
		Flush(true);
dvander@1084
    49
}
dvander@1084
    50
dvander@1084
    51
void BaseWorker::MakeThread(IThread *pThread)
dvander@1084
    52
{
dvander@1084
    53
	ThreadParams pt;
dvander@1084
    54
dvander@1084
    55
	pt.flags = Thread_AutoRelease;
dvander@1084
    56
	pt.prio = ThreadPrio_Normal;
dvander@1084
    57
dvander@1084
    58
	MakeThread(pThread, &pt);
dvander@1084
    59
}
dvander@1084
    60
dvander@1084
    61
IThreadHandle *BaseWorker::MakeThread(IThread *pThread, ThreadFlags flags)
dvander@1084
    62
{
dvander@1084
    63
	ThreadParams pt;
dvander@1084
    64
dvander@1084
    65
	pt.flags = flags;
dvander@1084
    66
	pt.prio = ThreadPrio_Normal;
dvander@1084
    67
dvander@1084
    68
	return MakeThread(pThread, &pt);
dvander@1084
    69
}
dvander@1084
    70
dvander@1084
    71
IThreadHandle *BaseWorker::MakeThread(IThread *pThread, const ThreadParams *params)
dvander@1084
    72
{
dvander@1084
    73
	if (m_state != Worker_Running)
dvander@1084
    74
		return NULL;
dvander@1084
    75
dvander@1084
    76
	SWThreadHandle *swt = new SWThreadHandle(this, params, pThread);
dvander@1084
    77
dvander@1084
    78
	AddThreadToQueue(swt);
dvander@1084
    79
dvander@1084
    80
	return swt;
dvander@1084
    81
}
dvander@1084
    82
dvander@1084
    83
void BaseWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
dvander@1084
    84
{
dvander@1084
    85
	max = ThreadPrio_Normal;
dvander@1084
    86
	min = ThreadPrio_Normal;
dvander@1084
    87
}
dvander@1084
    88
dvander@1084
    89
unsigned int BaseWorker::Flush(bool flush_cancel)
dvander@1084
    90
{
dvander@1084
    91
	SWThreadHandle *swt;
dvander@1084
    92
	unsigned int num = 0;
dvander@1084
    93
dvander@1084
    94
	while ((swt=PopThreadFromQueue()) != NULL)
dvander@1084
    95
	{
dvander@1084
    96
		swt->m_state = Thread_Done;
dvander@1084
    97
		if (!flush_cancel)
dvander@1084
    98
			swt->pThread->RunThread(swt);
dvander@1084
    99
		swt->pThread->OnTerminate(swt, flush_cancel);
dvander@1084
   100
		if (swt->m_params.flags & Thread_AutoRelease)
dvander@1084
   101
			delete swt;
dvander@1084
   102
		num++;
dvander@1084
   103
	}
dvander@1084
   104
dvander@1084
   105
	return num;
dvander@1084
   106
}
dvander@1084
   107
dvander@1084
   108
SWThreadHandle *BaseWorker::PopThreadFromQueue()
dvander@1084
   109
{
dvander@1084
   110
	if (!m_ThreadQueue.size())
dvander@1084
   111
		return NULL;
dvander@1084
   112
dvander@1084
   113
	SourceHook::List<SWThreadHandle *>::iterator begin;
dvander@1084
   114
	SWThreadHandle *swt;
dvander@1084
   115
dvander@1084
   116
	begin = m_ThreadQueue.begin();
dvander@1084
   117
	swt = (*begin);
dvander@1084
   118
	m_ThreadQueue.erase(begin);
dvander@1084
   119
dvander@1084
   120
	return swt;
dvander@1084
   121
}
dvander@1084
   122
dvander@1084
   123
void BaseWorker::AddThreadToQueue(SWThreadHandle *pHandle)
dvander@1084
   124
{
dvander@1084
   125
	m_ThreadQueue.push_back(pHandle);
dvander@1084
   126
}
dvander@1084
   127
dvander@1084
   128
unsigned int BaseWorker::GetMaxThreadsPerFrame()
dvander@1084
   129
{
dvander@1084
   130
	return m_perFrame;
dvander@1084
   131
}
dvander@1084
   132
dvander@1084
   133
WorkerState BaseWorker::GetStatus(unsigned int *threads)
dvander@1084
   134
{
dvander@1084
   135
	if (threads)
dvander@1084
   136
		*threads = m_perFrame;
dvander@1084
   137
dvander@1084
   138
	return m_state;
dvander@1084
   139
}
dvander@1084
   140
dvander@1084
   141
unsigned int BaseWorker::RunFrame()
dvander@1084
   142
{
dvander@1084
   143
	unsigned int done = 0;
dvander@1084
   144
	unsigned int max = GetMaxThreadsPerFrame();
dvander@1084
   145
	SWThreadHandle *swt = NULL;
dvander@1084
   146
	IThread *pThread = NULL;
dvander@1084
   147
dvander@1084
   148
	while (done < max)
dvander@1084
   149
	{
dvander@1084
   150
		if ((swt=PopThreadFromQueue()) == NULL)
dvander@1090
   151
		{
dvander@1084
   152
			break;
dvander@1090
   153
		}
dvander@1084
   154
		pThread = swt->pThread;
dvander@1084
   155
		swt->m_state = Thread_Running;
dvander@1084
   156
		pThread->RunThread(swt);
dvander@1084
   157
		swt->m_state = Thread_Done;
dvander@1084
   158
		pThread->OnTerminate(swt, false);
dvander@1084
   159
		if (swt->m_params.flags & Thread_AutoRelease)
dvander@1090
   160
		{
dvander@1084
   161
			delete swt;
dvander@1090
   162
		}
dvander@1084
   163
		done++;
dvander@1084
   164
	}
dvander@1084
   165
dvander@1084
   166
	return done;
dvander@1084
   167
}
dvander@1084
   168
dvander@1084
   169
void BaseWorker::SetMaxThreadsPerFrame(unsigned int threads)
dvander@1084
   170
{
dvander@1084
   171
	m_perFrame = threads;
dvander@1084
   172
}
dvander@1084
   173
dvander@1084
   174
bool BaseWorker::Start()
dvander@1084
   175
{
dvander@1084
   176
	if (m_state != Worker_Invalid && m_state != Worker_Stopped)
dvander@1084
   177
	{
dvander@1084
   178
		return false;
dvander@1084
   179
	}
dvander@1084
   180
dvander@1084
   181
	m_state = Worker_Running;
dvander@1084
   182
dvander@1090
   183
	if (m_pHooks)
dvander@1090
   184
	{
dvander@1090
   185
		m_pHooks->OnWorkerStart(this);
dvander@1090
   186
	}
dvander@1090
   187
dvander@1084
   188
    return true;
dvander@1084
   189
}
dvander@1084
   190
dvander@1084
   191
bool BaseWorker::Stop(bool flush_cancel)
dvander@1084
   192
{
dvander@1084
   193
	if (m_state == Worker_Invalid || m_state == Worker_Stopped)
dvander@1090
   194
	{
dvander@1084
   195
		return false;
dvander@1090
   196
	}
dvander@1084
   197
dvander@1084
   198
	if (m_state == Worker_Paused)
dvander@1084
   199
	{
dvander@1084
   200
		if (!Unpause())
dvander@1090
   201
		{
dvander@1084
   202
			return false;
dvander@1090
   203
		}
dvander@1084
   204
	}
dvander@1084
   205
dvander@1084
   206
	m_state = Worker_Stopped;
dvander@1084
   207
	Flush(flush_cancel);
dvander@1084
   208
dvander@1090
   209
	if (m_pHooks)
dvander@1090
   210
	{
dvander@1090
   211
		m_pHooks->OnWorkerStop(this);
dvander@1090
   212
	}
dvander@1090
   213
dvander@1084
   214
	return true;
dvander@1084
   215
}
dvander@1084
   216
dvander@1084
   217
bool BaseWorker::Pause()
dvander@1084
   218
{
dvander@1084
   219
	if (m_state != Worker_Running)
dvander@1090
   220
	{
dvander@1084
   221
		return false;
dvander@1090
   222
	}
dvander@1084
   223
dvander@1084
   224
	m_state = Worker_Paused;
dvander@1084
   225
dvander@1084
   226
	return true;
dvander@1084
   227
}
dvander@1084
   228
dvander@1084
   229
dvander@1084
   230
bool BaseWorker::Unpause()
dvander@1084
   231
{
dvander@1084
   232
	if (m_state != Worker_Paused)
dvander@1090
   233
	{
dvander@1084
   234
		return false;
dvander@1090
   235
	}
dvander@1084
   236
dvander@1084
   237
	m_state = Worker_Running;
dvander@1084
   238
dvander@1084
   239
	return true;
dvander@1084
   240
}
dvander@1084
   241
dvander@1084
   242
/***********************
dvander@1084
   243
 * THREAD HANDLE STUFF *
dvander@1084
   244
 ***********************/
dvander@1084
   245
dvander@1084
   246
void SWThreadHandle::DestroyThis()
dvander@1084
   247
{
dvander@1084
   248
	delete this;
dvander@1084
   249
}
dvander@1084
   250
dvander@1084
   251
void SWThreadHandle::GetParams(ThreadParams *p)
dvander@1084
   252
{
dvander@1084
   253
	*p = m_params;
dvander@1084
   254
}
dvander@1084
   255
dvander@1084
   256
ThreadPriority SWThreadHandle::GetPriority()
dvander@1084
   257
{
dvander@1084
   258
	return m_params.prio;
dvander@1084
   259
}
dvander@1084
   260
dvander@1084
   261
ThreadState SWThreadHandle::GetState()
dvander@1084
   262
{
dvander@1084
   263
	return m_state;
dvander@1084
   264
}
dvander@1084
   265
dvander@1084
   266
IThreadCreator *SWThreadHandle::Parent()
dvander@1084
   267
{
dvander@1084
   268
	return m_parent;
dvander@1084
   269
}
dvander@1084
   270
dvander@1084
   271
bool SWThreadHandle::SetPriority(ThreadPriority prio)
dvander@1084
   272
{
dvander@1084
   273
	if (m_params.prio != ThreadPrio_Normal)
dvander@1084
   274
		return false;
dvander@1084
   275
dvander@1084
   276
	m_params.prio = prio;
dvander@1084
   277
dvander@1084
   278
	return true;
dvander@1084
   279
}
dvander@1084
   280
dvander@1084
   281
bool SWThreadHandle::Unpause()
dvander@1084
   282
{
dvander@1084
   283
	if (m_state != Thread_Paused)
dvander@1084
   284
		return false;
dvander@1084
   285
dvander@1084
   286
	m_state = Thread_Running;
dvander@1084
   287
dvander@1084
   288
	return true;
dvander@1084
   289
}
dvander@1084
   290
dvander@1084
   291
bool SWThreadHandle::WaitForThread()
dvander@1084
   292
{
dvander@1084
   293
	return false;
dvander@1084
   294
}
dvander@1084
   295
dvander@1084
   296
SWThreadHandle::SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread) : 
dvander@1084
   297
	m_state(Thread_Paused), m_params(*p), m_parent(parent), pThread(thread)
dvander@1084
   298
{
dvander@1084
   299
}
dvander@1084
   300
dvander@1084
   301
IThread *SWThreadHandle::GetThread()
dvander@1084
   302
{
dvander@1084
   303
	return pThread;
dvander@1084
   304
}