dvander@1084: /**
dvander@1084: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
dvander@1231: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@1084: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@1084: *
dvander@1084: * Version: $Id$
dvander@1084: */
dvander@1084:
dvander@1084: #include "BaseWorker.h"
dvander@1084:
dvander@1090: BaseWorker::BaseWorker(IThreadWorkerCallbacks *hooks) :
dvander@1084: m_perFrame(SM_DEFAULT_THREADS_PER_FRAME),
dvander@1090: m_state(Worker_Stopped),
dvander@1090: m_pHooks(hooks)
dvander@1084: {
dvander@1084: }
dvander@1084:
dvander@1084: BaseWorker::~BaseWorker()
dvander@1084: {
dvander@1084: if (m_state != Worker_Stopped || m_state != Worker_Invalid)
dvander@1084: Stop(true);
dvander@1084:
dvander@1084: if (m_ThreadQueue.size())
dvander@1084: Flush(true);
dvander@1084: }
dvander@1084:
dvander@1084: void BaseWorker::MakeThread(IThread *pThread)
dvander@1084: {
dvander@1084: ThreadParams pt;
dvander@1084:
dvander@1084: pt.flags = Thread_AutoRelease;
dvander@1084: pt.prio = ThreadPrio_Normal;
dvander@1084:
dvander@1084: MakeThread(pThread, &pt);
dvander@1084: }
dvander@1084:
dvander@1084: IThreadHandle *BaseWorker::MakeThread(IThread *pThread, ThreadFlags flags)
dvander@1084: {
dvander@1084: ThreadParams pt;
dvander@1084:
dvander@1084: pt.flags = flags;
dvander@1084: pt.prio = ThreadPrio_Normal;
dvander@1084:
dvander@1084: return MakeThread(pThread, &pt);
dvander@1084: }
dvander@1084:
dvander@1084: IThreadHandle *BaseWorker::MakeThread(IThread *pThread, const ThreadParams *params)
dvander@1084: {
dvander@1084: if (m_state != Worker_Running)
dvander@1084: return NULL;
dvander@1084:
dvander@1084: SWThreadHandle *swt = new SWThreadHandle(this, params, pThread);
dvander@1084:
dvander@1084: AddThreadToQueue(swt);
dvander@1084:
dvander@1084: return swt;
dvander@1084: }
dvander@1084:
dvander@1084: void BaseWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
dvander@1084: {
dvander@1084: max = ThreadPrio_Normal;
dvander@1084: min = ThreadPrio_Normal;
dvander@1084: }
dvander@1084:
dvander@1084: unsigned int BaseWorker::Flush(bool flush_cancel)
dvander@1084: {
dvander@1084: SWThreadHandle *swt;
dvander@1084: unsigned int num = 0;
dvander@1084:
dvander@1084: while ((swt=PopThreadFromQueue()) != NULL)
dvander@1084: {
dvander@1084: swt->m_state = Thread_Done;
dvander@1084: if (!flush_cancel)
dvander@1084: swt->pThread->RunThread(swt);
dvander@1084: swt->pThread->OnTerminate(swt, flush_cancel);
dvander@1084: if (swt->m_params.flags & Thread_AutoRelease)
dvander@1084: delete swt;
dvander@1084: num++;
dvander@1084: }
dvander@1084:
dvander@1084: return num;
dvander@1084: }
dvander@1084:
dvander@1084: SWThreadHandle *BaseWorker::PopThreadFromQueue()
dvander@1084: {
dvander@1084: if (!m_ThreadQueue.size())
dvander@1084: return NULL;
dvander@1084:
dvander@1084: SourceHook::List::iterator begin;
dvander@1084: SWThreadHandle *swt;
dvander@1084:
dvander@1084: begin = m_ThreadQueue.begin();
dvander@1084: swt = (*begin);
dvander@1084: m_ThreadQueue.erase(begin);
dvander@1084:
dvander@1084: return swt;
dvander@1084: }
dvander@1084:
dvander@1084: void BaseWorker::AddThreadToQueue(SWThreadHandle *pHandle)
dvander@1084: {
dvander@1084: m_ThreadQueue.push_back(pHandle);
dvander@1084: }
dvander@1084:
dvander@1084: unsigned int BaseWorker::GetMaxThreadsPerFrame()
dvander@1084: {
dvander@1084: return m_perFrame;
dvander@1084: }
dvander@1084:
dvander@1084: WorkerState BaseWorker::GetStatus(unsigned int *threads)
dvander@1084: {
dvander@1084: if (threads)
dvander@1084: *threads = m_perFrame;
dvander@1084:
dvander@1084: return m_state;
dvander@1084: }
dvander@1084:
dvander@1084: unsigned int BaseWorker::RunFrame()
dvander@1084: {
dvander@1084: unsigned int done = 0;
dvander@1084: unsigned int max = GetMaxThreadsPerFrame();
dvander@1084: SWThreadHandle *swt = NULL;
dvander@1084: IThread *pThread = NULL;
dvander@1084:
dvander@1084: while (done < max)
dvander@1084: {
dvander@1084: if ((swt=PopThreadFromQueue()) == NULL)
dvander@1090: {
dvander@1084: break;
dvander@1090: }
dvander@1084: pThread = swt->pThread;
dvander@1084: swt->m_state = Thread_Running;
dvander@1084: pThread->RunThread(swt);
dvander@1084: swt->m_state = Thread_Done;
dvander@1084: pThread->OnTerminate(swt, false);
dvander@1084: if (swt->m_params.flags & Thread_AutoRelease)
dvander@1090: {
dvander@1084: delete swt;
dvander@1090: }
dvander@1084: done++;
dvander@1084: }
dvander@1084:
dvander@1084: return done;
dvander@1084: }
dvander@1084:
dvander@1084: void BaseWorker::SetMaxThreadsPerFrame(unsigned int threads)
dvander@1084: {
dvander@1084: m_perFrame = threads;
dvander@1084: }
dvander@1084:
dvander@1084: bool BaseWorker::Start()
dvander@1084: {
dvander@1084: if (m_state != Worker_Invalid && m_state != Worker_Stopped)
dvander@1084: {
dvander@1084: return false;
dvander@1084: }
dvander@1084:
dvander@1084: m_state = Worker_Running;
dvander@1084:
dvander@1090: if (m_pHooks)
dvander@1090: {
dvander@1090: m_pHooks->OnWorkerStart(this);
dvander@1090: }
dvander@1090:
dvander@1084: return true;
dvander@1084: }
dvander@1084:
dvander@1084: bool BaseWorker::Stop(bool flush_cancel)
dvander@1084: {
dvander@1084: if (m_state == Worker_Invalid || m_state == Worker_Stopped)
dvander@1090: {
dvander@1084: return false;
dvander@1090: }
dvander@1084:
dvander@1084: if (m_state == Worker_Paused)
dvander@1084: {
dvander@1084: if (!Unpause())
dvander@1090: {
dvander@1084: return false;
dvander@1090: }
dvander@1084: }
dvander@1084:
dvander@1084: m_state = Worker_Stopped;
dvander@1084: Flush(flush_cancel);
dvander@1084:
dvander@1090: if (m_pHooks)
dvander@1090: {
dvander@1090: m_pHooks->OnWorkerStop(this);
dvander@1090: }
dvander@1090:
dvander@1084: return true;
dvander@1084: }
dvander@1084:
dvander@1084: bool BaseWorker::Pause()
dvander@1084: {
dvander@1084: if (m_state != Worker_Running)
dvander@1090: {
dvander@1084: return false;
dvander@1090: }
dvander@1084:
dvander@1084: m_state = Worker_Paused;
dvander@1084:
dvander@1084: return true;
dvander@1084: }
dvander@1084:
dvander@1084:
dvander@1084: bool BaseWorker::Unpause()
dvander@1084: {
dvander@1084: if (m_state != Worker_Paused)
dvander@1090: {
dvander@1084: return false;
dvander@1090: }
dvander@1084:
dvander@1084: m_state = Worker_Running;
dvander@1084:
dvander@1084: return true;
dvander@1084: }
dvander@1084:
dvander@1084: /***********************
dvander@1084: * THREAD HANDLE STUFF *
dvander@1084: ***********************/
dvander@1084:
dvander@1084: void SWThreadHandle::DestroyThis()
dvander@1084: {
dvander@1084: delete this;
dvander@1084: }
dvander@1084:
dvander@1084: void SWThreadHandle::GetParams(ThreadParams *p)
dvander@1084: {
dvander@1084: *p = m_params;
dvander@1084: }
dvander@1084:
dvander@1084: ThreadPriority SWThreadHandle::GetPriority()
dvander@1084: {
dvander@1084: return m_params.prio;
dvander@1084: }
dvander@1084:
dvander@1084: ThreadState SWThreadHandle::GetState()
dvander@1084: {
dvander@1084: return m_state;
dvander@1084: }
dvander@1084:
dvander@1084: IThreadCreator *SWThreadHandle::Parent()
dvander@1084: {
dvander@1084: return m_parent;
dvander@1084: }
dvander@1084:
dvander@1084: bool SWThreadHandle::SetPriority(ThreadPriority prio)
dvander@1084: {
dvander@1084: if (m_params.prio != ThreadPrio_Normal)
dvander@1084: return false;
dvander@1084:
dvander@1084: m_params.prio = prio;
dvander@1084:
dvander@1084: return true;
dvander@1084: }
dvander@1084:
dvander@1084: bool SWThreadHandle::Unpause()
dvander@1084: {
dvander@1084: if (m_state != Thread_Paused)
dvander@1084: return false;
dvander@1084:
dvander@1084: m_state = Thread_Running;
dvander@1084:
dvander@1084: return true;
dvander@1084: }
dvander@1084:
dvander@1084: bool SWThreadHandle::WaitForThread()
dvander@1084: {
dvander@1084: return false;
dvander@1084: }
dvander@1084:
dvander@1084: SWThreadHandle::SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread) :
dvander@1084: m_state(Thread_Paused), m_params(*p), m_parent(parent), pThread(thread)
dvander@1084: {
dvander@1084: }
dvander@1084:
dvander@1084: IThread *SWThreadHandle::GetThread()
dvander@1084: {
dvander@1084: return pThread;
dvander@1084: }