1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/thread/BaseWorker.cpp Sun Jul 06 04:49:55 2008 +0000
1.3 @@ -0,0 +1,303 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include "BaseWorker.h"
1.36 +
1.37 +BaseWorker::BaseWorker(IThreadWorkerCallbacks *hooks) :
1.38 + m_perFrame(SM_DEFAULT_THREADS_PER_FRAME),
1.39 + m_state(Worker_Stopped),
1.40 + m_pHooks(hooks)
1.41 +{
1.42 +}
1.43 +
1.44 +BaseWorker::~BaseWorker()
1.45 +{
1.46 + if (m_state != Worker_Stopped || m_state != Worker_Invalid)
1.47 + Stop(true);
1.48 +
1.49 + if (m_ThreadQueue.size())
1.50 + Flush(true);
1.51 +}
1.52 +
1.53 +void BaseWorker::MakeThread(IThread *pThread)
1.54 +{
1.55 + ThreadParams pt;
1.56 +
1.57 + pt.flags = Thread_AutoRelease;
1.58 + pt.prio = ThreadPrio_Normal;
1.59 +
1.60 + MakeThread(pThread, &pt);
1.61 +}
1.62 +
1.63 +IThreadHandle *BaseWorker::MakeThread(IThread *pThread, ThreadFlags flags)
1.64 +{
1.65 + ThreadParams pt;
1.66 +
1.67 + pt.flags = flags;
1.68 + pt.prio = ThreadPrio_Normal;
1.69 +
1.70 + return MakeThread(pThread, &pt);
1.71 +}
1.72 +
1.73 +IThreadHandle *BaseWorker::MakeThread(IThread *pThread, const ThreadParams *params)
1.74 +{
1.75 + if (m_state != Worker_Running)
1.76 + return NULL;
1.77 +
1.78 + SWThreadHandle *swt = new SWThreadHandle(this, params, pThread);
1.79 +
1.80 + AddThreadToQueue(swt);
1.81 +
1.82 + return swt;
1.83 +}
1.84 +
1.85 +void BaseWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
1.86 +{
1.87 + max = ThreadPrio_Normal;
1.88 + min = ThreadPrio_Normal;
1.89 +}
1.90 +
1.91 +unsigned int BaseWorker::Flush(bool flush_cancel)
1.92 +{
1.93 + SWThreadHandle *swt;
1.94 + unsigned int num = 0;
1.95 +
1.96 + while ((swt=PopThreadFromQueue()) != NULL)
1.97 + {
1.98 + swt->m_state = Thread_Done;
1.99 + if (!flush_cancel)
1.100 + swt->pThread->RunThread(swt);
1.101 + swt->pThread->OnTerminate(swt, flush_cancel);
1.102 + if (swt->m_params.flags & Thread_AutoRelease)
1.103 + delete swt;
1.104 + num++;
1.105 + }
1.106 +
1.107 + return num;
1.108 +}
1.109 +
1.110 +SWThreadHandle *BaseWorker::PopThreadFromQueue()
1.111 +{
1.112 + if (!m_ThreadQueue.size())
1.113 + return NULL;
1.114 +
1.115 + SourceHook::List<SWThreadHandle *>::iterator begin;
1.116 + SWThreadHandle *swt;
1.117 +
1.118 + begin = m_ThreadQueue.begin();
1.119 + swt = (*begin);
1.120 + m_ThreadQueue.erase(begin);
1.121 +
1.122 + return swt;
1.123 +}
1.124 +
1.125 +void BaseWorker::AddThreadToQueue(SWThreadHandle *pHandle)
1.126 +{
1.127 + m_ThreadQueue.push_back(pHandle);
1.128 +}
1.129 +
1.130 +unsigned int BaseWorker::GetMaxThreadsPerFrame()
1.131 +{
1.132 + return m_perFrame;
1.133 +}
1.134 +
1.135 +WorkerState BaseWorker::GetStatus(unsigned int *threads)
1.136 +{
1.137 + if (threads)
1.138 + *threads = m_perFrame;
1.139 +
1.140 + return m_state;
1.141 +}
1.142 +
1.143 +unsigned int BaseWorker::RunFrame()
1.144 +{
1.145 + unsigned int done = 0;
1.146 + unsigned int max = GetMaxThreadsPerFrame();
1.147 + SWThreadHandle *swt = NULL;
1.148 + IThread *pThread = NULL;
1.149 +
1.150 + while (done < max)
1.151 + {
1.152 + if ((swt=PopThreadFromQueue()) == NULL)
1.153 + {
1.154 + break;
1.155 + }
1.156 + pThread = swt->pThread;
1.157 + swt->m_state = Thread_Running;
1.158 + pThread->RunThread(swt);
1.159 + swt->m_state = Thread_Done;
1.160 + pThread->OnTerminate(swt, false);
1.161 + if (swt->m_params.flags & Thread_AutoRelease)
1.162 + {
1.163 + delete swt;
1.164 + }
1.165 + done++;
1.166 + }
1.167 +
1.168 + return done;
1.169 +}
1.170 +
1.171 +void BaseWorker::SetMaxThreadsPerFrame(unsigned int threads)
1.172 +{
1.173 + m_perFrame = threads;
1.174 +}
1.175 +
1.176 +bool BaseWorker::Start()
1.177 +{
1.178 + if (m_state != Worker_Invalid && m_state != Worker_Stopped)
1.179 + {
1.180 + return false;
1.181 + }
1.182 +
1.183 + m_state = Worker_Running;
1.184 +
1.185 + if (m_pHooks)
1.186 + {
1.187 + m_pHooks->OnWorkerStart(this);
1.188 + }
1.189 +
1.190 + return true;
1.191 +}
1.192 +
1.193 +bool BaseWorker::Stop(bool flush_cancel)
1.194 +{
1.195 + if (m_state == Worker_Invalid || m_state == Worker_Stopped)
1.196 + {
1.197 + return false;
1.198 + }
1.199 +
1.200 + if (m_state == Worker_Paused)
1.201 + {
1.202 + if (!Unpause())
1.203 + {
1.204 + return false;
1.205 + }
1.206 + }
1.207 +
1.208 + m_state = Worker_Stopped;
1.209 + Flush(flush_cancel);
1.210 +
1.211 + if (m_pHooks)
1.212 + {
1.213 + m_pHooks->OnWorkerStop(this);
1.214 + }
1.215 +
1.216 + return true;
1.217 +}
1.218 +
1.219 +bool BaseWorker::Pause()
1.220 +{
1.221 + if (m_state != Worker_Running)
1.222 + {
1.223 + return false;
1.224 + }
1.225 +
1.226 + m_state = Worker_Paused;
1.227 +
1.228 + return true;
1.229 +}
1.230 +
1.231 +
1.232 +bool BaseWorker::Unpause()
1.233 +{
1.234 + if (m_state != Worker_Paused)
1.235 + {
1.236 + return false;
1.237 + }
1.238 +
1.239 + m_state = Worker_Running;
1.240 +
1.241 + return true;
1.242 +}
1.243 +
1.244 +/***********************
1.245 + * THREAD HANDLE STUFF *
1.246 + ***********************/
1.247 +
1.248 +void SWThreadHandle::DestroyThis()
1.249 +{
1.250 + delete this;
1.251 +}
1.252 +
1.253 +void SWThreadHandle::GetParams(ThreadParams *p)
1.254 +{
1.255 + *p = m_params;
1.256 +}
1.257 +
1.258 +ThreadPriority SWThreadHandle::GetPriority()
1.259 +{
1.260 + return m_params.prio;
1.261 +}
1.262 +
1.263 +ThreadState SWThreadHandle::GetState()
1.264 +{
1.265 + return m_state;
1.266 +}
1.267 +
1.268 +IThreadCreator *SWThreadHandle::Parent()
1.269 +{
1.270 + return m_parent;
1.271 +}
1.272 +
1.273 +bool SWThreadHandle::SetPriority(ThreadPriority prio)
1.274 +{
1.275 + if (m_params.prio != ThreadPrio_Normal)
1.276 + return false;
1.277 +
1.278 + m_params.prio = prio;
1.279 +
1.280 + return true;
1.281 +}
1.282 +
1.283 +bool SWThreadHandle::Unpause()
1.284 +{
1.285 + if (m_state != Thread_Paused)
1.286 + return false;
1.287 +
1.288 + m_state = Thread_Running;
1.289 +
1.290 + return true;
1.291 +}
1.292 +
1.293 +bool SWThreadHandle::WaitForThread()
1.294 +{
1.295 + return false;
1.296 +}
1.297 +
1.298 +SWThreadHandle::SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread) :
1.299 + m_state(Thread_Paused), m_params(*p), m_parent(parent), pThread(thread)
1.300 +{
1.301 +}
1.302 +
1.303 +IThread *SWThreadHandle::GetThread()
1.304 +{
1.305 + return pThread;
1.306 +}