Rewrite IThreader implementation around new synchronization primitives (bug 5862, r=fyren).
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(¶ms);
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(¶ms);
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].