diff -r 000000000000 -r c24a6fa957db core/thread/ThreadWorker.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/thread/ThreadWorker.cpp Sun Jul 06 04:49:55 2008 +0000
@@ -0,0 +1,320 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod
+ * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#include "ThreadWorker.h"
+
+ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks) : BaseWorker(hooks),
+ m_Threader(NULL),
+ m_QueueLock(NULL),
+ m_StateLock(NULL),
+ m_PauseSignal(NULL),
+ m_AddSignal(NULL),
+ me(NULL),
+ m_think_time(DEFAULT_THINK_TIME_MS)
+{
+ m_state = Worker_Invalid;
+}
+
+ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime) :
+ BaseWorker(hooks),
+ m_Threader(pThreader),
+ m_QueueLock(NULL),
+ m_StateLock(NULL),
+ m_PauseSignal(NULL),
+ m_AddSignal(NULL),
+ me(NULL),
+ m_think_time(thinktime)
+{
+ if (m_Threader)
+ {
+ m_state = Worker_Stopped;
+ } else {
+ m_state = Worker_Invalid;
+ }
+}
+
+ThreadWorker::~ThreadWorker()
+{
+ if (m_state != Worker_Stopped || m_state != Worker_Invalid)
+ {
+ Stop(true);
+ }
+
+ if (m_ThreadQueue.size())
+ {
+ Flush(true);
+ }
+}
+
+void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel)
+{
+ //we don't particularly care
+ return;
+}
+
+void ThreadWorker::RunThread(IThreadHandle *pHandle)
+{
+ WorkerState this_state = Worker_Running;
+ size_t num;
+
+ if (m_pHooks)
+ {
+ m_pHooks->OnWorkerStart(this);
+ }
+
+ while (true)
+ {
+ /**
+ * Check number of items in the queue
+ */
+ m_StateLock->Lock();
+ this_state = m_state;
+ m_StateLock->Unlock();
+ if (this_state != Worker_Stopped)
+ {
+ m_QueueLock->Lock();
+ num = m_ThreadQueue.size();
+ if (!num)
+ {
+ /**
+ * if none, wait for an item
+ */
+ m_Waiting = true;
+ m_QueueLock->Unlock();
+ /* first check if we should end again */
+ if (this_state == Worker_Stopped)
+ {
+ break;
+ }
+ m_AddSignal->Wait();
+ m_Waiting = false;
+ } else {
+ m_QueueLock->Unlock();
+ }
+ }
+ m_StateLock->Lock();
+ this_state = m_state;
+ m_StateLock->Unlock();
+ if (this_state != Worker_Running)
+ {
+ if (this_state == Worker_Paused || this_state == Worker_Stopped)
+ {
+ //wait until the lock is cleared.
+ if (this_state == Worker_Paused)
+ {
+ m_PauseSignal->Wait();
+ }
+ if (this_state == Worker_Stopped)
+ {
+ //if we're supposed to flush cleanrly,
+ // run all of the remaining frames first.
+ if (!m_FlushType)
+ {
+ while (m_ThreadQueue.size())
+ {
+ RunFrame();
+ }
+ }
+ break;
+ }
+ }
+ }
+ /**
+ * Run the frame.
+ */
+ RunFrame();
+
+ /**
+ * wait in between threads if specified
+ */
+ if (m_think_time)
+ {
+ m_Threader->ThreadSleep(m_think_time);
+ }
+ }
+
+ if (m_pHooks)
+ {
+ m_pHooks->OnWorkerStop(this);
+ }
+}
+
+SWThreadHandle *ThreadWorker::PopThreadFromQueue()
+{
+ if (m_state <= Worker_Stopped && !m_QueueLock)
+ {
+ return NULL;
+ }
+
+ SWThreadHandle *swt;
+ m_QueueLock->Lock();
+ swt = BaseWorker::PopThreadFromQueue();
+ m_QueueLock->Unlock();
+
+ return swt;
+}
+
+void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
+{
+ if (m_state <= Worker_Stopped)
+ {
+ return;
+ }
+
+ m_QueueLock->Lock();
+ BaseWorker::AddThreadToQueue(pHandle);
+ if (m_Waiting)
+ {
+ m_AddSignal->Signal();
+ }
+ m_QueueLock->Unlock();
+}
+
+WorkerState ThreadWorker::GetStatus(unsigned int *threads)
+{
+ WorkerState state;
+
+ m_StateLock->Lock();
+ state = BaseWorker::GetStatus(threads);
+ m_StateLock->Unlock();
+
+ return state;
+}
+
+bool ThreadWorker::Start()
+{
+ if (m_state == Worker_Invalid)
+ {
+ if (m_Threader == NULL)
+ {
+ return false;
+ }
+ } else if (m_state != Worker_Stopped) {
+ return false;
+ }
+
+ m_Waiting = false;
+ m_QueueLock = m_Threader->MakeMutex();
+ m_StateLock = m_Threader->MakeMutex();
+ m_PauseSignal = m_Threader->MakeEventSignal();
+ m_AddSignal = m_Threader->MakeEventSignal();
+ m_state = Worker_Running;
+ ThreadParams pt;
+ pt.flags = Thread_Default;
+ pt.prio = ThreadPrio_Normal;
+ me = m_Threader->MakeThread(this, &pt);
+
+ return true;
+}
+
+bool ThreadWorker::Stop(bool flush_cancel)
+{
+ if (m_state == Worker_Invalid || m_state == Worker_Stopped)
+ {
+ return false;
+ }
+
+ WorkerState oldstate;
+
+ //set new state
+ m_StateLock->Lock();
+ oldstate = m_state;
+ m_state = Worker_Stopped;
+ m_FlushType = flush_cancel;
+ m_StateLock->Unlock();
+
+ if (oldstate == Worker_Paused)
+ {
+ Unpause();
+ } else {
+ m_QueueLock->Lock();
+ if (m_Waiting)
+ {
+ m_AddSignal->Signal();
+ }
+ m_QueueLock->Unlock();
+ }
+
+ me->WaitForThread();
+ //destroy it
+ me->DestroyThis();
+ //flush all remaining events
+ Flush(true);
+
+ //free mutex locks
+ m_QueueLock->DestroyThis();
+ m_StateLock->DestroyThis();
+ m_PauseSignal->DestroyThis();
+ m_AddSignal->DestroyThis();
+
+ //invalidizzle
+ m_QueueLock = NULL;
+ m_StateLock = NULL;
+ m_PauseSignal = NULL;
+ m_AddSignal = NULL;
+ me = NULL;
+
+ return true;
+}
+
+bool ThreadWorker::Pause()
+{
+ if (m_state != Worker_Running)
+ {
+ return false;
+ }
+
+ m_StateLock->Lock();
+ m_state = Worker_Paused;
+ m_StateLock->Unlock();
+
+ return true;
+}
+
+
+bool ThreadWorker::Unpause()
+{
+ if (m_state != Worker_Paused)
+ {
+ return false;
+ }
+
+ m_StateLock->Lock();
+ m_state = Worker_Running;
+ m_StateLock->Unlock();
+ m_PauseSignal->Signal();
+ if (m_Waiting)
+ {
+ m_AddSignal->Signal();
+ }
+
+ return true;
+}