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