diff --git a/.travis.yml b/.travis.yml index 83c5b2cf..8459a9df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,110 +3,80 @@ git: sudo: false language: cpp -os: linux -dist: trusty -addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.9 - - llvm-toolchain-trusty-4.0 - - llvm-toolchain-trusty-5.0 - packages: - - lib32stdc++6 - - lib32z1-dev - - libc6-dev-i386 - - linux-libc-dev - - g++-multilib -# - clang-3.6 -# - clang-3.8 -# - clang-4.0 -# - clang-5.0 -# - g++-6 -# - g++-6-multilib - - clang-3.9 - - g++-4.8-multilib - - g++-4.8 - - g++-4.9-multilib - - g++-4.9 - - g++-5-multilib - - g++-5 - - g++-7-multilib - - g++-7 - cache: - directories: - - ../mysql-5.0 -env: - - MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" - - MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8" - - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" - - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" - - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" matrix: fast_finish: true include: - os: linux + dist: trusty sudo: false language: cpp addons: apt: - packages: ['clang-3.6', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] + sources: + - ubuntu-toolchain-r-test + packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib'] cache: directories: ['../mysql-5.0'] - env: ['MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6"'] + env: + - MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + - SDKS=episode1,css,tf2,l4d2,csgo,dota + - MODE=optimize - os: linux + dist: trusty sudo: false language: cpp addons: apt: - packages: ['clang-3.8', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] + sources: + - ubuntu-toolchain-r-test + packages: ['clang-3.4', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-4.9-multilib'] cache: directories: ['../mysql-5.0'] - env: ['MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8"'] + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - SDKS=episode1,css,tf2,l4d2,csgo,dota + - MODE=optimize + - os: osx + osx_image: xcode7.2 + language: cpp + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - SDKS=episode1,css,tf2,l4d2,csgo,dota + - MODE=optimize + + # # This is a faster test for the latest g++. + # - os: linux + # dist: bionic + # sudo: false + # language: cpp + # addons: + # apt: + # packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'g++'] + # cache: + # directories: ['../mysql-5.0'] + # env: + # - MATRIX_EVAL="CC=gcc && CXX=g++" + # - SDKS=csgo + # # GCC currently fails in opt builds trying to inline stuff in sqlite3.c. + # - MODE=debug + + # This is a faster test for the latest clang. - os: linux + dist: bionic sudo: false language: cpp addons: apt: - sources: ['llvm-toolchain-trusty-4.0'] - packages: ['clang-4.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] + packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'clang'] cache: directories: ['../mysql-5.0'] - env: ['MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0"'] - - - os: linux - sudo: false - language: cpp - addons: - apt: - sources: ['llvm-toolchain-trusty-5.0'] - packages: ['clang-5.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] - cache: - directories: ['../mysql-5.0'] - env: ['MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0"'] - - - os: linux - sudo: false - language: cpp - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['g++-6', 'g++-6-multilib', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib'] - cache: - directories: ['../mysql-5.0'] - env: ['MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"'] - - allow_failures: - - env: MATRIX_EVAL="CC=clang-3.7 && CXX=clang++-3.7" - - env: MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" - - env: MATRIX_EVAL="CC=gcc-4.8 && CXX=g++-4.8" - - env: MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" - - env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" - - env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + - SDKS=csgo + - MODE=optimize before_script: - CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR @@ -114,5 +84,7 @@ script: - mkdir build && cd build - PATH="~/.local/bin:$PATH" - eval "${MATRIX_EVAL}" - - python ../configure.py --enable-optimize --sdks=episode1,css,tf2,l4d2,csgo,dota + - eval "${CC} --version" + - eval "${CXX} --version" + - python ../configure.py --enable-${MODE} --sdks=${SDKS} - ambuild diff --git a/AMBuildScript b/AMBuildScript index 9e52a273..5d0fb201 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -281,8 +281,13 @@ class SMConfig(object): '-msse', '-fvisibility=hidden', ] + + if cxx.version == 'apple-clang-6.0' or cxx.version == 'clang-3.4': + 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', @@ -292,11 +297,11 @@ class SMConfig(object): have_gcc = cxx.family == 'gcc' have_clang = cxx.family == 'clang' - if cxx.version >= 'clang-3.9': + if cxx.version >= 'clang-3.9' or cxx.version == 'clang-3.4' or cxx.version > 'apple-clang-6.0': cxx.cxxflags += ['-Wno-expansion-to-defined'] if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0': cxx.cflags += ['-Wno-varargs'] - if cxx.version >= 'clang-3.6' or cxx.version >= 'apple-clang-7.0': + if cxx.version >= 'clang-3.4' or cxx.version >= 'apple-clang-7.0': cxx.cxxflags += ['-Wno-inconsistent-missing-override'] if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0': cxx.cxxflags += ['-Wno-null-dereference'] @@ -316,6 +321,13 @@ class SMConfig(object): cxx.cxxflags += ['-Wno-deprecated'] cxx.cflags += ['-Wno-sometimes-uninitialized'] + # Work around SDK warnings. + if cxx.version >= 'clang-10.0': + cxx.cflags += [ + '-Wno-implicit-int-float-conversion', + '-Wno-tautological-overlap-compare', + ] + if have_gcc: cxx.cflags += ['-mfpmath=sse'] cxx.cflags += ['-Wno-maybe-uninitialized'] @@ -379,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'] @@ -538,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)] diff --git a/core/logic/AMBuilder b/core/logic/AMBuilder index 1415faa4..fa3117eb 100644 --- a/core/logic/AMBuilder +++ b/core/logic/AMBuilder @@ -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)] diff --git a/core/logic/thread/BaseWorker.cpp b/core/logic/BaseWorker.cpp similarity index 100% rename from core/logic/thread/BaseWorker.cpp rename to core/logic/BaseWorker.cpp diff --git a/core/logic/thread/BaseWorker.h b/core/logic/BaseWorker.h similarity index 96% rename from core/logic/thread/BaseWorker.h rename to core/logic/BaseWorker.h index 0feceb5f..5e87ed63 100644 --- a/core/logic/thread/BaseWorker.h +++ b/core/logic/BaseWorker.h @@ -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(); diff --git a/core/logic/ThreadSupport.cpp b/core/logic/ThreadSupport.cpp index 55fd0327..1c4a35c5 100644 --- a/core/logic/ThreadSupport.cpp +++ b/core/logic/ThreadSupport.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#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* lock, SWThreadHandle* handle); + + private: + IThreadWorkerCallbacks* callbacks_; + WorkerState state_; + std::mutex mutex_; + std::condition_variable work_cv_; + ke::Deque work_; + std::unique_ptr thread_; + std::atomic jobs_per_wakeup_; + std::atomic 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 lock(mutex_); + if (state_ != Worker_Stopped) + return false; + + thread_ = std::make_unique([this]() -> void { + Worker(); + }); + state_ = Worker_Running; + return true; +} + +bool CompatWorker::Stop(bool) +{ + { + std::lock_guard 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 lock(mutex_); + if (state_ != Worker_Running) + return false; + + state_ = Worker_Paused; + work_cv_.notify_all(); + return true; +} + +bool CompatWorker::Unpause() +{ + std::lock_guard 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 lock(mutex_); + + if (callbacks_) { + lock.unlock(); + callbacks_->OnWorkerStart(this); + lock.lock(); + } + + typedef std::chrono::system_clock Clock; + typedef std::chrono::time_point TimePoint; + + auto can_work = [this]() -> bool { + return state_ == Worker_Running && !work_.empty(); + }; + + ke::Maybe 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 lock(mutex_); + if (work_.empty()) + break; + handle = work_.popFrontCopy(); + } + + RunWork(handle); + nprocessed++; + } + return nprocessed; +} + +void CompatWorker::RunWorkLocked(std::unique_lock* 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 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 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 thread_; + std::mutex mutex_; + std::condition_variable check_cv_; + std::atomic finished_; +}; + +CompatThread::CompatThread(IThread* callbacks, const ThreadParams* params) + : callbacks_(callbacks), + params_(*params) +{ + if (!(params_.flags & Thread_CreateSuspended)) + Unpause(); +} + +bool CompatThread::Unpause() +{ + std::unique_lock lock(mutex_); + if (thread_) + return false; + + thread_ = std::make_unique([this]() -> void { + Run(); + }); + + return true; +} + +void CompatThread::Run() +{ + // Create an ordering between when the thread runs and when thread_ is assigned. + std::unique_lock 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 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 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 lock(mutex_); + cv_.wait(lock); + } + void Signal() override { + std::lock_guard 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 { diff --git a/core/logic/ThreadSupport.h b/core/logic/ThreadSupport.h index 907c1d3f..4246f20f 100644 --- a/core/logic/ThreadSupport.h +++ b/core/logic/ThreadSupport.h @@ -32,49 +32,14 @@ #ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H #define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H +#include + #include #include #include 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 diff --git a/core/logic/thread/PosixThreads.cpp b/core/logic/thread/PosixThreads.cpp deleted file mode 100644 index 4932962a..00000000 --- a/core/logic/thread/PosixThreads.cpp +++ /dev/null @@ -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 . - * - * 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 . - * - * Version: $Id$ - */ - -#include -#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; -} - diff --git a/core/logic/thread/PosixThreads.h b/core/logic/thread/PosixThreads.h deleted file mode 100644 index 764994f9..00000000 --- a/core/logic/thread/PosixThreads.h +++ /dev/null @@ -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 . - * - * 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 . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_POSIXTHREADS_H_ -#define _INCLUDE_POSIXTHREADS_H_ - -#include -#include -#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 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_ diff --git a/core/logic/thread/ThreadWorker.cpp b/core/logic/thread/ThreadWorker.cpp deleted file mode 100644 index 20ce55e3..00000000 --- a/core/logic/thread/ThreadWorker.cpp +++ /dev/null @@ -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 . - * - * 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 . - * - * 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; -} diff --git a/core/logic/thread/ThreadWorker.h b/core/logic/thread/ThreadWorker.h deleted file mode 100644 index dd45f76f..00000000 --- a/core/logic/thread/ThreadWorker.h +++ /dev/null @@ -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 . - * - * 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 . - * - * 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 diff --git a/core/logic/thread/WinThreads.cpp b/core/logic/thread/WinThreads.cpp deleted file mode 100644 index 79cb142e..00000000 --- a/core/logic/thread/WinThreads.cpp +++ /dev/null @@ -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 . - * - * 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 . - * - * 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; -} diff --git a/core/logic/thread/WinThreads.h b/core/logic/thread/WinThreads.h deleted file mode 100644 index 63916fa4..00000000 --- a/core/logic/thread/WinThreads.h +++ /dev/null @@ -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 . - * - * 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 . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_WINTHREADS_H_ -#define _INCLUDE_WINTHREADS_H_ - -#include -#include -#include -#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 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_ diff --git a/public/IThreader.h b/public/IThreader.h index ed9cb1ae..5953bd27 100644 --- a/public/IThreader.h +++ b/public/IThreader.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; diff --git a/tools/checkout-deps.sh b/tools/checkout-deps.sh index d2b10332..e1d93451 100755 --- a/tools/checkout-deps.sh +++ b/tools/checkout-deps.sh @@ -136,7 +136,7 @@ if [ $? -eq 1 ]; then checkout cd ambuild - if [ $iswin -eq 1 ]; then + if [ $iswin -eq 1 ] || [ $ismac -eq 1 ]; then python setup.py install else python setup.py build