Rewrite IThreader implementation around new synchronization primitives (bug 5862, r=fyren).
authorDavid Anderson <dvander@alliedmods.net>
Mon Aug 19 20:58:02 2013 -0700 (2013-08-19)
changeset 4025542dde661d5c
parent 4024 152f31d6b8ca
child 4026 684cf3490051
Rewrite IThreader implementation around new synchronization primitives (bug 5862, r=fyren).
AMBuildScript
core/ConVarManager.cpp
core/MenuStyle_Radio.cpp
core/logic/AMBuilder
core/logic/ThreadSupport.h
core/logic/thread/PosixThreads.cpp
core/logic/thread/PosixThreads.h
core/logic/thread/ThreadWorker.cpp
core/logic/thread/ThreadWorker.h
core/logic/thread/WinThreads.cpp
core/logic/thread/WinThreads.h
public/IThreader.h
public/sourcepawn/ke_thread_utils.h
public/sourcepawn/ke_thread_windows.h
public/sourcepawn/ke_utility.h
     1.1 --- a/AMBuildScript	Mon Aug 19 12:59:10 2013 -0700
     1.2 +++ b/AMBuildScript	Mon Aug 19 20:58:02 2013 -0700
     1.3 @@ -163,6 +163,7 @@
     1.4  				self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
     1.5  				self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
     1.6  				self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
     1.7 +				self.compiler.AddToListVar('CXXFLAGS', '-Wno-narrowing')
     1.8  				if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \
     1.9  						(self.vendor == 'clang' and cxx.majorVersion >= 3):
    1.10  					self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor')
     2.1 --- a/core/ConVarManager.cpp	Mon Aug 19 12:59:10 2013 -0700
     2.2 +++ b/core/ConVarManager.cpp	Mon Aug 19 20:58:02 2013 -0700
     2.3 @@ -638,7 +638,7 @@
     2.4  		return InvalidQueryCvarCookie;
     2.5  	}
     2.6  
     2.7 -	ConVarQuery query = {cookie, pCallback, hndl};
     2.8 +	ConVarQuery query = {cookie, pCallback, (cell_t)hndl};
     2.9  	m_ConVarQueries.push_back(query);
    2.10  #endif
    2.11  
     3.1 --- a/core/MenuStyle_Radio.cpp	Mon Aug 19 12:59:10 2013 -0700
     3.2 +++ b/core/MenuStyle_Radio.cpp	Mon Aug 19 20:58:02 2013 -0700
     3.3 @@ -480,7 +480,7 @@
     3.4  void CRadioMenuPlayer::Radio_Refresh()
     3.5  {
     3.6  #if SOURCE_ENGINE != SE_DOTA
     3.7 -	cell_t players[1] = {m_index};
     3.8 +	cell_t players[1] = { (cell_t)m_index };
     3.9  	char *ptr = display_pkt;
    3.10  	char save = 0;
    3.11  	size_t len = display_len;
     4.1 --- a/core/logic/AMBuilder	Mon Aug 19 12:59:10 2013 -0700
     4.2 +++ b/core/logic/AMBuilder	Mon Aug 19 20:58:02 2013 -0700
     4.3 @@ -12,6 +12,7 @@
     4.4  
     4.5  if AMBuild.target['platform'] == 'linux':
     4.6  	compiler['POSTLINKFLAGS'].append('-lpthread')
     4.7 +	compiler['POSTLINKFLAGS'].append('-lrt')
     4.8  if AMBuild.target['platform'] == 'darwin':
     4.9  	compiler['CFLAGS'].extend(['-Wno-deprecated-declarations'])
    4.10  	compiler['POSTLINKFLAGS'].extend(['-framework', 'CoreServices'])
     5.1 --- a/core/logic/ThreadSupport.h	Mon Aug 19 12:59:10 2013 -0700
     5.2 +++ b/core/logic/ThreadSupport.h	Mon Aug 19 20:58:02 2013 -0700
     5.3 @@ -33,9 +33,48 @@
     5.4  #define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
     5.5  
     5.6  #include <IThreader.h>
     5.7 +#include <ke_thread_utils.h>
     5.8 +#include <ke_utility.h>
     5.9  
    5.10  using namespace SourceMod;
    5.11  
    5.12 +class CompatMutex : public IMutex
    5.13 +{
    5.14 +public:
    5.15 +	bool TryLock() {
    5.16 +		return mutex_.TryLock();
    5.17 +	}
    5.18 +	void Lock() {
    5.19 +		mutex_.Lock();
    5.20 +	}
    5.21 +	void Unlock() {
    5.22 +		mutex_.Unlock();
    5.23 +	}
    5.24 +	void DestroyThis() {
    5.25 +		delete this;
    5.26 +	}
    5.27 +private:
    5.28 +	ke::Mutex mutex_;
    5.29 +};
    5.30 +
    5.31 +class CompatCondVar : public IEventSignal
    5.32 +{
    5.33 +public:
    5.34 +	void Wait() {
    5.35 +		ke::AutoLock lock(&cv_);
    5.36 +		cv_.Wait();
    5.37 +	}
    5.38 +	void Signal() {
    5.39 +		ke::AutoLock lock(&cv_);
    5.40 +		cv_.Notify();
    5.41 +	}
    5.42 +	void DestroyThis() {
    5.43 +		delete this;
    5.44 +	}
    5.45 +private:
    5.46 +	ke::ConditionVariable cv_;
    5.47 +};
    5.48 +
    5.49  extern IThreader *g_pThreader;
    5.50  
    5.51  #endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
     6.1 --- a/core/logic/thread/PosixThreads.cpp	Mon Aug 19 12:59:10 2013 -0700
     6.2 +++ b/core/logic/thread/PosixThreads.cpp	Mon Aug 19 20:58:02 2013 -0700
     6.3 @@ -1,5 +1,5 @@
     6.4  /**
     6.5 - * vim: set ts=4 :
     6.6 + * vim: set ts=4 sw=4 tw=99 noet:
     6.7   * =============================================================================
     6.8   * SourceMod
     6.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    6.10 @@ -61,17 +61,9 @@
    6.11  
    6.12  IMutex *PosixThreader::MakeMutex()
    6.13  {
    6.14 -	pthread_mutex_t mutex;
    6.15 -
    6.16 -	if (pthread_mutex_init(&mutex, NULL) != 0)
    6.17 -		return NULL;
    6.18 -
    6.19 -	PosixMutex *pMutex = new PosixMutex(mutex);
    6.20 -
    6.21 -	return pMutex;
    6.22 +	return new CompatMutex();
    6.23  }
    6.24  
    6.25 -
    6.26  void PosixThreader::MakeThread(IThread *pThread)
    6.27  {
    6.28  	ThreadParams defparams;
    6.29 @@ -92,30 +84,21 @@
    6.30  	return MakeThread(pThread, &defparams);
    6.31  }
    6.32  
    6.33 -void *Posix_ThreadGate(void *param)
    6.34 +void PosixThreader::ThreadHandle::Run()
    6.35  {
    6.36 -	PosixThreader::ThreadHandle *pHandle = 
    6.37 -		reinterpret_cast<PosixThreader::ThreadHandle *>(param);
    6.38 -
    6.39 -	//Block this thread from being started initially.
    6.40 -	pthread_mutex_lock(&pHandle->m_runlock);
    6.41 -	//if we get here, we've obtained the lock and are allowed to run.
    6.42 -	//unlock and continue.
    6.43 -	pthread_mutex_unlock(&pHandle->m_runlock);
    6.44 +	// Wait for an unpause if necessary.
    6.45 +	{
    6.46 +		ke::AutoLock lock(&m_runlock);
    6.47 +		if (m_state == Thread_Paused)
    6.48 +			m_runlock.Wait();
    6.49 +	}
    6.50  
    6.51 -	pHandle->m_run->RunThread(pHandle);
    6.52 +	m_run->RunThread(this);
    6.53 +	m_state = Thread_Done;
    6.54 +	m_run->OnTerminate(this, false);
    6.55  
    6.56 -	ThreadParams params;
    6.57 -	pthread_mutex_lock(&pHandle->m_statelock);
    6.58 -	pHandle->m_state = Thread_Done;
    6.59 -	pHandle->GetParams(&params);
    6.60 -	pthread_mutex_unlock(&pHandle->m_statelock);
    6.61 -
    6.62 -	pHandle->m_run->OnTerminate(pHandle, false);
    6.63 -	if (params.flags & Thread_AutoRelease)
    6.64 -		delete pHandle;
    6.65 -
    6.66 -	return 0;
    6.67 +	if (m_params.flags & Thread_AutoRelease)
    6.68 +		delete this;
    6.69  }
    6.70  
    6.71  ThreadParams g_defparams;
    6.72 @@ -124,68 +107,21 @@
    6.73  	if (params == NULL)
    6.74  		params = &g_defparams;
    6.75  
    6.76 -	PosixThreader::ThreadHandle *pHandle = 
    6.77 -		new PosixThreader::ThreadHandle(this, pThread, params);
    6.78 -
    6.79 -	pthread_mutex_lock(&pHandle->m_runlock);
    6.80 +	ke::AutoPtr<ThreadHandle> pHandle(new ThreadHandle(this, pThread, params));
    6.81  
    6.82 -	int err;
    6.83 -	err = pthread_create(&pHandle->m_thread, NULL, Posix_ThreadGate, (void *)pHandle);	
    6.84 -
    6.85 -	if (err != 0)
    6.86 -	{
    6.87 -		pthread_mutex_unlock(&pHandle->m_runlock);
    6.88 -		delete pHandle;
    6.89 +	pHandle->m_thread = new ke::Thread(pHandle, "SourceMod");
    6.90 +	if (!pHandle->m_thread->Succeeded())
    6.91  		return NULL;
    6.92 -	}
    6.93 -
    6.94 -	//Don't bother setting priority...
    6.95  
    6.96 -	if (!(pHandle->m_params.flags & Thread_CreateSuspended))
    6.97 -	{
    6.98 -		pHandle->m_state = Thread_Running;
    6.99 -		err = pthread_mutex_unlock(&pHandle->m_runlock);
   6.100 -		if (err != 0)
   6.101 -			pHandle->m_state = Thread_Paused;
   6.102 -	}
   6.103 +	if (!(params->flags & Thread_CreateSuspended))
   6.104 +		pHandle->Unpause();
   6.105  
   6.106 -	return pHandle;
   6.107 +	return pHandle.take();
   6.108  }
   6.109  
   6.110  IEventSignal *PosixThreader::MakeEventSignal()
   6.111  {
   6.112 -	return new PosixEventSignal();
   6.113 -}
   6.114 -
   6.115 -/*****************
   6.116 -**** Mutexes ****
   6.117 -*****************/
   6.118 -
   6.119 -PosixThreader::PosixMutex::~PosixMutex()
   6.120 -{
   6.121 -	pthread_mutex_destroy(&m_mutex);
   6.122 -}
   6.123 -
   6.124 -bool PosixThreader::PosixMutex::TryLock()
   6.125 -{
   6.126 -	int err = pthread_mutex_trylock(&m_mutex);
   6.127 -
   6.128 -	return (err == 0);
   6.129 -}
   6.130 -
   6.131 -void PosixThreader::PosixMutex::Lock()
   6.132 -{
   6.133 -	pthread_mutex_lock(&m_mutex);
   6.134 -}
   6.135 -
   6.136 -void PosixThreader::PosixMutex::Unlock()
   6.137 -{
   6.138 -	pthread_mutex_unlock(&m_mutex);
   6.139 -}
   6.140 -
   6.141 -void PosixThreader::PosixMutex::DestroyThis()
   6.142 -{
   6.143 -	delete this;
   6.144 +	return new CompatCondVar();
   6.145  }
   6.146  
   6.147  /******************
   6.148 @@ -195,35 +131,24 @@
   6.149  PosixThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) : 
   6.150  	m_parent(parent), m_params(*params), m_run(run), m_state(Thread_Paused)
   6.151  {
   6.152 -	pthread_mutex_init(&m_runlock, NULL);
   6.153 -	pthread_mutex_init(&m_statelock, NULL);
   6.154  }
   6.155  
   6.156  PosixThreader::ThreadHandle::~ThreadHandle()
   6.157  {
   6.158 -	pthread_mutex_destroy(&m_runlock);
   6.159 -	pthread_mutex_destroy(&m_statelock);
   6.160  }
   6.161  
   6.162  bool PosixThreader::ThreadHandle::WaitForThread()
   6.163  {
   6.164 -	void *arg;
   6.165 -	
   6.166 -	if (pthread_join(m_thread, &arg) != 0)
   6.167 +	if (!m_thread)
   6.168  		return false;
   6.169  
   6.170 +	m_thread->Join();
   6.171  	return true;
   6.172  }
   6.173  
   6.174  ThreadState PosixThreader::ThreadHandle::GetState()
   6.175  {
   6.176 -	ThreadState state;
   6.177 -
   6.178 -	pthread_mutex_lock(&m_statelock);
   6.179 -	state = m_state;
   6.180 -	pthread_mutex_unlock(&m_statelock);
   6.181 -
   6.182 -	return state;
   6.183 +	return m_state;
   6.184  }
   6.185  
   6.186  IThreadCreator *PosixThreader::ThreadHandle::Parent()
   6.187 @@ -262,48 +187,9 @@
   6.188  	if (m_state != Thread_Paused)
   6.189  		return false;
   6.190  
   6.191 +	ke::AutoLock lock(&m_runlock);
   6.192  	m_state = Thread_Running;
   6.193 -
   6.194 -	if (pthread_mutex_unlock(&m_runlock) != 0)
   6.195 -	{
   6.196 -		m_state = Thread_Paused;
   6.197 -		return false;
   6.198 -	}
   6.199 -
   6.200 +	m_runlock.Notify();
   6.201  	return true;
   6.202  }
   6.203  
   6.204 -/*****************
   6.205 - * EVENT SIGNALS *
   6.206 - *****************/
   6.207 -
   6.208 -PosixThreader::PosixEventSignal::PosixEventSignal()
   6.209 -{
   6.210 -	pthread_cond_init(&m_cond, NULL);
   6.211 -	pthread_mutex_init(&m_mutex, NULL);
   6.212 -}
   6.213 -
   6.214 -PosixThreader::PosixEventSignal::~PosixEventSignal()
   6.215 -{
   6.216 -	pthread_cond_destroy(&m_cond);
   6.217 -	pthread_mutex_destroy(&m_mutex);
   6.218 -}
   6.219 -
   6.220 -void PosixThreader::PosixEventSignal::Wait()
   6.221 -{
   6.222 -	pthread_mutex_lock(&m_mutex);
   6.223 -	pthread_cond_wait(&m_cond, &m_mutex);
   6.224 -	pthread_mutex_unlock(&m_mutex);
   6.225 -}
   6.226 -
   6.227 -void PosixThreader::PosixEventSignal::Signal()
   6.228 -{
   6.229 -	pthread_mutex_lock(&m_mutex);
   6.230 -	pthread_cond_broadcast(&m_cond);
   6.231 -	pthread_mutex_unlock(&m_mutex);
   6.232 -}
   6.233 -
   6.234 -void PosixThreader::PosixEventSignal::DestroyThis()
   6.235 -{
   6.236 -        delete this;
   6.237 -}
     7.1 --- a/core/logic/thread/PosixThreads.h	Mon Aug 19 12:59:10 2013 -0700
     7.2 +++ b/core/logic/thread/PosixThreads.h	Mon Aug 19 20:58:02 2013 -0700
     7.3 @@ -1,5 +1,5 @@
     7.4  /**
     7.5 - * vim: set ts=4 :
     7.6 + * vim: set ts=4 sw=4 tw=99 noet:
     7.7   * =============================================================================
     7.8   * SourceMod
     7.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    7.10 @@ -33,19 +33,17 @@
    7.11  #define _INCLUDE_POSIXTHREADS_H_
    7.12  
    7.13  #include <pthread.h>
    7.14 +#include <ke_thread_utils.h>
    7.15  #include "IThreader.h"
    7.16  
    7.17  using namespace SourceMod;
    7.18  
    7.19 -void *Posix_ThreadGate(void *param);
    7.20 -
    7.21  class PosixThreader : public IThreader
    7.22  {
    7.23  public:
    7.24 -	class ThreadHandle : public IThreadHandle
    7.25 +	class ThreadHandle : public IThreadHandle, public ke::IRunnable
    7.26  	{
    7.27  		friend class PosixThreader;
    7.28 -		friend void *Posix_ThreadGate(void *param);
    7.29  	public:
    7.30  		ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params);
    7.31  		virtual ~ThreadHandle();
    7.32 @@ -58,43 +56,16 @@
    7.33  		virtual bool SetPriority(ThreadPriority prio);
    7.34  		virtual ThreadState GetState();
    7.35  		virtual bool Unpause();
    7.36 +	public:
    7.37 +		void Run();
    7.38  	protected:
    7.39  		IThreader *m_parent;		//Parent handle
    7.40 -		pthread_t m_thread;			//Windows HANDLE	
    7.41  		ThreadParams m_params;		//Current Parameters
    7.42 -		IThread *m_run;	//Runnable context
    7.43 -		pthread_mutex_t m_statelock;
    7.44 -		pthread_mutex_t m_runlock;
    7.45 +		IThread *m_run;				//Runnable context
    7.46 +		ke::AutoPtr<ke::Thread> m_thread;
    7.47 +		ke::ConditionVariable m_runlock;
    7.48  		ThreadState m_state;		//internal state
    7.49  	};
    7.50 -	class PosixMutex : public IMutex
    7.51 -	{
    7.52 -	public:
    7.53 -		PosixMutex(pthread_mutex_t m) : m_mutex(m)
    7.54 -		{
    7.55 -		};
    7.56 -		virtual ~PosixMutex();
    7.57 -	public:
    7.58 -		virtual bool TryLock();
    7.59 -		virtual void Lock();
    7.60 -		virtual void Unlock();
    7.61 -		virtual void DestroyThis();
    7.62 -	protected:
    7.63 -		pthread_mutex_t m_mutex;
    7.64 -	};
    7.65 -	class PosixEventSignal : public IEventSignal
    7.66 -	{
    7.67 -	public:
    7.68 -		PosixEventSignal();
    7.69 -		virtual ~PosixEventSignal();
    7.70 -	public:
    7.71 -		virtual void Wait();
    7.72 -		virtual void Signal();
    7.73 -		virtual void DestroyThis();
    7.74 -	protected:
    7.75 -		pthread_cond_t m_cond;
    7.76 -		pthread_mutex_t m_mutex;
    7.77 -	};
    7.78  public:
    7.79  	IMutex *MakeMutex();
    7.80  	void MakeThread(IThread *pThread);
     8.1 --- a/core/logic/thread/ThreadWorker.cpp	Mon Aug 19 12:59:10 2013 -0700
     8.2 +++ b/core/logic/thread/ThreadWorker.cpp	Mon Aug 19 20:58:02 2013 -0700
     8.3 @@ -33,10 +33,6 @@
     8.4  
     8.5  ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks) : BaseWorker(hooks),
     8.6  	m_Threader(NULL),
     8.7 -	m_QueueLock(NULL),
     8.8 -	m_StateLock(NULL),
     8.9 -	m_PauseSignal(NULL),
    8.10 -	m_AddSignal(NULL),
    8.11  	me(NULL),
    8.12  	m_think_time(DEFAULT_THINK_TIME_MS)
    8.13  {
    8.14 @@ -46,32 +42,19 @@
    8.15  ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime) : 
    8.16  	BaseWorker(hooks),
    8.17  	m_Threader(pThreader),
    8.18 -	m_QueueLock(NULL),
    8.19 -	m_StateLock(NULL),
    8.20 -	m_PauseSignal(NULL),
    8.21 -	m_AddSignal(NULL),
    8.22  	me(NULL),
    8.23  	m_think_time(thinktime)
    8.24  {
    8.25 -	if (m_Threader)
    8.26 -	{
    8.27 -		m_state = Worker_Stopped;
    8.28 -	} else {
    8.29 -		m_state = Worker_Invalid;
    8.30 -	}
    8.31 +	m_state = m_Threader ? Worker_Stopped : Worker_Invalid;
    8.32  }
    8.33  
    8.34  ThreadWorker::~ThreadWorker()
    8.35  {
    8.36  	if (m_state != Worker_Stopped || m_state != Worker_Invalid)
    8.37 -	{
    8.38  		Stop(true);
    8.39 -	}
    8.40 -
    8.41 +	
    8.42  	if (m_ThreadQueue.size())
    8.43 -	{
    8.44  		Flush(true);
    8.45 -	}
    8.46  }
    8.47  
    8.48  void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel)
    8.49 @@ -82,131 +65,88 @@
    8.50  
    8.51  void ThreadWorker::RunThread(IThreadHandle *pHandle)
    8.52  {
    8.53 -	WorkerState this_state = Worker_Running;
    8.54 -	size_t num;
    8.55 +	if (m_pHooks)
    8.56 +		m_pHooks->OnWorkerStart(this);
    8.57  
    8.58 -	if (m_pHooks)
    8.59 -	{
    8.60 -		m_pHooks->OnWorkerStart(this);
    8.61 -	}
    8.62 -    
    8.63 +	ke::AutoLock lock(&monitor_);
    8.64 +
    8.65  	while (true)
    8.66  	{
    8.67 -		/**
    8.68 -		 * Check number of items in the queue
    8.69 -		 */
    8.70 -		m_StateLock->Lock();
    8.71 -		this_state = m_state;
    8.72 -		m_StateLock->Unlock();
    8.73 -		if (this_state != Worker_Stopped)
    8.74 +		if (m_state == Worker_Paused)
    8.75  		{
    8.76 -			m_QueueLock->Lock();
    8.77 -			num = m_ThreadQueue.size();
    8.78 -			if (!num)
    8.79 -			{
    8.80 -				/** 
    8.81 -				 * if none, wait for an item
    8.82 -				 */
    8.83 -				m_Waiting = true;
    8.84 -				m_QueueLock->Unlock();
    8.85 -				/* first check if we should end again */
    8.86 -				if (this_state == Worker_Stopped)
    8.87 -				{
    8.88 -					break;
    8.89 -				}
    8.90 -				m_AddSignal->Wait();
    8.91 -				m_Waiting = false;
    8.92 -			} else {
    8.93 -				m_QueueLock->Unlock();
    8.94 -			}
    8.95 +			// Wait until we're told to wake up.
    8.96 +			monitor_.Wait();
    8.97 +			continue;
    8.98  		}
    8.99 -		m_StateLock->Lock();
   8.100 -		this_state = m_state;
   8.101 -		m_StateLock->Unlock();
   8.102 -		if (this_state != Worker_Running)
   8.103 +
   8.104 +		if (m_state == Worker_Stopped)
   8.105  		{
   8.106 -			if (this_state == Worker_Paused || this_state == Worker_Stopped)
   8.107 +			// We've been told to stop entirely. If we've also been told to
   8.108 +			// flush the queue, do that now.
   8.109 +			while (!m_ThreadQueue.empty())
   8.110  			{
   8.111 -				//wait until the lock is cleared.
   8.112 -				if (this_state == Worker_Paused)
   8.113 -				{
   8.114 -					m_PauseSignal->Wait();
   8.115 -				}
   8.116 -				if (this_state == Worker_Stopped)
   8.117 -				{
   8.118 -					//if we're supposed to flush cleanrly, 
   8.119 -					// run all of the remaining frames first.
   8.120 -					if (!m_FlushType)
   8.121 -					{
   8.122 -						while (m_ThreadQueue.size())
   8.123 -						{
   8.124 -							RunFrame();
   8.125 -						}
   8.126 -					}
   8.127 -					break;
   8.128 -				}
   8.129 +				// Release the lock since PopThreadFromQueue() will re-acquire it. The
   8.130 +				// main thread is blocking anyway.
   8.131 +				ke::AutoUnlock unlock(&monitor_);
   8.132 +				RunFrame();
   8.133  			}
   8.134 +			assert(m_state == Worker_Stopped);
   8.135 +			return;
   8.136  		}
   8.137 -		/**
   8.138 -		 * Run the frame.
   8.139 -		 */
   8.140 -		RunFrame();
   8.141 +
   8.142 +		assert(m_state == Worker_Running);
   8.143 +
   8.144 +		// Process one frame.
   8.145 +		WorkerState oldstate = m_state;
   8.146 +		{
   8.147 +			ke::AutoUnlock unlock(&monitor_);
   8.148 +			RunFrame();
   8.149 +		}
   8.150  
   8.151 -		/**
   8.152 -		 * wait in between threads if specified
   8.153 -		 */
   8.154 -		if (m_think_time)
   8.155 -		{
   8.156 -			m_Threader->ThreadSleep(m_think_time);
   8.157 -		}
   8.158 +		// If the state changed, loop back and process the new state.
   8.159 +		if (m_state != oldstate)
   8.160 +			continue;
   8.161 +		
   8.162 +		// If the thread queue is now empty, wait for a signal. Otherwise, if
   8.163 +		// we're on a delay, wait for either a notification or a timeout to
   8.164 +		// process the next item. If the queue has items and we don't have a
   8.165 +		// delay, then we just loop around and keep processing.
   8.166 +		if (m_ThreadQueue.empty())
   8.167 +			monitor_.Wait();
   8.168 +		else if (m_think_time)
   8.169 +			monitor_.Wait(m_think_time);
   8.170  	}
   8.171  
   8.172 -	if (m_pHooks)
   8.173  	{
   8.174 -		m_pHooks->OnWorkerStop(this);
   8.175 +		ke::AutoUnlock unlock(&monitor_);
   8.176 +		if (m_pHooks)
   8.177 +			m_pHooks->OnWorkerStop(this);
   8.178  	}
   8.179  }
   8.180  
   8.181  SWThreadHandle *ThreadWorker::PopThreadFromQueue()
   8.182  {
   8.183 -	if (m_state <= Worker_Stopped && !m_QueueLock)
   8.184 -	{
   8.185 +	ke::AutoLock lock(&monitor_);
   8.186 +	if (m_state <= Worker_Stopped)
   8.187  		return NULL;
   8.188 -	}
   8.189  
   8.190 -	SWThreadHandle *swt;
   8.191 -	m_QueueLock->Lock();
   8.192 -	swt = BaseWorker::PopThreadFromQueue();
   8.193 -	m_QueueLock->Unlock();
   8.194 -
   8.195 -	return swt;
   8.196 +	return BaseWorker::PopThreadFromQueue();
   8.197  }
   8.198  
   8.199  void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
   8.200  {
   8.201 +	ke::AutoLock lock(&monitor_);
   8.202  	if (m_state <= Worker_Stopped)
   8.203 -	{
   8.204  		return;
   8.205 -	}
   8.206  
   8.207 -	m_QueueLock->Lock();
   8.208  	BaseWorker::AddThreadToQueue(pHandle);
   8.209 -	if (m_Waiting)
   8.210 -	{
   8.211 -		m_AddSignal->Signal();
   8.212 -	}
   8.213 -	m_QueueLock->Unlock();
   8.214 +	monitor_.Notify();
   8.215  }
   8.216  
   8.217  WorkerState ThreadWorker::GetStatus(unsigned int *threads)
   8.218  {
   8.219 -	WorkerState state;
   8.220 -
   8.221 -	m_StateLock->Lock();
   8.222 -	state = BaseWorker::GetStatus(threads);
   8.223 -	m_StateLock->Unlock();
   8.224 -
   8.225 -	return state;
   8.226 +	ke::AutoLock lock(&monitor_);
   8.227 +	return BaseWorker::GetStatus(threads);
   8.228  }
   8.229  
   8.230  void ThreadWorker::SetThinkTimePerFrame(unsigned int thinktime)
   8.231 @@ -216,56 +156,32 @@
   8.232  
   8.233  bool ThreadWorker::Start()
   8.234  {
   8.235 -	if (m_state == Worker_Invalid)
   8.236 -	{
   8.237 -		if (m_Threader == NULL)
   8.238 -		{
   8.239 -			return false;
   8.240 -		}
   8.241 -	} else if (m_state != Worker_Stopped) {
   8.242 +	if (m_state == Worker_Invalid && m_Threader == NULL)
   8.243  		return false;
   8.244 -	}
   8.245  
   8.246 -	m_Waiting = false;
   8.247 -	m_QueueLock = m_Threader->MakeMutex();
   8.248 -	m_StateLock = m_Threader->MakeMutex();
   8.249 -	m_PauseSignal = m_Threader->MakeEventSignal();
   8.250 -	m_AddSignal = m_Threader->MakeEventSignal();
   8.251 +	if (m_state != Worker_Stopped)
   8.252 +		return false;
   8.253 +
   8.254  	m_state = Worker_Running;
   8.255 +
   8.256  	ThreadParams pt;
   8.257  	pt.flags = Thread_Default;
   8.258  	pt.prio = ThreadPrio_Normal;
   8.259  	me = m_Threader->MakeThread(this, &pt);
   8.260 -
   8.261  	return true;
   8.262  }
   8.263  
   8.264  bool ThreadWorker::Stop(bool flush_cancel)
   8.265  {
   8.266 -	if (m_state == Worker_Invalid || m_state == Worker_Stopped)
   8.267 +	// Change the state to signal a stop, and then trigger a notify.
   8.268  	{
   8.269 -		return false;
   8.270 -	}
   8.271 -
   8.272 -	WorkerState oldstate;
   8.273 +		ke::AutoLock lock(&monitor_);
   8.274 +		if (m_state == Worker_Invalid || m_state == Worker_Stopped)
   8.275 +			return false;
   8.276  
   8.277 -	//set new state
   8.278 -	m_StateLock->Lock();
   8.279 -	oldstate = m_state;
   8.280 -	m_state = Worker_Stopped;
   8.281 -	m_FlushType = flush_cancel;
   8.282 -	m_StateLock->Unlock();
   8.283 -
   8.284 -	if (oldstate == Worker_Paused)
   8.285 -	{
   8.286 -		Unpause();
   8.287 -	} else {
   8.288 -		m_QueueLock->Lock();
   8.289 -		if (m_Waiting)
   8.290 -		{
   8.291 -			m_AddSignal->Signal();
   8.292 -		}
   8.293 -		m_QueueLock->Unlock();
   8.294 +		m_state = Worker_Stopped;
   8.295 +		m_FlushType = flush_cancel;
   8.296 +		monitor_.Notify();
   8.297  	}
   8.298  
   8.299  	me->WaitForThread();
   8.300 @@ -274,33 +190,18 @@
   8.301  	//flush all remaining events
   8.302  	Flush(true);
   8.303  
   8.304 -	//free mutex locks
   8.305 -	m_QueueLock->DestroyThis();
   8.306 -	m_StateLock->DestroyThis();
   8.307 -	m_PauseSignal->DestroyThis();
   8.308 -	m_AddSignal->DestroyThis();
   8.309 -
   8.310 -	//invalidizzle
   8.311 -	m_QueueLock = NULL;
   8.312 -	m_StateLock = NULL;
   8.313 -	m_PauseSignal = NULL;
   8.314 -	m_AddSignal = NULL;
   8.315  	me = NULL;
   8.316 -
   8.317  	return true;
   8.318  }
   8.319  
   8.320  bool ThreadWorker::Pause()
   8.321  {
   8.322  	if (m_state != Worker_Running)
   8.323 -	{
   8.324  		return false;
   8.325 -	}
   8.326  
   8.327 -	m_StateLock->Lock();
   8.328 +	ke::AutoLock lock(&monitor_);
   8.329  	m_state = Worker_Paused;
   8.330 -	m_StateLock->Unlock();
   8.331 -
   8.332 +	monitor_.Notify();
   8.333  	return true;
   8.334  }
   8.335  
   8.336 @@ -308,18 +209,10 @@
   8.337  bool ThreadWorker::Unpause()
   8.338  {
   8.339  	if (m_state != Worker_Paused)
   8.340 -	{
   8.341  		return false;
   8.342 -	}
   8.343  
   8.344 -	m_StateLock->Lock();
   8.345 +	ke::AutoLock lock(&monitor_);
   8.346  	m_state = Worker_Running;
   8.347 -	m_StateLock->Unlock();
   8.348 -	m_PauseSignal->Signal();
   8.349 -	if (m_Waiting)
   8.350 -	{
   8.351 -		m_AddSignal->Signal();
   8.352 -	}
   8.353 -
   8.354 +	monitor_.Notify();
   8.355  	return true;
   8.356  }
     9.1 --- a/core/logic/thread/ThreadWorker.h	Mon Aug 19 12:59:10 2013 -0700
     9.2 +++ b/core/logic/thread/ThreadWorker.h	Mon Aug 19 20:58:02 2013 -0700
     9.3 @@ -60,14 +60,10 @@
     9.4  	virtual SWThreadHandle *PopThreadFromQueue();
     9.5  protected:
     9.6  	IThreader *m_Threader;
     9.7 -	IMutex *m_QueueLock;
     9.8 -	IMutex *m_StateLock;
     9.9 -	IEventSignal *m_PauseSignal;
    9.10 -	IEventSignal *m_AddSignal;
    9.11  	IThreadHandle *me;
    9.12  	unsigned int m_think_time;
    9.13 -	volatile bool m_Waiting;
    9.14 -	volatile bool m_FlushType;
    9.15 +	bool m_FlushType;
    9.16 +	ke::ConditionVariable monitor_;
    9.17  };
    9.18  
    9.19  #endif //_INCLUDE_SOURCEMOD_THREADWORKER_H
    10.1 --- a/core/logic/thread/WinThreads.cpp	Mon Aug 19 12:59:10 2013 -0700
    10.2 +++ b/core/logic/thread/WinThreads.cpp	Mon Aug 19 20:58:02 2013 -0700
    10.3 @@ -1,5 +1,5 @@
    10.4  /**
    10.5 - * vim: set ts=4 :
    10.6 + * vim: set ts=4 sw=4 tw=99 noet:
    10.7   * =============================================================================
    10.8   * SourceMod
    10.9   * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
   10.10 @@ -55,9 +55,7 @@
   10.11  
   10.12  IMutex *WinThreader::MakeMutex()
   10.13  {
   10.14 -	WinMutex *pMutex = new WinMutex();
   10.15 -
   10.16 -	return pMutex;
   10.17 +	return new CompatMutex();
   10.18  }
   10.19  
   10.20  IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
   10.21 @@ -80,24 +78,20 @@
   10.22  	MakeThread(pThread, &defparams);
   10.23  }
   10.24  
   10.25 -DWORD WINAPI Win32_ThreadGate(LPVOID param)
   10.26 +void WinThreader::ThreadHandle::Run()
   10.27  {
   10.28 -	WinThreader::ThreadHandle *pHandle = 
   10.29 -		reinterpret_cast<WinThreader::ThreadHandle *>(param);
   10.30 -
   10.31 -	pHandle->m_run->RunThread(pHandle);
   10.32 -
   10.33 -	ThreadParams params;
   10.34 -	EnterCriticalSection(&pHandle->m_crit);
   10.35 -	pHandle->m_state = Thread_Done;
   10.36 -	pHandle->GetParams(&params);
   10.37 -	LeaveCriticalSection(&pHandle->m_crit);
   10.38 -
   10.39 -	pHandle->m_run->OnTerminate(pHandle, false);
   10.40 -	if (params.flags & Thread_AutoRelease)
   10.41 -		delete pHandle;
   10.42 -
   10.43 -	return 0;
   10.44 +	// Wait for an unpause if necessary.
   10.45 +	{
   10.46 +		ke::AutoLock lock(&suspend_);
   10.47 +		if (m_state == Thread_Paused)
   10.48 +			suspend_.Wait();
   10.49 +	}
   10.50 +	
   10.51 +	m_run->RunThread(this);
   10.52 +	m_state = Thread_Done;
   10.53 +	m_run->OnTerminate(this, false);
   10.54 +	if (m_params.flags & Thread_AutoRelease)
   10.55 +		delete this;
   10.56  }
   10.57  
   10.58  void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
   10.59 @@ -112,119 +106,52 @@
   10.60  	if (params == NULL)
   10.61  		params = &g_defparams;
   10.62  
   10.63 -	WinThreader::ThreadHandle *pHandle = 
   10.64 -		new WinThreader::ThreadHandle(this, NULL, pThread, params);
   10.65 +	ke::AutoPtr<ThreadHandle> pHandle(new ThreadHandle(this, pThread, params));
   10.66  
   10.67 -	DWORD tid;
   10.68 -	pHandle->m_thread = 
   10.69 -		CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
   10.70 -
   10.71 -	if (!pHandle->m_thread)
   10.72 -	{
   10.73 -		delete pHandle;
   10.74 +	pHandle->m_thread = new ke::Thread(pHandle, "SourceMod");
   10.75 +	if (!pHandle->m_thread->Succeeded())
   10.76  		return NULL;
   10.77 -	}
   10.78  
   10.79  	if (pHandle->m_params.prio != ThreadPrio_Normal)
   10.80 -	{
   10.81  		pHandle->SetPriority(pHandle->m_params.prio);
   10.82 -	}
   10.83  
   10.84 -	if (!(pHandle->m_params.flags & Thread_CreateSuspended))
   10.85 -	{
   10.86 +	if (!(params->flags & Thread_CreateSuspended))
   10.87  		pHandle->Unpause();
   10.88 -	}
   10.89  
   10.90 -	return pHandle;
   10.91 +	return pHandle.take();
   10.92  }
   10.93  
   10.94  IEventSignal *WinThreader::MakeEventSignal()
   10.95  {
   10.96 -	HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
   10.97 -
   10.98 -	if (!event)
   10.99 -		return NULL;
  10.100 -
  10.101 -	WinEvent *pEvent = new WinEvent(event);
  10.102 -
  10.103 -	return pEvent;
  10.104 -}
  10.105 -
  10.106 -/*****************
  10.107 - **** Mutexes ****
  10.108 - *****************/
  10.109 -
  10.110 -WinThreader::WinMutex::WinMutex()
  10.111 -{
  10.112 -	InitializeCriticalSection(&m_crit);
  10.113 -}
  10.114 -
  10.115 -WinThreader::WinMutex::~WinMutex()
  10.116 -{
  10.117 -	DeleteCriticalSection(&m_crit);
  10.118 -}
  10.119 -
  10.120 -bool WinThreader::WinMutex::TryLock()
  10.121 -{
  10.122 -	return (TryEnterCriticalSection(&m_crit) != FALSE);
  10.123 -}
  10.124 -
  10.125 -void WinThreader::WinMutex::Lock()
  10.126 -{
  10.127 -	EnterCriticalSection(&m_crit);
  10.128 -}
  10.129 -
  10.130 -void WinThreader::WinMutex::Unlock()
  10.131 -{
  10.132 -	LeaveCriticalSection(&m_crit);
  10.133 -}
  10.134 -
  10.135 -void WinThreader::WinMutex::DestroyThis()
  10.136 -{
  10.137 -	delete this;
  10.138 +	return new CompatCondVar();
  10.139  }
  10.140  
  10.141  /******************
  10.142   * Thread Handles *
  10.143   ******************/
  10.144  
  10.145 -WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) : 
  10.146 -	m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
  10.147 +WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) : 
  10.148 +	m_parent(parent), m_run(run), m_params(*params),
  10.149  	m_state(Thread_Paused)
  10.150  {
  10.151 -	InitializeCriticalSection(&m_crit);
  10.152  }
  10.153  
  10.154  WinThreader::ThreadHandle::~ThreadHandle()
  10.155  {
  10.156 -	if (m_thread)
  10.157 -	{
  10.158 -		CloseHandle(m_thread);
  10.159 -		m_thread = NULL;
  10.160 -	}
  10.161 -	DeleteCriticalSection(&m_crit);
  10.162  }
  10.163  
  10.164  bool WinThreader::ThreadHandle::WaitForThread()
  10.165  {
  10.166 -	if (m_thread == NULL)
  10.167 +	if (!m_thread)
  10.168  		return false;
  10.169  
  10.170 -	if (WaitForSingleObject(m_thread, INFINITE) != 0)
  10.171 -		return false;
  10.172 -
  10.173 +	m_thread->Join();
  10.174  	return true;
  10.175  }
  10.176  
  10.177  ThreadState WinThreader::ThreadHandle::GetState()
  10.178  {
  10.179 -	ThreadState state;
  10.180 -
  10.181 -	EnterCriticalSection(&m_crit);
  10.182 -	state = m_state;
  10.183 -	LeaveCriticalSection(&m_crit);
  10.184 -
  10.185 -	return state;
  10.186 +	return m_state;
  10.187  }
  10.188  
  10.189  IThreadCreator *WinThreader::ThreadHandle::Parent()
  10.190 @@ -255,21 +182,18 @@
  10.191  
  10.192  bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
  10.193  {
  10.194 -	if (!m_thread)
  10.195 -		return false;
  10.196 -
  10.197  	BOOL res = FALSE;
  10.198  
  10.199  	if (prio >= ThreadPrio_Maximum)
  10.200 -		res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
  10.201 +		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_HIGHEST);
  10.202  	else if (prio <= ThreadPrio_Minimum)
  10.203 -		res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
  10.204 +		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_LOWEST);
  10.205  	else if (prio == ThreadPrio_Normal)
  10.206 -		res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
  10.207 +		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_NORMAL);
  10.208  	else if (prio == ThreadPrio_High)
  10.209 -		res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
  10.210 +		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_ABOVE_NORMAL);
  10.211  	else if (prio == ThreadPrio_Low)
  10.212 -		res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
  10.213 +		res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_BELOW_NORMAL);
  10.214  
  10.215  	m_params.prio = prio;
  10.216  
  10.217 @@ -278,43 +202,11 @@
  10.218  
  10.219  bool WinThreader::ThreadHandle::Unpause()
  10.220  {
  10.221 -	if (!m_thread)
  10.222 -		return false;
  10.223 -
  10.224  	if (m_state != Thread_Paused)
  10.225  		return false;
  10.226  
  10.227 +	ke::AutoLock lock(&suspend_);
  10.228  	m_state = Thread_Running;
  10.229 -
  10.230 -	if (ResumeThread(m_thread) == -1)
  10.231 -	{
  10.232 -		m_state = Thread_Paused;
  10.233 -		return false;
  10.234 -	}
  10.235 -
  10.236 +	suspend_.Notify();
  10.237  	return true;
  10.238  }
  10.239 -
  10.240 -/*****************
  10.241 - * EVENT SIGNALS *
  10.242 - *****************/
  10.243 -
  10.244 -WinThreader::WinEvent::~WinEvent()
  10.245 -{
  10.246 -	CloseHandle(m_event);
  10.247 -}
  10.248 -
  10.249 -void WinThreader::WinEvent::Wait()
  10.250 -{
  10.251 -	WaitForSingleObject(m_event, INFINITE);
  10.252 -}
  10.253 -
  10.254 -void WinThreader::WinEvent::Signal()
  10.255 -{
  10.256 -	SetEvent(m_event);
  10.257 -}
  10.258 -
  10.259 -void WinThreader::WinEvent::DestroyThis()
  10.260 -{
  10.261 -	delete this;
  10.262 -}
    11.1 --- a/core/logic/thread/WinThreads.h	Mon Aug 19 12:59:10 2013 -0700
    11.2 +++ b/core/logic/thread/WinThreads.h	Mon Aug 19 20:58:02 2013 -0700
    11.3 @@ -32,22 +32,22 @@
    11.4  #ifndef _INCLUDE_WINTHREADS_H_
    11.5  #define _INCLUDE_WINTHREADS_H_
    11.6  
    11.7 +#include <ke_thread_utils.h>
    11.8 +#include <ke_utility.h>
    11.9  #include <windows.h>
   11.10  #include "IThreader.h"
   11.11  
   11.12  using namespace SourceMod;
   11.13  
   11.14 -DWORD WINAPI Win32_ThreadGate(LPVOID param);
   11.15 -
   11.16  class WinThreader : public IThreader
   11.17  {
   11.18  public:
   11.19 -	class ThreadHandle : public IThreadHandle
   11.20 +	class ThreadHandle : public IThreadHandle, public ke::IRunnable
   11.21  	{
   11.22  		friend class WinThreader;
   11.23  		friend DWORD WINAPI Win32_ThreadGate(LPVOID param);
   11.24  	public:
   11.25 -		ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params);
   11.26 +		ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params);
   11.27  		virtual ~ThreadHandle();
   11.28  	public:
   11.29  		virtual bool WaitForThread();
   11.30 @@ -58,41 +58,16 @@
   11.31  		virtual bool SetPriority(ThreadPriority prio);
   11.32  		virtual ThreadState GetState();
   11.33  		virtual bool Unpause();
   11.34 +		virtual void Run();
   11.35  	protected:
   11.36  		IThreader *m_parent;		//Parent handle
   11.37 -		HANDLE m_thread;			//Windows HANDLE	
   11.38 +		ke::AutoPtr<ke::Thread> m_thread;
   11.39  		ThreadParams m_params;		//Current Parameters
   11.40 -		IThread *m_run;	//Runnable context
   11.41 +		IThread *m_run;				//Runnable context
   11.42  		ThreadState m_state;		//internal state
   11.43 -		CRITICAL_SECTION m_crit;
   11.44 +		ke::ConditionVariable suspend_;
   11.45  	};
   11.46 -	class WinMutex : public IMutex
   11.47 -	{
   11.48 -	public:
   11.49 -		WinMutex();
   11.50 -		virtual ~WinMutex();
   11.51 -	public:
   11.52 -		virtual bool TryLock();
   11.53 -		virtual void Lock();
   11.54 -		virtual void Unlock();
   11.55 -		virtual void DestroyThis();
   11.56 -	protected:
   11.57 -		CRITICAL_SECTION m_crit;
   11.58 -	};
   11.59 -	class WinEvent : public IEventSignal
   11.60 -	{
   11.61 -	public:
   11.62 -		WinEvent(HANDLE event) : m_event(event)
   11.63 -		{
   11.64 -		};
   11.65 -		virtual ~WinEvent();
   11.66 -	public:
   11.67 -		virtual void Wait();
   11.68 -		virtual void Signal();
   11.69 -		virtual void DestroyThis();
   11.70 -	public:
   11.71 -		HANDLE m_event;
   11.72 -	};
   11.73 +
   11.74  public:
   11.75  	IMutex *MakeMutex();
   11.76  	void MakeThread(IThread *pThread);
    12.1 --- a/public/IThreader.h	Mon Aug 19 12:59:10 2013 -0700
    12.2 +++ b/public/IThreader.h	Mon Aug 19 20:58:02 2013 -0700
    12.3 @@ -38,6 +38,7 @@
    12.4   */
    12.5  
    12.6  #include <IShareSys.h>
    12.7 +#include <ke_thread_utils.h>
    12.8  
    12.9  #define SMINTERFACE_THREADER_NAME		"IThreader"
   12.10  #define SMINTERFACE_THREADER_VERSION	3
    13.1 --- a/public/sourcepawn/ke_thread_utils.h	Mon Aug 19 12:59:10 2013 -0700
    13.2 +++ b/public/sourcepawn/ke_thread_utils.h	Mon Aug 19 20:58:02 2013 -0700
    13.3 @@ -20,6 +20,7 @@
    13.4  #include <assert.h>
    13.5  #if defined(_MSC_VER)
    13.6  # include <windows.h>
    13.7 +# include <WinBase.h>
    13.8  #else
    13.9  # include <pthread.h>
   13.10  #endif
   13.11 @@ -56,8 +57,13 @@
   13.12  // When Wait() returns, the lock is automatically re-acquired. This operation
   13.13  // is NOT atomic. In between waking up and re-acquiring the lock, another
   13.14  // thread may steal the lock and issue another event. Applications must
   13.15 -// account for this. For example, a message pump should check that there are no
   13.16 -// messages left to process before blocking again.
   13.17 +// account for this. For example, a message pump should check that there are
   13.18 +// no messages left to process before blocking again.
   13.19 +//
   13.20 +// Likewise, it is also not defined whether a Signal() will have any effect
   13.21 +// while a thread is not waiting on the monitor. This is yet another reason
   13.22 +// the above paragraph is so important - applications should, under a lock of
   13.23 +// the condition variable - check for state changes before waiting.
   13.24  //
   13.25  // -- Threads --
   13.26  //
   13.27 @@ -72,13 +78,13 @@
   13.28  
   13.29  namespace ke {
   13.30  
   13.31 -// Abstraction for accessing the current thread.
   13.32 +// Abstraction for getting a unique thread identifier. Debug-only.
   13.33  #if defined(_MSC_VER)
   13.34 -typedef HANDLE ThreadId;
   13.35 +typedef DWORD ThreadId;
   13.36  
   13.37  static inline ThreadId GetCurrentThreadId()
   13.38  {
   13.39 -  return GetCurrentThread();
   13.40 +  return ::GetCurrentThreadId();
   13.41  }
   13.42  #else
   13.43  typedef pthread_t ThreadId;
   13.44 @@ -238,4 +244,3 @@
   13.45  #endif
   13.46  
   13.47  #endif // _include_sourcepawn_threads_
   13.48 -
    14.1 --- a/public/sourcepawn/ke_thread_windows.h	Mon Aug 19 12:59:10 2013 -0700
    14.2 +++ b/public/sourcepawn/ke_thread_windows.h	Mon Aug 19 20:58:02 2013 -0700
    14.3 @@ -120,6 +120,10 @@
    14.4      WaitForSingleObject(thread_, INFINITE);
    14.5    }
    14.6  
    14.7 +  HANDLE handle() const {
    14.8 +	  return thread_;
    14.9 +  }
   14.10 +
   14.11   private:
   14.12    static DWORD WINAPI Main(LPVOID arg) {
   14.13      ((IRunnable *)arg)->Run();
    15.1 --- a/public/sourcepawn/ke_utility.h	Mon Aug 19 12:59:10 2013 -0700
    15.2 +++ b/public/sourcepawn/ke_utility.h	Mon Aug 19 20:58:02 2013 -0700
    15.3 @@ -22,6 +22,7 @@
    15.4  #include <assert.h>
    15.5  #include <stddef.h>
    15.6  #include <stdlib.h>
    15.7 +#include <stdint.h>
    15.8  #if defined(_MSC_VER)
    15.9  # include <intrin.h>
   15.10  #endif
   15.11 @@ -56,6 +57,8 @@
   15.12      return saved;
   15.13  }
   15.14  
   15.15 +// Wrapper that automatically deletes its contents. The pointer can be taken
   15.16 +// to avoid destruction.
   15.17  template <typename T>
   15.18  class AutoPtr
   15.19  {
   15.20 @@ -89,6 +92,9 @@
   15.21          delete t_;
   15.22          t_ = t;
   15.23      }
   15.24 +    bool operator !() const {
   15.25 +        return !t_;
   15.26 +    }
   15.27  };
   15.28  
   15.29  // Bob Jenkin's one-at-a-time hash function[1].