core/thread/ThreadWorker.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Jul 15 08:00:26 2007 +0000 (2007-07-15)
changeset 1116 40cc5e9f0f1b
parent 1090 5c54e353c019
child 1231 17badaf66ce4
permissions -rw-r--r--
Removed strange debugging code
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "ThreadWorker.h"
    16 
    17 ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks) : BaseWorker(hooks),
    18 	m_Threader(NULL),
    19 	m_QueueLock(NULL),
    20 	m_StateLock(NULL),
    21 	m_PauseSignal(NULL),
    22 	m_AddSignal(NULL),
    23 	me(NULL),
    24 	m_think_time(DEFAULT_THINK_TIME_MS)
    25 {
    26 	m_state = Worker_Invalid;
    27 }
    28 
    29 ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime) : 
    30 	BaseWorker(hooks),
    31 	m_Threader(pThreader),
    32 	m_QueueLock(NULL),
    33 	m_StateLock(NULL),
    34 	m_PauseSignal(NULL),
    35 	m_AddSignal(NULL),
    36 	me(NULL),
    37 	m_think_time(thinktime)
    38 {
    39 	if (m_Threader)
    40 	{
    41 		m_state = Worker_Stopped;
    42 	} else {
    43 		m_state = Worker_Invalid;
    44 	}
    45 }
    46 
    47 ThreadWorker::~ThreadWorker()
    48 {
    49 	if (m_state != Worker_Stopped || m_state != Worker_Invalid)
    50 	{
    51 		Stop(true);
    52 	}
    53 
    54 	if (m_ThreadQueue.size())
    55 	{
    56 		Flush(true);
    57 	}
    58 }
    59 
    60 void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel)
    61 {
    62 	//we don't particularly care
    63 	return;
    64 }
    65 
    66 void ThreadWorker::RunThread(IThreadHandle *pHandle)
    67 {
    68 	WorkerState this_state = Worker_Running;
    69 	size_t num;
    70 
    71 	if (m_pHooks)
    72 	{
    73 		m_pHooks->OnWorkerStart(this);
    74 	}
    75     
    76 	while (true)
    77 	{
    78 		/**
    79 		 * Check number of items in the queue
    80 		 */
    81 		m_StateLock->Lock();
    82 		this_state = m_state;
    83 		m_StateLock->Unlock();
    84 		if (this_state != Worker_Stopped)
    85 		{
    86 			m_QueueLock->Lock();
    87 			num = m_ThreadQueue.size();
    88 			if (!num)
    89 			{
    90 				/** 
    91 				 * if none, wait for an item
    92 				 */
    93 				m_Waiting = true;
    94 				m_QueueLock->Unlock();
    95 				/* first check if we should end again */
    96 				if (this_state == Worker_Stopped)
    97 				{
    98 					break;
    99 				}
   100 				m_AddSignal->Wait();
   101 				m_Waiting = false;
   102 			} else {
   103 				m_QueueLock->Unlock();
   104 			}
   105 		}
   106 		m_StateLock->Lock();
   107 		this_state = m_state;
   108 		m_StateLock->Unlock();
   109 		if (this_state != Worker_Running)
   110 		{
   111 			if (this_state == Worker_Paused || this_state == Worker_Stopped)
   112 			{
   113 				//wait until the lock is cleared.
   114 				if (this_state == Worker_Paused)
   115 				{
   116 					m_PauseSignal->Wait();
   117 				}
   118 				if (this_state == Worker_Stopped)
   119 				{
   120 					//if we're supposed to flush cleanrly, 
   121 					// run all of the remaining frames first.
   122 					if (!m_FlushType)
   123 					{
   124 						while (m_ThreadQueue.size())
   125 						{
   126 							RunFrame();
   127 						}
   128 					}
   129 					break;
   130 				}
   131 			}
   132 		}
   133 		/**
   134 		 * Run the frame.
   135 		 */
   136 		RunFrame();
   137 
   138 		/**
   139 		 * wait in between threads if specified
   140 		 */
   141 		if (m_think_time)
   142 		{
   143 			m_Threader->ThreadSleep(m_think_time);
   144 		}
   145 	}
   146 
   147 	if (m_pHooks)
   148 	{
   149 		m_pHooks->OnWorkerStop(this);
   150 	}
   151 }
   152 
   153 SWThreadHandle *ThreadWorker::PopThreadFromQueue()
   154 {
   155 	if (m_state <= Worker_Stopped && !m_QueueLock)
   156 	{
   157 		return NULL;
   158 	}
   159 
   160 	SWThreadHandle *swt;
   161 	m_QueueLock->Lock();
   162 	swt = BaseWorker::PopThreadFromQueue();
   163 	m_QueueLock->Unlock();
   164 
   165 	return swt;
   166 }
   167 
   168 void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
   169 {
   170 	if (m_state <= Worker_Stopped)
   171 	{
   172 		return;
   173 	}
   174 
   175 	m_QueueLock->Lock();
   176 	BaseWorker::AddThreadToQueue(pHandle);
   177 	if (m_Waiting)
   178 	{
   179 		m_AddSignal->Signal();
   180 	}
   181 	m_QueueLock->Unlock();
   182 }
   183 
   184 WorkerState ThreadWorker::GetStatus(unsigned int *threads)
   185 {
   186 	WorkerState state;
   187 
   188 	m_StateLock->Lock();
   189 	state = BaseWorker::GetStatus(threads);
   190 	m_StateLock->Unlock();
   191 
   192 	return state;
   193 }
   194 
   195 bool ThreadWorker::Start()
   196 {
   197 	if (m_state == Worker_Invalid)
   198 	{
   199 		if (m_Threader == NULL)
   200 		{
   201 			return false;
   202 		}
   203 	} else if (m_state != Worker_Stopped) {
   204 		return false;
   205 	}
   206 
   207 	m_Waiting = false;
   208 	m_QueueLock = m_Threader->MakeMutex();
   209 	m_StateLock = m_Threader->MakeMutex();
   210 	m_PauseSignal = m_Threader->MakeEventSignal();
   211 	m_AddSignal = m_Threader->MakeEventSignal();
   212 	m_state = Worker_Running;
   213 	ThreadParams pt;
   214 	pt.flags = Thread_Default;
   215 	pt.prio = ThreadPrio_Normal;
   216 	me = m_Threader->MakeThread(this, &pt);
   217 
   218 	return true;
   219 }
   220 
   221 bool ThreadWorker::Stop(bool flush_cancel)
   222 {
   223 	if (m_state == Worker_Invalid || m_state == Worker_Stopped)
   224 	{
   225 		return false;
   226 	}
   227 
   228 	WorkerState oldstate;
   229 
   230 	//set new state
   231 	m_StateLock->Lock();
   232 	oldstate = m_state;
   233 	m_state = Worker_Stopped;
   234 	m_FlushType = flush_cancel;
   235 	m_StateLock->Unlock();
   236 
   237 	if (oldstate == Worker_Paused)
   238 	{
   239 		Unpause();
   240 	} else {
   241 		m_QueueLock->Lock();
   242 		if (m_Waiting)
   243 		{
   244 			m_AddSignal->Signal();
   245 		}
   246 		m_QueueLock->Unlock();
   247 	}
   248 
   249 	me->WaitForThread();
   250 	//destroy it
   251 	me->DestroyThis();
   252 	//flush all remaining events
   253 	Flush(true);
   254 
   255 	//free mutex locks
   256 	m_QueueLock->DestroyThis();
   257 	m_StateLock->DestroyThis();
   258 	m_PauseSignal->DestroyThis();
   259 	m_AddSignal->DestroyThis();
   260 
   261 	//invalidizzle
   262 	m_QueueLock = NULL;
   263 	m_StateLock = NULL;
   264 	m_PauseSignal = NULL;
   265 	m_AddSignal = NULL;
   266 	me = NULL;
   267 
   268 	return true;
   269 }
   270 
   271 bool ThreadWorker::Pause()
   272 {
   273 	if (m_state != Worker_Running)
   274 	{
   275 		return false;
   276 	}
   277 
   278 	m_StateLock->Lock();
   279 	m_state = Worker_Paused;
   280 	m_StateLock->Unlock();
   281 
   282 	return true;
   283 }
   284 
   285 
   286 bool ThreadWorker::Unpause()
   287 {
   288 	if (m_state != Worker_Paused)
   289 	{
   290 		return false;
   291 	}
   292 
   293 	m_StateLock->Lock();
   294 	m_state = Worker_Running;
   295 	m_StateLock->Unlock();
   296 	m_PauseSignal->Signal();
   297 	if (m_Waiting)
   298 	{
   299 		m_AddSignal->Signal();
   300 	}
   301 
   302 	return true;
   303 }