diff --git a/core/thread/BaseWorker.cpp b/core/thread/BaseWorker.cpp index 0179b788..fc10c0bd 100644 --- a/core/thread/BaseWorker.cpp +++ b/core/thread/BaseWorker.cpp @@ -14,9 +14,10 @@ #include "BaseWorker.h" -BaseWorker::BaseWorker() : +BaseWorker::BaseWorker(IThreadWorkerCallbacks *hooks) : m_perFrame(SM_DEFAULT_THREADS_PER_FRAME), - m_state(Worker_Stopped) + m_state(Worker_Stopped), + m_pHooks(hooks) { } @@ -129,14 +130,18 @@ unsigned int BaseWorker::RunFrame() while (done < max) { if ((swt=PopThreadFromQueue()) == NULL) + { break; + } pThread = swt->pThread; swt->m_state = Thread_Running; pThread->RunThread(swt); swt->m_state = Thread_Done; pThread->OnTerminate(swt, false); if (swt->m_params.flags & Thread_AutoRelease) + { delete swt; + } done++; } @@ -157,30 +162,46 @@ bool BaseWorker::Start() m_state = Worker_Running; + if (m_pHooks) + { + m_pHooks->OnWorkerStart(this); + } + return true; } bool BaseWorker::Stop(bool flush_cancel) { if (m_state == Worker_Invalid || m_state == Worker_Stopped) + { return false; + } if (m_state == Worker_Paused) { if (!Unpause()) + { return false; + } } m_state = Worker_Stopped; Flush(flush_cancel); + if (m_pHooks) + { + m_pHooks->OnWorkerStop(this); + } + return true; } bool BaseWorker::Pause() { if (m_state != Worker_Running) + { return false; + } m_state = Worker_Paused; @@ -191,7 +212,9 @@ bool BaseWorker::Pause() bool BaseWorker::Unpause() { if (m_state != Worker_Paused) + { return false; + } m_state = Worker_Running; diff --git a/core/thread/BaseWorker.h b/core/thread/BaseWorker.h index 20df57d2..9b14d6aa 100644 --- a/core/thread/BaseWorker.h +++ b/core/thread/BaseWorker.h @@ -54,7 +54,7 @@ private: class BaseWorker : public IThreadWorker { public: - BaseWorker(); + BaseWorker(IThreadWorkerCallbacks *hooks); virtual ~BaseWorker(); public: //IWorker virtual unsigned int RunFrame(); @@ -81,6 +81,7 @@ protected: SourceHook::List m_ThreadQueue; unsigned int m_perFrame; volatile WorkerState m_state; + IThreadWorkerCallbacks *m_pHooks; }; #endif //_INCLUDE_SOURCEMOD_BASEWORKER_H diff --git a/core/thread/PosixThreads.cpp b/core/thread/PosixThreads.cpp index b2a30aca..83c5ffe0 100644 --- a/core/thread/PosixThreads.cpp +++ b/core/thread/PosixThreads.cpp @@ -25,13 +25,13 @@ #include "PosixThreads.h" #include "ThreadWorker.h" -IThreadWorker *PosixThreader::MakeWorker(bool threaded) +IThreadWorker *PosixThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) { if (threaded) { - return new ThreadWorker(this, DEFAULT_THINK_TIME_MS); + return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS); } else { - return new BaseWorker(); + return new BaseWorker(hooks); } } diff --git a/core/thread/PosixThreads.h b/core/thread/PosixThreads.h index efa4248a..803730ef 100644 --- a/core/thread/PosixThreads.h +++ b/core/thread/PosixThreads.h @@ -95,7 +95,7 @@ public: void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min); void ThreadSleep(unsigned int ms); IEventSignal *MakeEventSignal(); - IThreadWorker *MakeWorker(bool threaded); + IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded); void DestroyWorker(IThreadWorker *pWorker); }; diff --git a/core/thread/ThreadWorker.cpp b/core/thread/ThreadWorker.cpp index 47ec9a00..f6e917bb 100644 --- a/core/thread/ThreadWorker.cpp +++ b/core/thread/ThreadWorker.cpp @@ -14,7 +14,7 @@ #include "ThreadWorker.h" -ThreadWorker::ThreadWorker() : +ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks) : BaseWorker(hooks), m_Threader(NULL), m_QueueLock(NULL), m_StateLock(NULL), @@ -26,7 +26,8 @@ ThreadWorker::ThreadWorker() : m_state = Worker_Invalid; } -ThreadWorker::ThreadWorker(IThreader *pThreader, unsigned int thinktime) : +ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime) : + BaseWorker(hooks), m_Threader(pThreader), m_QueueLock(NULL), m_StateLock(NULL), @@ -46,10 +47,14 @@ ThreadWorker::ThreadWorker(IThreader *pThreader, unsigned int thinktime) : ThreadWorker::~ThreadWorker() { if (m_state != Worker_Stopped || m_state != Worker_Invalid) + { Stop(true); + } if (m_ThreadQueue.size()) + { Flush(true); + } } void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel) @@ -62,6 +67,11 @@ void ThreadWorker::RunThread(IThreadHandle *pHandle) { WorkerState this_state = Worker_Running; size_t num; + + if (m_pHooks) + { + m_pHooks->OnWorkerStart(this); + } while (true) { @@ -112,7 +122,9 @@ void ThreadWorker::RunThread(IThreadHandle *pHandle) if (!m_FlushType) { while (m_ThreadQueue.size()) + { RunFrame(); + } } break; } @@ -127,14 +139,23 @@ void ThreadWorker::RunThread(IThreadHandle *pHandle) * wait in between threads if specified */ if (m_think_time) + { m_Threader->ThreadSleep(m_think_time); + } + } + + if (m_pHooks) + { + m_pHooks->OnWorkerStop(this); } } SWThreadHandle *ThreadWorker::PopThreadFromQueue() { if (m_state <= Worker_Stopped && !m_QueueLock) + { return NULL; + } SWThreadHandle *swt; m_QueueLock->Lock(); @@ -147,7 +168,9 @@ SWThreadHandle *ThreadWorker::PopThreadFromQueue() void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle) { if (m_state <= Worker_Stopped) + { return; + } m_QueueLock->Lock(); BaseWorker::AddThreadToQueue(pHandle); @@ -174,7 +197,9 @@ bool ThreadWorker::Start() if (m_state == Worker_Invalid) { if (m_Threader == NULL) + { return false; + } } else if (m_state != Worker_Stopped) { return false; } @@ -196,7 +221,9 @@ bool ThreadWorker::Start() bool ThreadWorker::Stop(bool flush_cancel) { if (m_state == Worker_Invalid || m_state == Worker_Stopped) + { return false; + } WorkerState oldstate; @@ -244,7 +271,9 @@ bool ThreadWorker::Stop(bool flush_cancel) bool ThreadWorker::Pause() { if (m_state != Worker_Running) + { return false; + } m_StateLock->Lock(); m_state = Worker_Paused; @@ -257,7 +286,9 @@ bool ThreadWorker::Pause() bool ThreadWorker::Unpause() { if (m_state != Worker_Paused) + { return false; + } m_StateLock->Lock(); m_state = Worker_Running; diff --git a/core/thread/ThreadWorker.h b/core/thread/ThreadWorker.h index e1a99634..910273ed 100644 --- a/core/thread/ThreadWorker.h +++ b/core/thread/ThreadWorker.h @@ -22,8 +22,8 @@ class ThreadWorker : public BaseWorker, public IThread { public: - ThreadWorker(); - ThreadWorker(IThreader *pThreader, unsigned int thinktime=DEFAULT_THINK_TIME_MS); + ThreadWorker(IThreadWorkerCallbacks *hooks); + ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime=DEFAULT_THINK_TIME_MS); virtual ~ThreadWorker(); public: //IThread virtual void OnTerminate(IThreadHandle *pHandle, bool cancel); diff --git a/core/thread/WinThreads.cpp b/core/thread/WinThreads.cpp index 2180ed30..eb0d44a0 100644 --- a/core/thread/WinThreads.cpp +++ b/core/thread/WinThreads.cpp @@ -16,13 +16,13 @@ #include "WinThreads.h" #include "ThreadWorker.h" -IThreadWorker *WinThreader::MakeWorker(bool threaded) +IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) { if (threaded) { - return new ThreadWorker(this, DEFAULT_THINK_TIME_MS); + return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS); } else { - return new BaseWorker(); + return new BaseWorker(hooks); } } diff --git a/core/thread/WinThreads.h b/core/thread/WinThreads.h index 956ccf82..3b95ffc4 100644 --- a/core/thread/WinThreads.h +++ b/core/thread/WinThreads.h @@ -84,7 +84,7 @@ public: void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min); void ThreadSleep(unsigned int ms); IEventSignal *MakeEventSignal(); - IThreadWorker *MakeWorker(bool threaded); + IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded); void DestroyWorker(IThreadWorker *pWorker); }; diff --git a/public/IThreader.h b/public/IThreader.h index 369f8dfd..b33d84b9 100644 --- a/public/IThreader.h +++ b/public/IThreader.h @@ -27,7 +27,7 @@ #include #define SMINTERFACE_THREADER_NAME "IThreader" -#define SMINTERFACE_THREADER_VERSION 1 +#define SMINTERFACE_THREADER_VERSION 2 namespace SourceMod { @@ -351,6 +351,31 @@ namespace SourceMod virtual WorkerState GetStatus(unsigned int *numThreads) =0; }; + /** + * @brief Describes thread worker callbacks. + */ + class IThreadWorkerCallbacks + { + public: + /** + * @brief Called when the worker thread is initialized. + * + * @param pWorker Pointer to the worker. + */ + virtual void OnWorkerStart(IThreadWorker *pWorker) + { + } + + /** + * @brief Called when the worker thread is cleaning up. + * + * @param pWorker Pointer to the worker. + */ + virtual void OnWorkerStop(IThreadWorker *pWorker) + { + } + }; + /** * @brief Describes a threading system */ @@ -365,6 +390,14 @@ namespace SourceMod { return SMINTERFACE_THREADER_VERSION; } + virtual bool IsVersionCompatible(unsigned int version) + { + if (version < 2) + { + return false; + } + return SMInterface::IsVersionCompatible(version); + } public: /** * @brief Creates a mutex (mutual exclusion lock). @@ -390,11 +423,12 @@ namespace SourceMod /** * @brief Creates a thread worker. * + * @param hooks Optional pointer to callback interface. * @param threaded If true, the worker will be threaded. * If false, the worker will require manual frame execution. * @return A new IThreadWorker pointer (must be destroyed). */ - virtual IThreadWorker *MakeWorker(bool threaded) =0; + virtual IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) =0; /** * @brief Destroys an IThreadWorker pointer. diff --git a/public/sample_ext/sdk/smsdk_config.h b/public/sample_ext/sdk/smsdk_config.h index 47cf8928..2d563ab4 100644 --- a/public/sample_ext/sdk/smsdk_config.h +++ b/public/sample_ext/sdk/smsdk_config.h @@ -54,5 +54,6 @@ //#define SMEXT_ENABLE_MEMUTILS //#define SMEXT_ENABLE_GAMEHELPERS //#define SMEXT_ENABLE_TIMERSYS +//#define SMEXT_ENABLE_THREADER #endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/public/sample_ext/sdk/smsdk_ext.cpp b/public/sample_ext/sdk/smsdk_ext.cpp index 83046dcc..675f28b4 100644 --- a/public/sample_ext/sdk/smsdk_ext.cpp +++ b/public/sample_ext/sdk/smsdk_ext.cpp @@ -60,6 +60,9 @@ ITimerSystem *timersys = NULL; #if defined SMEXT_ENABLE_ADTFACTORY IADTFactory *adtfactory = NULL; #endif +#if defined SMEXT_ENABLE_THREADER +IThreader *threader = NULL; +#endif /** Exports the main interface */ PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() @@ -124,6 +127,9 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, #if defined SMEXT_ENABLE_ADTFACTORY SM_GET_IFACE(ADTFACTORY, adtfactory); #endif +#if defined SMEXT_ENABLE_THREADER + SM_GET_IFACE(THREADER, threader); +#endif if (SDK_OnLoad(error, maxlength, late)) { diff --git a/public/sample_ext/sdk/smsdk_ext.h b/public/sample_ext/sdk/smsdk_ext.h index ebb60277..757f4163 100644 --- a/public/sample_ext/sdk/smsdk_ext.h +++ b/public/sample_ext/sdk/smsdk_ext.h @@ -54,6 +54,9 @@ #if defined SMEXT_ENABLE_ADTFACTORY #include #endif +#if defined SMEXT_ENABLE_THREADER +#include +#endif #if defined SMEXT_CONF_METAMOD #include @@ -231,6 +234,9 @@ extern ITimerSystem *timersys; #if defined SMEXT_ENABLE_ADTFACTORY extern IADTFactory *adtfactory; #endif +#if defined SMEXT_ENABLE_THREADER +extern IThreader *threader; +#endif #if defined SMEXT_CONF_METAMOD PLUGIN_GLOBALVARS();