Pare down ThreadSupport and remove ancient thread code.
This patch removes almost all of the existing platform-specific ThreadSupport code, as well as code derived from it. It is now implemented on top of C++11 threads and is much simpler. This is the first inclusion of STL in SourceMod. Mac and Windows are allowed to dynamically link to their respective implementations. On Linux, libstdc++ is statically linked, except in the cases where it was already dynamically linked (csgo, blade). IEventSignal has been retained because sourcemod-curl-extension relies on it. As written, it is impossible to use as a condition variable, because the caller does not have access to the underlying mutex. There is no way to make this API safe or non-racy, so extensions relying on it should switch to C++11 threads. ThreadWorker is now pared down and does not interact or inherit from BaseWorker in any way. Basic functionality has been tested. Since it is not used anywhere in SourceMod, or seemingly in any repository on GitHub, it's unclear whether it should even exist. But it has been tested in this patch. This change bumps the minimum macOS version to OS X 10.7, and the minimum C++ standard level to C++14.
This commit is contained in:
parent
87cc42d348
commit
f76cb94511
@ -281,8 +281,13 @@ class SMConfig(object):
|
||||
'-msse',
|
||||
'-fvisibility=hidden',
|
||||
]
|
||||
|
||||
if cxx.version == 'apple-clang-6.0':
|
||||
cxx.cxxflags += ['-std=c++1y']
|
||||
else:
|
||||
cxx.cxxflags += ['-std=c++14']
|
||||
|
||||
cxx.cxxflags += [
|
||||
'-std=c++11',
|
||||
'-fno-exceptions',
|
||||
'-fno-threadsafe-statics',
|
||||
'-Wno-non-virtual-dtor',
|
||||
@ -386,16 +391,16 @@ class SMConfig(object):
|
||||
cxx.linkflags += ['-static-libgcc']
|
||||
elif cxx.family == 'clang':
|
||||
cxx.linkflags += ['-lgcc_eh']
|
||||
cxx.linkflags += ['-static-libstdc++']
|
||||
|
||||
def configure_mac(self, cxx):
|
||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.5']
|
||||
cxx.cflags += ['-mmacosx-version-min=10.7']
|
||||
cxx.linkflags += [
|
||||
'-mmacosx-version-min=10.5',
|
||||
'-lstdc++',
|
||||
'-stdlib=libstdc++',
|
||||
'-mmacosx-version-min=10.7',
|
||||
'-stdlib=libc++',
|
||||
]
|
||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
||||
cxx.cxxflags += ['-stdlib=libc++']
|
||||
|
||||
def configure_windows(self, cxx):
|
||||
cxx.defines += ['WIN32', '_WINDOWS']
|
||||
@ -545,9 +550,11 @@ class SMConfig(object):
|
||||
if builder.target.platform in ['linux', 'mac']:
|
||||
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
||||
|
||||
if sdk.name in ['csgo', 'blade'] and builder.target.platform == 'linux':
|
||||
compiler.linkflags += ['-lstdc++']
|
||||
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
||||
if builder.target.platform == 'linux':
|
||||
if sdk.name in ['csgo', 'blade']:
|
||||
compiler.linkflags.remove('-static-libstdc++')
|
||||
compiler.linkflags += ['-lstdc++']
|
||||
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
||||
|
||||
for path in paths:
|
||||
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||
|
@ -35,8 +35,7 @@ for arch in SM.archs:
|
||||
'smn_maplists.cpp',
|
||||
'ADTFactory.cpp',
|
||||
'smn_adt_stack.cpp',
|
||||
'thread/ThreadWorker.cpp',
|
||||
'thread/BaseWorker.cpp',
|
||||
'BaseWorker.cpp',
|
||||
'ThreadSupport.cpp',
|
||||
'smn_float.cpp',
|
||||
'TextParsers.cpp',
|
||||
@ -90,9 +89,4 @@ for arch in SM.archs:
|
||||
if arch == 'x64':
|
||||
binary.sources += ['PseudoAddrManager.cpp']
|
||||
|
||||
if builder.target.platform == 'windows':
|
||||
binary.sources += ['thread/WinThreads.cpp']
|
||||
else:
|
||||
binary.sources += ['thread/PosixThreads.cpp']
|
||||
|
||||
SM.binaries += [builder.Add(binary)]
|
||||
|
@ -43,6 +43,7 @@ class BaseWorker;
|
||||
class SWThreadHandle : public IThreadHandle
|
||||
{
|
||||
friend class BaseWorker;
|
||||
friend class CompatWorker;
|
||||
public:
|
||||
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
||||
IThread *GetThread();
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
@ -29,17 +29,515 @@
|
||||
* Version: $Id$
|
||||
*/
|
||||
#include <sm_platform.h>
|
||||
#include <amtl/am-deque.h>
|
||||
#include <amtl/am-maybe.h>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "BaseWorker.h"
|
||||
#include "ThreadSupport.h"
|
||||
#include "common_logic.h"
|
||||
|
||||
#if defined PLATFORM_POSIX
|
||||
#include "thread/PosixThreads.h"
|
||||
#elif defined PLATFORM_WINDOWS
|
||||
#include "thread/WinThreads.h"
|
||||
#endif
|
||||
static constexpr unsigned int DEFAULT_THINK_TIME_MS = 20;
|
||||
|
||||
MainThreader g_MainThreader;
|
||||
IThreader *g_pThreader = &g_MainThreader;
|
||||
class CompatWorker final : public IThreadWorker
|
||||
{
|
||||
public:
|
||||
explicit CompatWorker(IThreadWorkerCallbacks* callbacks);
|
||||
~CompatWorker();
|
||||
|
||||
void MakeThread(IThread *pThread) override;
|
||||
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override;
|
||||
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override;
|
||||
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override;
|
||||
unsigned int RunFrame() override;
|
||||
bool Pause() override;
|
||||
bool Unpause() override;
|
||||
bool Start() override;
|
||||
bool Stop(bool flush) override;
|
||||
WorkerState GetStatus(unsigned int *numThreads) override;
|
||||
void SetMaxThreadsPerFrame(unsigned int threads) override;
|
||||
void SetThinkTimePerFrame(unsigned int thinktime) override;
|
||||
|
||||
private:
|
||||
void Flush();
|
||||
void Worker();
|
||||
void RunWork(SWThreadHandle* handle);
|
||||
void RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle);
|
||||
|
||||
private:
|
||||
IThreadWorkerCallbacks* callbacks_;
|
||||
WorkerState state_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable work_cv_;
|
||||
ke::Deque<SWThreadHandle*> work_;
|
||||
std::unique_ptr<std::thread> thread_;
|
||||
std::atomic<unsigned int> jobs_per_wakeup_;
|
||||
std::atomic<unsigned int> wait_between_jobs_;
|
||||
};
|
||||
|
||||
CompatWorker::CompatWorker(IThreadWorkerCallbacks* callbacks)
|
||||
: callbacks_(callbacks),
|
||||
state_(Worker_Stopped),
|
||||
jobs_per_wakeup_(SM_DEFAULT_THREADS_PER_FRAME),
|
||||
wait_between_jobs_(DEFAULT_THINK_TIME_MS)
|
||||
{
|
||||
}
|
||||
|
||||
CompatWorker::~CompatWorker()
|
||||
{
|
||||
Stop(false /* ignored */);
|
||||
Flush();
|
||||
}
|
||||
|
||||
bool CompatWorker::Start()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (state_ != Worker_Stopped)
|
||||
return false;
|
||||
|
||||
thread_ = std::make_unique<std::thread>([this]() -> void {
|
||||
Worker();
|
||||
});
|
||||
state_ = Worker_Running;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompatWorker::Stop(bool)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
if (state_ <= Worker_Stopped)
|
||||
return false;
|
||||
|
||||
state_ = Worker_Stopped;
|
||||
work_cv_.notify_all();
|
||||
}
|
||||
|
||||
thread_->join();
|
||||
thread_ = nullptr;
|
||||
|
||||
Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompatWorker::Pause()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (state_ != Worker_Running)
|
||||
return false;
|
||||
|
||||
state_ = Worker_Paused;
|
||||
work_cv_.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompatWorker::Unpause()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (state_ != Worker_Paused)
|
||||
return false;
|
||||
|
||||
state_ = Worker_Running;
|
||||
work_cv_.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompatWorker::Flush()
|
||||
{
|
||||
while (!work_.empty()) {
|
||||
auto handle = work_.popFrontCopy();
|
||||
handle->GetThread()->OnTerminate(handle, true);
|
||||
if (handle->m_params.flags & Thread_AutoRelease)
|
||||
delete handle;
|
||||
}
|
||||
}
|
||||
|
||||
void CompatWorker::Worker()
|
||||
{
|
||||
// Note: this must be first to ensure an ordering between Worker() and
|
||||
// Start(). It must also be outside of the loop to ensure the lock is
|
||||
// held across wakeup and retesting the predicates.
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
|
||||
if (callbacks_) {
|
||||
lock.unlock();
|
||||
callbacks_->OnWorkerStart(this);
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
typedef std::chrono::system_clock Clock;
|
||||
typedef std::chrono::time_point<Clock> TimePoint;
|
||||
|
||||
auto can_work = [this]() -> bool {
|
||||
return state_ == Worker_Running && !work_.empty();
|
||||
};
|
||||
|
||||
ke::Maybe<TimePoint> wait;
|
||||
unsigned int work_in_frame = 0;
|
||||
for (;;) {
|
||||
if (state_ == Worker_Stopped)
|
||||
break;
|
||||
|
||||
if (!can_work()) {
|
||||
// Wait for work or a Stop.
|
||||
work_cv_.wait(lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wait.isValid()) {
|
||||
// Wait until the specified time has passed. If we wake up with a
|
||||
// timeout, then the wait has elapsed, so reset the holder.
|
||||
if (work_cv_.wait_until(lock, wait.get()) == std::cv_status::timeout)
|
||||
wait = ke::Nothing();
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(state_ == Worker_Running);
|
||||
assert(!work_.empty());
|
||||
|
||||
SWThreadHandle* handle = work_.popFrontCopy();
|
||||
RunWorkLocked(&lock, handle);
|
||||
work_in_frame++;
|
||||
|
||||
// If we've reached our max jobs per "frame", signal that the next
|
||||
// immediate job must be delayed. We retain the old ThreadWorker
|
||||
// behavior by checking if the queue has more work. Thus, a delay
|
||||
// only occurs if two jobs would be processed in the same wakeup.
|
||||
if (work_in_frame >= jobs_per_wakeup_ && wait_between_jobs_ && can_work())
|
||||
wait = ke::Some(Clock::now() + std::chrono::milliseconds(wait_between_jobs_));
|
||||
}
|
||||
|
||||
assert(lock.owns_lock());
|
||||
|
||||
while (!work_.empty()) {
|
||||
SWThreadHandle* handle = work_.popFrontCopy();
|
||||
RunWorkLocked(&lock, handle);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CompatWorker::RunFrame()
|
||||
{
|
||||
unsigned int nprocessed = 0;
|
||||
for (unsigned int i = 1; i <= jobs_per_wakeup_; i++) {
|
||||
SWThreadHandle* handle;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (work_.empty())
|
||||
break;
|
||||
handle = work_.popFrontCopy();
|
||||
}
|
||||
|
||||
RunWork(handle);
|
||||
nprocessed++;
|
||||
}
|
||||
return nprocessed;
|
||||
}
|
||||
|
||||
void CompatWorker::RunWorkLocked(std::unique_lock<std::mutex>* lock, SWThreadHandle* handle)
|
||||
{
|
||||
lock->unlock();
|
||||
RunWork(handle);
|
||||
lock->lock();
|
||||
}
|
||||
|
||||
void CompatWorker::RunWork(SWThreadHandle* handle)
|
||||
{
|
||||
bool autorelease = !!(handle->m_params.flags & Thread_AutoRelease);
|
||||
handle->m_state = Thread_Running;
|
||||
handle->GetThread()->RunThread(handle);
|
||||
handle->m_state = Thread_Done;
|
||||
handle->GetThread()->OnTerminate(handle, false);
|
||||
if (autorelease)
|
||||
delete handle;
|
||||
}
|
||||
|
||||
void CompatWorker::MakeThread(IThread *pThread)
|
||||
{
|
||||
ThreadParams params;
|
||||
params.flags = Thread_AutoRelease;
|
||||
MakeThread(pThread, ¶ms);
|
||||
}
|
||||
|
||||
IThreadHandle *CompatWorker::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||
{
|
||||
ThreadParams params;
|
||||
params.flags = flags;
|
||||
return MakeThread(pThread, ¶ms);
|
||||
}
|
||||
|
||||
IThreadHandle *CompatWorker::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
ThreadParams def_params;
|
||||
if (!params)
|
||||
params = &def_params;
|
||||
|
||||
if (state_ <= Worker_Stopped)
|
||||
return nullptr;
|
||||
|
||||
SWThreadHandle* handle = new SWThreadHandle(this, params, pThread);
|
||||
work_.append(handle);
|
||||
work_cv_.notify_one();
|
||||
return handle;
|
||||
}
|
||||
|
||||
void CompatWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||
{
|
||||
min = ThreadPrio_Normal;
|
||||
max = ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
void CompatWorker::SetMaxThreadsPerFrame(unsigned int threads)
|
||||
{
|
||||
jobs_per_wakeup_ = threads;
|
||||
}
|
||||
|
||||
void CompatWorker::SetThinkTimePerFrame(unsigned int thinktime)
|
||||
{
|
||||
wait_between_jobs_ = thinktime;
|
||||
}
|
||||
|
||||
WorkerState CompatWorker::GetStatus(unsigned int *numThreads)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
// This number is meaningless and the status is racy.
|
||||
if (numThreads)
|
||||
*numThreads = jobs_per_wakeup_;
|
||||
return state_;
|
||||
}
|
||||
|
||||
class CompatThread final : public IThreadHandle
|
||||
{
|
||||
public:
|
||||
CompatThread(IThread* callbacks, const ThreadParams* params);
|
||||
|
||||
bool WaitForThread() override;
|
||||
void DestroyThis() override;
|
||||
IThreadCreator *Parent() override;
|
||||
void GetParams(ThreadParams *ptparams) override;
|
||||
ThreadPriority GetPriority() override;
|
||||
bool SetPriority(ThreadPriority prio) override;
|
||||
ThreadState GetState() override;
|
||||
bool Unpause() override;
|
||||
|
||||
private:
|
||||
void Run();
|
||||
|
||||
private:
|
||||
IThread* callbacks_;
|
||||
ThreadParams params_;
|
||||
std::unique_ptr<std::thread> thread_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable check_cv_;
|
||||
std::atomic<bool> finished_;
|
||||
};
|
||||
|
||||
CompatThread::CompatThread(IThread* callbacks, const ThreadParams* params)
|
||||
: callbacks_(callbacks),
|
||||
params_(*params)
|
||||
{
|
||||
if (!(params_.flags & Thread_CreateSuspended))
|
||||
Unpause();
|
||||
}
|
||||
|
||||
bool CompatThread::Unpause()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (thread_)
|
||||
return false;
|
||||
|
||||
thread_ = std::make_unique<std::thread>([this]() -> void {
|
||||
Run();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompatThread::Run()
|
||||
{
|
||||
// Create an ordering between when the thread runs and when thread_ is assigned.
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
|
||||
lock.unlock();
|
||||
callbacks_->RunThread(this);
|
||||
finished_ = true;
|
||||
callbacks_->OnTerminate(this, false);
|
||||
|
||||
if (params_.flags & Thread_AutoRelease) {
|
||||
// There should be no handles outstanding, so it's safe to self-destruct.
|
||||
thread_->detach();
|
||||
delete this;
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
callbacks_ = nullptr;
|
||||
check_cv_.notify_all();
|
||||
}
|
||||
|
||||
bool CompatThread::WaitForThread()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
for (;;) {
|
||||
// When done, callbacks are unset. If paused, this will deadlock.
|
||||
if (!callbacks_)
|
||||
break;
|
||||
check_cv_.wait(lock);
|
||||
}
|
||||
|
||||
thread_->join();
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadState CompatThread::GetState()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (!thread_)
|
||||
return Thread_Paused;
|
||||
return finished_ ? Thread_Done : Thread_Running;
|
||||
}
|
||||
|
||||
void CompatThread::DestroyThis()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
ThreadPriority CompatThread::GetPriority()
|
||||
{
|
||||
return ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
bool CompatThread::SetPriority(ThreadPriority prio)
|
||||
{
|
||||
return prio == ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
IThreadCreator *CompatThread::Parent()
|
||||
{
|
||||
return g_pThreader;
|
||||
}
|
||||
|
||||
void CompatThread::GetParams(ThreadParams *ptparams)
|
||||
{
|
||||
*ptparams = params_;
|
||||
}
|
||||
|
||||
class CompatMutex : public IMutex
|
||||
{
|
||||
public:
|
||||
bool TryLock() {
|
||||
return mutex_.try_lock();
|
||||
}
|
||||
void Lock() {
|
||||
mutex_.lock();
|
||||
}
|
||||
void Unlock() {
|
||||
mutex_.unlock();
|
||||
}
|
||||
void DestroyThis() {
|
||||
delete this;
|
||||
}
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
class CompatThreader final : public IThreader
|
||||
{
|
||||
public:
|
||||
void MakeThread(IThread *pThread) override;
|
||||
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags) override;
|
||||
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params) override;
|
||||
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min) override;
|
||||
IMutex *MakeMutex() override;
|
||||
void ThreadSleep(unsigned int ms) override;
|
||||
IEventSignal *MakeEventSignal() override;
|
||||
IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded) override;
|
||||
void DestroyWorker(IThreadWorker *pWorker) override;
|
||||
} sCompatThreader;
|
||||
|
||||
void CompatThreader::MakeThread(IThread *pThread)
|
||||
{
|
||||
ThreadParams params;
|
||||
params.flags = Thread_AutoRelease;
|
||||
MakeThread(pThread, ¶ms);
|
||||
}
|
||||
|
||||
IThreadHandle *CompatThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||
{
|
||||
ThreadParams params;
|
||||
params.flags = flags;
|
||||
return MakeThread(pThread, ¶ms);
|
||||
}
|
||||
|
||||
IThreadHandle *CompatThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||
{
|
||||
ThreadParams def_params;
|
||||
if (!params)
|
||||
params = &def_params;
|
||||
|
||||
return new CompatThread(pThread, params);
|
||||
}
|
||||
|
||||
void CompatThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||
{
|
||||
min = ThreadPrio_Normal;
|
||||
max = ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
IMutex *CompatThreader::MakeMutex()
|
||||
{
|
||||
return new CompatMutex();
|
||||
}
|
||||
|
||||
void CompatThreader::ThreadSleep(unsigned int ms)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
class CompatEventSignal final : public IEventSignal
|
||||
{
|
||||
public:
|
||||
void Wait() override {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cv_.wait(lock);
|
||||
}
|
||||
void Signal() override {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
cv_.notify_all();
|
||||
}
|
||||
void DestroyThis() override {
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
};
|
||||
|
||||
IEventSignal *CompatThreader::MakeEventSignal()
|
||||
{
|
||||
return new CompatEventSignal();
|
||||
}
|
||||
|
||||
IThreadWorker *CompatThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
|
||||
{
|
||||
if (!threaded)
|
||||
return new BaseWorker(hooks);
|
||||
return new CompatWorker(hooks);
|
||||
}
|
||||
|
||||
void CompatThreader::DestroyWorker(IThreadWorker *pWorker)
|
||||
{
|
||||
delete pWorker;
|
||||
}
|
||||
|
||||
IThreader *g_pThreader = &sCompatThreader;
|
||||
|
||||
class RegThreadStuff : public SMGlobalClass
|
||||
{
|
||||
|
@ -32,49 +32,14 @@
|
||||
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <IThreader.h>
|
||||
#include <am-thread-utils.h>
|
||||
#include <am-utility.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
class CompatMutex : public IMutex
|
||||
{
|
||||
public:
|
||||
bool TryLock() {
|
||||
return mutex_.TryLock();
|
||||
}
|
||||
void Lock() {
|
||||
mutex_.Lock();
|
||||
}
|
||||
void Unlock() {
|
||||
mutex_.Unlock();
|
||||
}
|
||||
void DestroyThis() {
|
||||
delete this;
|
||||
}
|
||||
private:
|
||||
ke::Mutex mutex_;
|
||||
};
|
||||
|
||||
class CompatCondVar : public IEventSignal
|
||||
{
|
||||
public:
|
||||
void Wait() {
|
||||
ke::AutoLock lock(&cv_);
|
||||
cv_.Wait();
|
||||
}
|
||||
void Signal() {
|
||||
ke::AutoLock lock(&cv_);
|
||||
cv_.Notify();
|
||||
}
|
||||
void DestroyThis() {
|
||||
delete this;
|
||||
}
|
||||
private:
|
||||
ke::ConditionVariable cv_;
|
||||
};
|
||||
|
||||
extern IThreader *g_pThreader;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||
|
@ -1,199 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet:
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "PosixThreads.h"
|
||||
#include "ThreadWorker.h"
|
||||
|
||||
IThreadWorker *PosixThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
|
||||
{
|
||||
if (threaded)
|
||||
{
|
||||
return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
|
||||
} else {
|
||||
return new BaseWorker(hooks);
|
||||
}
|
||||
}
|
||||
|
||||
void PosixThreader::DestroyWorker(IThreadWorker *pWorker)
|
||||
{
|
||||
delete pWorker;
|
||||
}
|
||||
|
||||
void PosixThreader::ThreadSleep(unsigned int ms)
|
||||
{
|
||||
usleep( ms * 1000 );
|
||||
}
|
||||
|
||||
void PosixThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||
{
|
||||
max = ThreadPrio_Normal;
|
||||
min = ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
IMutex *PosixThreader::MakeMutex()
|
||||
{
|
||||
return new CompatMutex();
|
||||
}
|
||||
|
||||
void PosixThreader::MakeThread(IThread *pThread)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = Thread_AutoRelease;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
IThreadHandle *PosixThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = flags;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
return MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
void PosixThreader::ThreadHandle::Run()
|
||||
{
|
||||
// Wait for an unpause if necessary.
|
||||
{
|
||||
ke::AutoLock lock(&m_runlock);
|
||||
if (m_state == Thread_Paused)
|
||||
m_runlock.Wait();
|
||||
}
|
||||
|
||||
m_run->RunThread(this);
|
||||
m_state = Thread_Done;
|
||||
m_run->OnTerminate(this, false);
|
||||
|
||||
if (m_params.flags & Thread_AutoRelease)
|
||||
delete this;
|
||||
}
|
||||
|
||||
ThreadParams g_defparams;
|
||||
IThreadHandle *PosixThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||
{
|
||||
if (params == NULL)
|
||||
params = &g_defparams;
|
||||
|
||||
ThreadHandle* pHandle = new ThreadHandle(this, pThread, params);
|
||||
|
||||
pHandle->m_thread = new ke::Thread([pHandle]() -> void {
|
||||
pHandle->Run();
|
||||
}, "SourceMod");
|
||||
if (!pHandle->m_thread->Succeeded()) {
|
||||
delete pHandle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(params->flags & Thread_CreateSuspended))
|
||||
pHandle->Unpause();
|
||||
|
||||
return pHandle;
|
||||
}
|
||||
|
||||
IEventSignal *PosixThreader::MakeEventSignal()
|
||||
{
|
||||
return new CompatCondVar();
|
||||
}
|
||||
|
||||
/******************
|
||||
* Thread Handles *
|
||||
******************/
|
||||
|
||||
PosixThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) :
|
||||
m_parent(parent), m_params(*params), m_run(run), m_state(Thread_Paused)
|
||||
{
|
||||
}
|
||||
|
||||
PosixThreader::ThreadHandle::~ThreadHandle()
|
||||
{
|
||||
}
|
||||
|
||||
bool PosixThreader::ThreadHandle::WaitForThread()
|
||||
{
|
||||
if (!m_thread)
|
||||
return false;
|
||||
|
||||
m_thread->Join();
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadState PosixThreader::ThreadHandle::GetState()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
IThreadCreator *PosixThreader::ThreadHandle::Parent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
void PosixThreader::ThreadHandle::DestroyThis()
|
||||
{
|
||||
if (m_params.flags & Thread_AutoRelease)
|
||||
return;
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PosixThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
|
||||
{
|
||||
if (!ptparams)
|
||||
return;
|
||||
|
||||
*ptparams = m_params;
|
||||
}
|
||||
|
||||
ThreadPriority PosixThreader::ThreadHandle::GetPriority()
|
||||
{
|
||||
return ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
bool PosixThreader::ThreadHandle::SetPriority(ThreadPriority prio)
|
||||
{
|
||||
return (prio == ThreadPrio_Normal);
|
||||
}
|
||||
|
||||
bool PosixThreader::ThreadHandle::Unpause()
|
||||
{
|
||||
if (m_state != Thread_Paused)
|
||||
return false;
|
||||
|
||||
ke::AutoLock lock(&m_runlock);
|
||||
m_state = Thread_Running;
|
||||
m_runlock.Notify();
|
||||
return true;
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet:
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_POSIXTHREADS_H_
|
||||
#define _INCLUDE_POSIXTHREADS_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <am-thread-utils.h>
|
||||
#include "IThreader.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
class PosixThreader : public IThreader
|
||||
{
|
||||
public:
|
||||
class ThreadHandle : public IThreadHandle
|
||||
{
|
||||
friend class PosixThreader;
|
||||
public:
|
||||
ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params);
|
||||
virtual ~ThreadHandle();
|
||||
public:
|
||||
virtual bool WaitForThread();
|
||||
virtual void DestroyThis();
|
||||
virtual IThreadCreator *Parent();
|
||||
virtual void GetParams(ThreadParams *ptparams);
|
||||
virtual ThreadPriority GetPriority();
|
||||
virtual bool SetPriority(ThreadPriority prio);
|
||||
virtual ThreadState GetState();
|
||||
virtual bool Unpause();
|
||||
public:
|
||||
void Run();
|
||||
protected:
|
||||
IThreader *m_parent; //Parent handle
|
||||
ThreadParams m_params; //Current Parameters
|
||||
IThread *m_run; //Runnable context
|
||||
ke::AutoPtr<ke::Thread> m_thread;
|
||||
ke::ConditionVariable m_runlock;
|
||||
ThreadState m_state; //internal state
|
||||
};
|
||||
public:
|
||||
IMutex *MakeMutex();
|
||||
void MakeThread(IThread *pThread);
|
||||
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags);
|
||||
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params);
|
||||
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min);
|
||||
void ThreadSleep(unsigned int ms);
|
||||
IEventSignal *MakeEventSignal();
|
||||
IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded);
|
||||
void DestroyWorker(IThreadWorker *pWorker);
|
||||
};
|
||||
|
||||
#if defined SM_DEFAULT_THREADER && !defined SM_MAIN_THREADER
|
||||
#define SM_MAIN_THREADER PosixThreader;
|
||||
typedef class PosixThreader MainThreader;
|
||||
#endif
|
||||
|
||||
#endif //_INCLUDE_POSIXTHREADS_H_
|
@ -1,218 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "ThreadWorker.h"
|
||||
|
||||
ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks) : BaseWorker(hooks),
|
||||
m_Threader(NULL),
|
||||
me(NULL),
|
||||
m_think_time(DEFAULT_THINK_TIME_MS)
|
||||
{
|
||||
m_state = Worker_Invalid;
|
||||
}
|
||||
|
||||
ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime) :
|
||||
BaseWorker(hooks),
|
||||
m_Threader(pThreader),
|
||||
me(NULL),
|
||||
m_think_time(thinktime)
|
||||
{
|
||||
m_state = m_Threader ? Worker_Stopped : Worker_Invalid;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//we don't particularly care
|
||||
return;
|
||||
}
|
||||
|
||||
void ThreadWorker::RunThread(IThreadHandle *pHandle)
|
||||
{
|
||||
if (m_pHooks)
|
||||
m_pHooks->OnWorkerStart(this);
|
||||
|
||||
ke::AutoLock lock(&monitor_);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (m_state == Worker_Paused)
|
||||
{
|
||||
// Wait until we're told to wake up.
|
||||
monitor_.Wait();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_state == Worker_Stopped)
|
||||
{
|
||||
// We've been told to stop entirely. If we've also been told to
|
||||
// flush the queue, do that now.
|
||||
while (!m_ThreadQueue.empty())
|
||||
{
|
||||
// Release the lock since PopThreadFromQueue() will re-acquire it. The
|
||||
// main thread is blocking anyway.
|
||||
ke::AutoUnlock unlock(&monitor_);
|
||||
RunFrame();
|
||||
}
|
||||
assert(m_state == Worker_Stopped);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(m_state == Worker_Running);
|
||||
|
||||
// Process one frame.
|
||||
WorkerState oldstate = m_state;
|
||||
{
|
||||
ke::AutoUnlock unlock(&monitor_);
|
||||
RunFrame();
|
||||
}
|
||||
|
||||
// If the state changed, loop back and process the new state.
|
||||
if (m_state != oldstate)
|
||||
continue;
|
||||
|
||||
// If the thread queue is now empty, wait for a signal. Otherwise, if
|
||||
// we're on a delay, wait for either a notification or a timeout to
|
||||
// process the next item. If the queue has items and we don't have a
|
||||
// delay, then we just loop around and keep processing.
|
||||
if (m_ThreadQueue.empty())
|
||||
monitor_.Wait();
|
||||
else if (m_think_time)
|
||||
monitor_.Wait(m_think_time);
|
||||
}
|
||||
|
||||
{
|
||||
ke::AutoUnlock unlock(&monitor_);
|
||||
if (m_pHooks)
|
||||
m_pHooks->OnWorkerStop(this);
|
||||
}
|
||||
}
|
||||
|
||||
SWThreadHandle *ThreadWorker::PopThreadFromQueue()
|
||||
{
|
||||
ke::AutoLock lock(&monitor_);
|
||||
if (m_state <= Worker_Stopped)
|
||||
return NULL;
|
||||
|
||||
return BaseWorker::PopThreadFromQueue();
|
||||
}
|
||||
|
||||
void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
|
||||
{
|
||||
ke::AutoLock lock(&monitor_);
|
||||
if (m_state <= Worker_Stopped)
|
||||
return;
|
||||
|
||||
BaseWorker::AddThreadToQueue(pHandle);
|
||||
monitor_.Notify();
|
||||
}
|
||||
|
||||
WorkerState ThreadWorker::GetStatus(unsigned int *threads)
|
||||
{
|
||||
ke::AutoLock lock(&monitor_);
|
||||
return BaseWorker::GetStatus(threads);
|
||||
}
|
||||
|
||||
void ThreadWorker::SetThinkTimePerFrame(unsigned int thinktime)
|
||||
{
|
||||
m_think_time = thinktime;
|
||||
}
|
||||
|
||||
bool ThreadWorker::Start()
|
||||
{
|
||||
if (m_state == Worker_Invalid && m_Threader == NULL)
|
||||
return false;
|
||||
|
||||
if (m_state != Worker_Stopped)
|
||||
return false;
|
||||
|
||||
m_state = Worker_Running;
|
||||
|
||||
ThreadParams pt;
|
||||
pt.flags = Thread_Default;
|
||||
pt.prio = ThreadPrio_Normal;
|
||||
me = m_Threader->MakeThread(this, &pt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadWorker::Stop(bool flush_cancel)
|
||||
{
|
||||
// Change the state to signal a stop, and then trigger a notify.
|
||||
{
|
||||
ke::AutoLock lock(&monitor_);
|
||||
if (m_state == Worker_Invalid || m_state == Worker_Stopped)
|
||||
return false;
|
||||
|
||||
m_state = Worker_Stopped;
|
||||
m_FlushType = flush_cancel;
|
||||
monitor_.Notify();
|
||||
}
|
||||
|
||||
me->WaitForThread();
|
||||
//destroy it
|
||||
me->DestroyThis();
|
||||
//flush all remaining events
|
||||
Flush(true);
|
||||
|
||||
me = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadWorker::Pause()
|
||||
{
|
||||
if (m_state != Worker_Running)
|
||||
return false;
|
||||
|
||||
ke::AutoLock lock(&monitor_);
|
||||
m_state = Worker_Paused;
|
||||
monitor_.Notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadWorker::Unpause()
|
||||
{
|
||||
if (m_state != Worker_Paused)
|
||||
return false;
|
||||
|
||||
ke::AutoLock lock(&monitor_);
|
||||
m_state = Worker_Running;
|
||||
monitor_.Notify();
|
||||
return true;
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_THREADWORKER_H
|
||||
#define _INCLUDE_SOURCEMOD_THREADWORKER_H
|
||||
|
||||
#include "BaseWorker.h"
|
||||
|
||||
#define DEFAULT_THINK_TIME_MS 20
|
||||
|
||||
class ThreadWorker : public BaseWorker, public IThread
|
||||
{
|
||||
public:
|
||||
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);
|
||||
virtual void RunThread(IThreadHandle *pHandle);
|
||||
public: //IWorker
|
||||
//Controls the worker
|
||||
virtual bool Pause();
|
||||
virtual bool Unpause();
|
||||
virtual bool Start();
|
||||
virtual bool Stop(bool flush_cancel);
|
||||
//returns status and number of threads in queue
|
||||
virtual WorkerState GetStatus(unsigned int *numThreads);
|
||||
//virtual void SetMaxThreadsPerFrame(unsigned int threads);
|
||||
virtual void SetThinkTimePerFrame(unsigned int thinktime);
|
||||
public: //BaseWorker
|
||||
virtual void AddThreadToQueue(SWThreadHandle *pHandle);
|
||||
virtual SWThreadHandle *PopThreadFromQueue();
|
||||
protected:
|
||||
IThreader *m_Threader;
|
||||
IThreadHandle *me;
|
||||
unsigned int m_think_time;
|
||||
bool m_FlushType;
|
||||
ke::ConditionVariable monitor_;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_THREADWORKER_H
|
@ -1,216 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet:
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include "WinThreads.h"
|
||||
#include "ThreadWorker.h"
|
||||
|
||||
IThreadWorker *WinThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
|
||||
{
|
||||
if (threaded)
|
||||
{
|
||||
return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
|
||||
} else {
|
||||
return new BaseWorker(hooks);
|
||||
}
|
||||
}
|
||||
|
||||
void WinThreader::DestroyWorker(IThreadWorker *pWorker)
|
||||
{
|
||||
delete pWorker;
|
||||
}
|
||||
|
||||
void WinThreader::ThreadSleep(unsigned int ms)
|
||||
{
|
||||
Sleep((DWORD)ms);
|
||||
}
|
||||
|
||||
IMutex *WinThreader::MakeMutex()
|
||||
{
|
||||
return new CompatMutex();
|
||||
}
|
||||
|
||||
IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = flags;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
return MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
void WinThreader::MakeThread(IThread *pThread)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = Thread_AutoRelease;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
void WinThreader::ThreadHandle::Run()
|
||||
{
|
||||
// Wait for an unpause if necessary.
|
||||
{
|
||||
ke::AutoLock lock(&suspend_);
|
||||
if (m_state == Thread_Paused)
|
||||
suspend_.Wait();
|
||||
}
|
||||
|
||||
m_run->RunThread(this);
|
||||
m_state = Thread_Done;
|
||||
m_run->OnTerminate(this, false);
|
||||
if (m_params.flags & Thread_AutoRelease)
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||
{
|
||||
max = ThreadPrio_Maximum;
|
||||
min = ThreadPrio_Minimum;
|
||||
}
|
||||
|
||||
ThreadParams g_defparams;
|
||||
IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||
{
|
||||
if (params == NULL)
|
||||
params = &g_defparams;
|
||||
|
||||
ThreadHandle* pHandle = new ThreadHandle(this, pThread, params);
|
||||
|
||||
pHandle->m_thread = new ke::Thread([pHandle]() -> void {
|
||||
pHandle->Run();
|
||||
}, "SourceMod");
|
||||
if (!pHandle->m_thread->Succeeded()) {
|
||||
delete pHandle;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pHandle->m_params.prio != ThreadPrio_Normal)
|
||||
pHandle->SetPriority(pHandle->m_params.prio);
|
||||
|
||||
if (!(params->flags & Thread_CreateSuspended))
|
||||
pHandle->Unpause();
|
||||
|
||||
return pHandle;
|
||||
}
|
||||
|
||||
IEventSignal *WinThreader::MakeEventSignal()
|
||||
{
|
||||
return new CompatCondVar();
|
||||
}
|
||||
|
||||
/******************
|
||||
* Thread Handles *
|
||||
******************/
|
||||
|
||||
WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) :
|
||||
m_parent(parent), m_run(run), m_params(*params),
|
||||
m_state(Thread_Paused)
|
||||
{
|
||||
}
|
||||
|
||||
WinThreader::ThreadHandle::~ThreadHandle()
|
||||
{
|
||||
}
|
||||
|
||||
bool WinThreader::ThreadHandle::WaitForThread()
|
||||
{
|
||||
if (!m_thread)
|
||||
return false;
|
||||
|
||||
m_thread->Join();
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadState WinThreader::ThreadHandle::GetState()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
IThreadCreator *WinThreader::ThreadHandle::Parent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
void WinThreader::ThreadHandle::DestroyThis()
|
||||
{
|
||||
if (m_params.flags & Thread_AutoRelease)
|
||||
return;
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
|
||||
{
|
||||
if (!ptparams)
|
||||
return;
|
||||
|
||||
*ptparams = m_params;
|
||||
}
|
||||
|
||||
ThreadPriority WinThreader::ThreadHandle::GetPriority()
|
||||
{
|
||||
return m_params.prio;
|
||||
}
|
||||
|
||||
bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
|
||||
if (prio >= ThreadPrio_Maximum)
|
||||
res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_HIGHEST);
|
||||
else if (prio <= ThreadPrio_Minimum)
|
||||
res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_LOWEST);
|
||||
else if (prio == ThreadPrio_Normal)
|
||||
res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_NORMAL);
|
||||
else if (prio == ThreadPrio_High)
|
||||
res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
else if (prio == ThreadPrio_Low)
|
||||
res = SetThreadPriority(m_thread->handle(), THREAD_PRIORITY_BELOW_NORMAL);
|
||||
|
||||
m_params.prio = prio;
|
||||
|
||||
return (res != FALSE);
|
||||
}
|
||||
|
||||
bool WinThreader::ThreadHandle::Unpause()
|
||||
{
|
||||
if (m_state != Thread_Paused)
|
||||
return false;
|
||||
|
||||
ke::AutoLock lock(&suspend_);
|
||||
m_state = Thread_Running;
|
||||
suspend_.Notify();
|
||||
return true;
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_WINTHREADS_H_
|
||||
#define _INCLUDE_WINTHREADS_H_
|
||||
|
||||
#include <am-thread-utils.h>
|
||||
#include <am-utility.h>
|
||||
#include <windows.h>
|
||||
#include "IThreader.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
class WinThreader : public IThreader
|
||||
{
|
||||
public:
|
||||
class ThreadHandle : public IThreadHandle
|
||||
{
|
||||
friend class WinThreader;
|
||||
friend DWORD WINAPI Win32_ThreadGate(LPVOID param);
|
||||
public:
|
||||
ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params);
|
||||
virtual ~ThreadHandle();
|
||||
public:
|
||||
virtual bool WaitForThread();
|
||||
virtual void DestroyThis();
|
||||
virtual IThreadCreator *Parent();
|
||||
virtual void GetParams(ThreadParams *ptparams);
|
||||
virtual ThreadPriority GetPriority();
|
||||
virtual bool SetPriority(ThreadPriority prio);
|
||||
virtual ThreadState GetState();
|
||||
virtual bool Unpause();
|
||||
virtual void Run();
|
||||
protected:
|
||||
IThreader *m_parent; //Parent handle
|
||||
ke::AutoPtr<ke::Thread> m_thread;
|
||||
ThreadParams m_params; //Current Parameters
|
||||
IThread *m_run; //Runnable context
|
||||
ThreadState m_state; //internal state
|
||||
ke::ConditionVariable suspend_;
|
||||
};
|
||||
|
||||
public:
|
||||
IMutex *MakeMutex();
|
||||
void MakeThread(IThread *pThread);
|
||||
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags);
|
||||
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params);
|
||||
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min);
|
||||
void ThreadSleep(unsigned int ms);
|
||||
IEventSignal *MakeEventSignal();
|
||||
IThreadWorker *MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded);
|
||||
void DestroyWorker(IThreadWorker *pWorker);
|
||||
};
|
||||
|
||||
#if defined SM_DEFAULT_THREADER && !defined SM_MAIN_THREADER
|
||||
#define SM_MAIN_THREADER WinThreader;
|
||||
typedef class WinThreader MainThreader;
|
||||
#endif
|
||||
|
||||
#endif //_INCLUDE_WINTHREADS_H_
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@ -273,7 +273,9 @@ namespace SourceMod
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Describes a simple "condition variable"/signal lock.
|
||||
* @brief Object that can be used to signal from one thread to another.
|
||||
* This should not be used and is deprecated. Use C++11
|
||||
* std::condition_variable instead, as this version is fundamentally racy.
|
||||
*/
|
||||
class IEventSignal
|
||||
{
|
||||
@ -286,7 +288,7 @@ namespace SourceMod
|
||||
*/
|
||||
virtual void Wait() =0;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Triggers the signal and resets the signal after triggering.
|
||||
*/
|
||||
virtual void Signal() =0;
|
||||
@ -326,7 +328,7 @@ namespace SourceMod
|
||||
* @return Number of tasks processed.
|
||||
*/
|
||||
virtual unsigned int RunFrame() =0;
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Pauses the worker.
|
||||
*
|
||||
@ -446,9 +448,9 @@ namespace SourceMod
|
||||
virtual void ThreadSleep(unsigned int ms) =0;
|
||||
|
||||
/**
|
||||
* @brief Creates a non-signalled event.
|
||||
* @brief Deprecated; do not use.
|
||||
*
|
||||
* @return A new IEventSignal pointer (must be destroyed).
|
||||
* @return Returns a new IEventSignal.
|
||||
*/
|
||||
virtual IEventSignal *MakeEventSignal() =0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user