1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/thread/ThreadWorker.cpp Mon Jul 09 16:10:23 2007 +0000
1.3 @@ -0,0 +1,272 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * ===============================================================
1.7 + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
1.8 + * ===============================================================
1.9 + *
1.10 + * This file is not open source and may not be copied without explicit
1.11 + * written permission of AlliedModders LLC. This file may not be redistributed
1.12 + * in whole or significant part.
1.13 + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
1.14 + *
1.15 + * Version: $Id$
1.16 + */
1.17 +
1.18 +#include "ThreadWorker.h"
1.19 +
1.20 +ThreadWorker::ThreadWorker() :
1.21 + m_Threader(NULL),
1.22 + m_QueueLock(NULL),
1.23 + m_StateLock(NULL),
1.24 + m_PauseSignal(NULL),
1.25 + m_AddSignal(NULL),
1.26 + me(NULL),
1.27 + m_think_time(DEFAULT_THINK_TIME_MS)
1.28 +{
1.29 + m_state = Worker_Invalid;
1.30 +}
1.31 +
1.32 +ThreadWorker::ThreadWorker(IThreader *pThreader, unsigned int thinktime) :
1.33 + m_Threader(pThreader),
1.34 + m_QueueLock(NULL),
1.35 + m_StateLock(NULL),
1.36 + m_PauseSignal(NULL),
1.37 + m_AddSignal(NULL),
1.38 + me(NULL),
1.39 + m_think_time(thinktime)
1.40 +{
1.41 + if (m_Threader)
1.42 + {
1.43 + m_state = Worker_Stopped;
1.44 + } else {
1.45 + m_state = Worker_Invalid;
1.46 + }
1.47 +}
1.48 +
1.49 +ThreadWorker::~ThreadWorker()
1.50 +{
1.51 + if (m_state != Worker_Stopped || m_state != Worker_Invalid)
1.52 + Stop(true);
1.53 +
1.54 + if (m_ThreadQueue.size())
1.55 + Flush(true);
1.56 +}
1.57 +
1.58 +void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel)
1.59 +{
1.60 + //we don't particularly care
1.61 + return;
1.62 +}
1.63 +
1.64 +void ThreadWorker::RunThread(IThreadHandle *pHandle)
1.65 +{
1.66 + WorkerState this_state = Worker_Running;
1.67 + size_t num;
1.68 +
1.69 + while (true)
1.70 + {
1.71 + /**
1.72 + * Check number of items in the queue
1.73 + */
1.74 + m_StateLock->Lock();
1.75 + this_state = m_state;
1.76 + m_StateLock->Unlock();
1.77 + if (this_state != Worker_Stopped)
1.78 + {
1.79 + m_QueueLock->Lock();
1.80 + num = m_ThreadQueue.size();
1.81 + if (!num)
1.82 + {
1.83 + /**
1.84 + * if none, wait for an item
1.85 + */
1.86 + m_Waiting = true;
1.87 + m_QueueLock->Unlock();
1.88 + /* first check if we should end again */
1.89 + if (this_state == Worker_Stopped)
1.90 + {
1.91 + break;
1.92 + }
1.93 + m_AddSignal->Wait();
1.94 + m_Waiting = false;
1.95 + } else {
1.96 + m_QueueLock->Unlock();
1.97 + }
1.98 + }
1.99 + m_StateLock->Lock();
1.100 + this_state = m_state;
1.101 + m_StateLock->Unlock();
1.102 + if (this_state != Worker_Running)
1.103 + {
1.104 + if (this_state == Worker_Paused || this_state == Worker_Stopped)
1.105 + {
1.106 + //wait until the lock is cleared.
1.107 + if (this_state == Worker_Paused)
1.108 + {
1.109 + m_PauseSignal->Wait();
1.110 + }
1.111 + if (this_state == Worker_Stopped)
1.112 + {
1.113 + //if we're supposed to flush cleanrly,
1.114 + // run all of the remaining frames first.
1.115 + if (!m_FlushType)
1.116 + {
1.117 + while (m_ThreadQueue.size())
1.118 + RunFrame();
1.119 + }
1.120 + break;
1.121 + }
1.122 + }
1.123 + }
1.124 + /**
1.125 + * Run the frame.
1.126 + */
1.127 + RunFrame();
1.128 +
1.129 + /**
1.130 + * wait in between threads if specified
1.131 + */
1.132 + if (m_think_time)
1.133 + m_Threader->ThreadSleep(m_think_time);
1.134 + }
1.135 +}
1.136 +
1.137 +SWThreadHandle *ThreadWorker::PopThreadFromQueue()
1.138 +{
1.139 + if (m_state <= Worker_Stopped && !m_QueueLock)
1.140 + return NULL;
1.141 +
1.142 + SWThreadHandle *swt;
1.143 + m_QueueLock->Lock();
1.144 + swt = BaseWorker::PopThreadFromQueue();
1.145 + m_QueueLock->Unlock();
1.146 +
1.147 + return swt;
1.148 +}
1.149 +
1.150 +void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
1.151 +{
1.152 + if (m_state <= Worker_Stopped)
1.153 + return;
1.154 +
1.155 + m_QueueLock->Lock();
1.156 + BaseWorker::AddThreadToQueue(pHandle);
1.157 + if (m_Waiting)
1.158 + {
1.159 + m_AddSignal->Signal();
1.160 + }
1.161 + m_QueueLock->Unlock();
1.162 +}
1.163 +
1.164 +WorkerState ThreadWorker::GetStatus(unsigned int *threads)
1.165 +{
1.166 + WorkerState state;
1.167 +
1.168 + m_StateLock->Lock();
1.169 + state = BaseWorker::GetStatus(threads);
1.170 + m_StateLock->Unlock();
1.171 +
1.172 + return state;
1.173 +}
1.174 +
1.175 +bool ThreadWorker::Start()
1.176 +{
1.177 + if (m_state == Worker_Invalid)
1.178 + {
1.179 + if (m_Threader == NULL)
1.180 + return false;
1.181 + } else if (m_state != Worker_Stopped) {
1.182 + return false;
1.183 + }
1.184 +
1.185 + m_Waiting = false;
1.186 + m_QueueLock = m_Threader->MakeMutex();
1.187 + m_StateLock = m_Threader->MakeMutex();
1.188 + m_PauseSignal = m_Threader->MakeEventSignal();
1.189 + m_AddSignal = m_Threader->MakeEventSignal();
1.190 + m_state = Worker_Running;
1.191 + ThreadParams pt;
1.192 + pt.flags = Thread_Default;
1.193 + pt.prio = ThreadPrio_Normal;
1.194 + me = m_Threader->MakeThread(this, &pt);
1.195 +
1.196 + return true;
1.197 +}
1.198 +
1.199 +bool ThreadWorker::Stop(bool flush_cancel)
1.200 +{
1.201 + if (m_state == Worker_Invalid || m_state == Worker_Stopped)
1.202 + return false;
1.203 +
1.204 + WorkerState oldstate;
1.205 +
1.206 + //set new state
1.207 + m_StateLock->Lock();
1.208 + oldstate = m_state;
1.209 + m_state = Worker_Stopped;
1.210 + m_FlushType = flush_cancel;
1.211 + m_StateLock->Unlock();
1.212 +
1.213 + if (oldstate == Worker_Paused)
1.214 + {
1.215 + Unpause();
1.216 + } else {
1.217 + m_QueueLock->Lock();
1.218 + if (m_Waiting)
1.219 + {
1.220 + m_AddSignal->Signal();
1.221 + }
1.222 + m_QueueLock->Unlock();
1.223 + }
1.224 +
1.225 + me->WaitForThread();
1.226 + //destroy it
1.227 + me->DestroyThis();
1.228 + //flush all remaining events
1.229 + Flush(true);
1.230 +
1.231 + //free mutex locks
1.232 + m_QueueLock->DestroyThis();
1.233 + m_StateLock->DestroyThis();
1.234 + m_PauseSignal->DestroyThis();
1.235 + m_AddSignal->DestroyThis();
1.236 +
1.237 + //invalidizzle
1.238 + m_QueueLock = NULL;
1.239 + m_StateLock = NULL;
1.240 + m_PauseSignal = NULL;
1.241 + m_AddSignal = NULL;
1.242 + me = NULL;
1.243 +
1.244 + return true;
1.245 +}
1.246 +
1.247 +bool ThreadWorker::Pause()
1.248 +{
1.249 + if (m_state != Worker_Running)
1.250 + return false;
1.251 +
1.252 + m_StateLock->Lock();
1.253 + m_state = Worker_Paused;
1.254 + m_StateLock->Unlock();
1.255 +
1.256 + return true;
1.257 +}
1.258 +
1.259 +
1.260 +bool ThreadWorker::Unpause()
1.261 +{
1.262 + if (m_state != Worker_Paused)
1.263 + return false;
1.264 +
1.265 + m_StateLock->Lock();
1.266 + m_state = Worker_Running;
1.267 + m_StateLock->Unlock();
1.268 + m_PauseSignal->Signal();
1.269 + if (m_Waiting)
1.270 + {
1.271 + m_AddSignal->Signal();
1.272 + }
1.273 +
1.274 + return true;
1.275 +}