core/logic/thread/ThreadWorker.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4025 542dde661d5c
permissions -rw-r--r--
Update CS:GO team score gamedata.
dvander@2726
     1
/**
dvander@2726
     2
 * vim: set ts=4 :
dvander@2726
     3
 * =============================================================================
dvander@2726
     4
 * SourceMod
dvander@2726
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2726
     6
 * =============================================================================
dvander@2726
     7
 *
dvander@2726
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2726
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2726
    10
 * Free Software Foundation.
dvander@2726
    11
 * 
dvander@2726
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2726
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2726
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2726
    15
 * details.
dvander@2726
    16
 *
dvander@2726
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2726
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2726
    19
 *
dvander@2726
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2726
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2726
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2726
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2726
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2726
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2726
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2726
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2726
    28
 *
dvander@2726
    29
 * Version: $Id$
dvander@2726
    30
 */
dvander@2726
    31
dvander@2726
    32
#include "ThreadWorker.h"
dvander@2726
    33
dvander@2726
    34
ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks) : BaseWorker(hooks),
dvander@2726
    35
	m_Threader(NULL),
dvander@2726
    36
	me(NULL),
dvander@2726
    37
	m_think_time(DEFAULT_THINK_TIME_MS)
dvander@2726
    38
{
dvander@2726
    39
	m_state = Worker_Invalid;
dvander@2726
    40
}
dvander@2726
    41
dvander@2726
    42
ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime) : 
dvander@2726
    43
	BaseWorker(hooks),
dvander@2726
    44
	m_Threader(pThreader),
dvander@2726
    45
	me(NULL),
dvander@2726
    46
	m_think_time(thinktime)
dvander@2726
    47
{
dvander@4025
    48
	m_state = m_Threader ? Worker_Stopped : Worker_Invalid;
dvander@2726
    49
}
dvander@2726
    50
dvander@2726
    51
ThreadWorker::~ThreadWorker()
dvander@2726
    52
{
dvander@2726
    53
	if (m_state != Worker_Stopped || m_state != Worker_Invalid)
dvander@2726
    54
		Stop(true);
dvander@4025
    55
	
dvander@2726
    56
	if (m_ThreadQueue.size())
dvander@2726
    57
		Flush(true);
dvander@2726
    58
}
dvander@2726
    59
dvander@2726
    60
void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel)
dvander@2726
    61
{
dvander@2726
    62
	//we don't particularly care
dvander@2726
    63
	return;
dvander@2726
    64
}
dvander@2726
    65
dvander@2726
    66
void ThreadWorker::RunThread(IThreadHandle *pHandle)
dvander@2726
    67
{
dvander@4025
    68
	if (m_pHooks)
dvander@4025
    69
		m_pHooks->OnWorkerStart(this);
dvander@2726
    70
dvander@4025
    71
	ke::AutoLock lock(&monitor_);
dvander@4025
    72
dvander@2726
    73
	while (true)
dvander@2726
    74
	{
dvander@4025
    75
		if (m_state == Worker_Paused)
dvander@2726
    76
		{
dvander@4025
    77
			// Wait until we're told to wake up.
dvander@4025
    78
			monitor_.Wait();
dvander@4025
    79
			continue;
dvander@2726
    80
		}
dvander@4025
    81
dvander@4025
    82
		if (m_state == Worker_Stopped)
dvander@2726
    83
		{
dvander@4025
    84
			// We've been told to stop entirely. If we've also been told to
dvander@4025
    85
			// flush the queue, do that now.
dvander@4025
    86
			while (!m_ThreadQueue.empty())
dvander@2726
    87
			{
dvander@4025
    88
				// Release the lock since PopThreadFromQueue() will re-acquire it. The
dvander@4025
    89
				// main thread is blocking anyway.
dvander@4025
    90
				ke::AutoUnlock unlock(&monitor_);
dvander@4025
    91
				RunFrame();
dvander@2726
    92
			}
dvander@4025
    93
			assert(m_state == Worker_Stopped);
dvander@4025
    94
			return;
dvander@2726
    95
		}
dvander@4025
    96
dvander@4025
    97
		assert(m_state == Worker_Running);
dvander@4025
    98
dvander@4025
    99
		// Process one frame.
dvander@4025
   100
		WorkerState oldstate = m_state;
dvander@4025
   101
		{
dvander@4025
   102
			ke::AutoUnlock unlock(&monitor_);
dvander@4025
   103
			RunFrame();
dvander@4025
   104
		}
dvander@2726
   105
dvander@4025
   106
		// If the state changed, loop back and process the new state.
dvander@4025
   107
		if (m_state != oldstate)
dvander@4025
   108
			continue;
dvander@4025
   109
		
dvander@4025
   110
		// If the thread queue is now empty, wait for a signal. Otherwise, if
dvander@4025
   111
		// we're on a delay, wait for either a notification or a timeout to
dvander@4025
   112
		// process the next item. If the queue has items and we don't have a
dvander@4025
   113
		// delay, then we just loop around and keep processing.
dvander@4025
   114
		if (m_ThreadQueue.empty())
dvander@4025
   115
			monitor_.Wait();
dvander@4025
   116
		else if (m_think_time)
dvander@4025
   117
			monitor_.Wait(m_think_time);
dvander@2726
   118
	}
dvander@2726
   119
dvander@2726
   120
	{
dvander@4025
   121
		ke::AutoUnlock unlock(&monitor_);
dvander@4025
   122
		if (m_pHooks)
dvander@4025
   123
			m_pHooks->OnWorkerStop(this);
dvander@2726
   124
	}
dvander@2726
   125
}
dvander@2726
   126
dvander@2726
   127
SWThreadHandle *ThreadWorker::PopThreadFromQueue()
dvander@2726
   128
{
dvander@4025
   129
	ke::AutoLock lock(&monitor_);
dvander@4025
   130
	if (m_state <= Worker_Stopped)
dvander@2726
   131
		return NULL;
dvander@2726
   132
dvander@4025
   133
	return BaseWorker::PopThreadFromQueue();
dvander@2726
   134
}
dvander@2726
   135
dvander@2726
   136
void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
dvander@2726
   137
{
dvander@4025
   138
	ke::AutoLock lock(&monitor_);
dvander@2726
   139
	if (m_state <= Worker_Stopped)
dvander@2726
   140
		return;
dvander@2726
   141
dvander@2726
   142
	BaseWorker::AddThreadToQueue(pHandle);
dvander@4025
   143
	monitor_.Notify();
dvander@2726
   144
}
dvander@2726
   145
dvander@2726
   146
WorkerState ThreadWorker::GetStatus(unsigned int *threads)
dvander@2726
   147
{
dvander@4025
   148
	ke::AutoLock lock(&monitor_);
dvander@4025
   149
	return BaseWorker::GetStatus(threads);
dvander@2726
   150
}
dvander@2726
   151
asherkin@3704
   152
void ThreadWorker::SetThinkTimePerFrame(unsigned int thinktime)
asherkin@3704
   153
{
asherkin@3704
   154
	m_think_time = thinktime;
asherkin@3704
   155
}
asherkin@3704
   156
dvander@2726
   157
bool ThreadWorker::Start()
dvander@2726
   158
{
dvander@4025
   159
	if (m_state == Worker_Invalid && m_Threader == NULL)
dvander@2726
   160
		return false;
dvander@2726
   161
dvander@4025
   162
	if (m_state != Worker_Stopped)
dvander@4025
   163
		return false;
dvander@4025
   164
dvander@2726
   165
	m_state = Worker_Running;
dvander@4025
   166
dvander@2726
   167
	ThreadParams pt;
dvander@2726
   168
	pt.flags = Thread_Default;
dvander@2726
   169
	pt.prio = ThreadPrio_Normal;
dvander@2726
   170
	me = m_Threader->MakeThread(this, &pt);
dvander@2726
   171
	return true;
dvander@2726
   172
}
dvander@2726
   173
dvander@2726
   174
bool ThreadWorker::Stop(bool flush_cancel)
dvander@2726
   175
{
dvander@4025
   176
	// Change the state to signal a stop, and then trigger a notify.
dvander@2726
   177
	{
dvander@4025
   178
		ke::AutoLock lock(&monitor_);
dvander@4025
   179
		if (m_state == Worker_Invalid || m_state == Worker_Stopped)
dvander@4025
   180
			return false;
dvander@2726
   181
dvander@4025
   182
		m_state = Worker_Stopped;
dvander@4025
   183
		m_FlushType = flush_cancel;
dvander@4025
   184
		monitor_.Notify();
dvander@2726
   185
	}
dvander@2726
   186
dvander@2726
   187
	me->WaitForThread();
dvander@2726
   188
	//destroy it
dvander@2726
   189
	me->DestroyThis();
dvander@2726
   190
	//flush all remaining events
dvander@2726
   191
	Flush(true);
dvander@2726
   192
dvander@2726
   193
	me = NULL;
dvander@2726
   194
	return true;
dvander@2726
   195
}
dvander@2726
   196
dvander@2726
   197
bool ThreadWorker::Pause()
dvander@2726
   198
{
dvander@2726
   199
	if (m_state != Worker_Running)
dvander@2726
   200
		return false;
dvander@2726
   201
dvander@4025
   202
	ke::AutoLock lock(&monitor_);
dvander@2726
   203
	m_state = Worker_Paused;
dvander@4025
   204
	monitor_.Notify();
dvander@2726
   205
	return true;
dvander@2726
   206
}
dvander@2726
   207
dvander@2726
   208
dvander@2726
   209
bool ThreadWorker::Unpause()
dvander@2726
   210
{
dvander@2726
   211
	if (m_state != Worker_Paused)
dvander@2726
   212
		return false;
dvander@2726
   213
dvander@4025
   214
	ke::AutoLock lock(&monitor_);
dvander@2726
   215
	m_state = Worker_Running;
dvander@4025
   216
	monitor_.Notify();
dvander@2726
   217
	return true;
dvander@2726
   218
}