Merge pull request #1266 from alliedmodders/threads-3
Pare down ThreadSupport and remove ancient thread code.
This commit is contained in:
commit
15023777f4
128
.travis.yml
128
.travis.yml
@ -3,110 +3,80 @@ git:
|
|||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
language: cpp
|
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:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
- os: linux
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
sudo: false
|
sudo: false
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
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:
|
cache:
|
||||||
directories: ['../mysql-5.0']
|
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
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
sudo: false
|
sudo: false
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
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:
|
cache:
|
||||||
directories: ['../mysql-5.0']
|
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
|
- os: linux
|
||||||
|
dist: bionic
|
||||||
sudo: false
|
sudo: false
|
||||||
language: cpp
|
language: cpp
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['llvm-toolchain-trusty-4.0']
|
packages: ['lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev:i386', 'g++-multilib', 'clang']
|
||||||
packages: ['clang-4.0', 'lib32stdc++6', 'lib32z1-dev', 'libc6-dev-i386', 'linux-libc-dev', 'g++-multilib']
|
|
||||||
cache:
|
cache:
|
||||||
directories: ['../mysql-5.0']
|
directories: ['../mysql-5.0']
|
||||||
env: ['MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0"']
|
env:
|
||||||
|
- MATRIX_EVAL="CC=clang && CXX=clang++"
|
||||||
- os: linux
|
- SDKS=csgo
|
||||||
sudo: false
|
- MODE=optimize
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR
|
- CHECKOUT_DIR=$PWD && cd .. && $CHECKOUT_DIR/tools/checkout-deps.sh && cd $CHECKOUT_DIR
|
||||||
@ -114,5 +84,7 @@ script:
|
|||||||
- mkdir build && cd build
|
- mkdir build && cd build
|
||||||
- PATH="~/.local/bin:$PATH"
|
- PATH="~/.local/bin:$PATH"
|
||||||
- eval "${MATRIX_EVAL}"
|
- 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
|
- ambuild
|
||||||
|
@ -281,8 +281,13 @@ class SMConfig(object):
|
|||||||
'-msse',
|
'-msse',
|
||||||
'-fvisibility=hidden',
|
'-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 += [
|
cxx.cxxflags += [
|
||||||
'-std=c++11',
|
|
||||||
'-fno-exceptions',
|
'-fno-exceptions',
|
||||||
'-fno-threadsafe-statics',
|
'-fno-threadsafe-statics',
|
||||||
'-Wno-non-virtual-dtor',
|
'-Wno-non-virtual-dtor',
|
||||||
@ -292,11 +297,11 @@ class SMConfig(object):
|
|||||||
|
|
||||||
have_gcc = cxx.family == 'gcc'
|
have_gcc = cxx.family == 'gcc'
|
||||||
have_clang = cxx.family == 'clang'
|
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']
|
cxx.cxxflags += ['-Wno-expansion-to-defined']
|
||||||
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
||||||
cxx.cflags += ['-Wno-varargs']
|
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']
|
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
||||||
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
||||||
cxx.cxxflags += ['-Wno-null-dereference']
|
cxx.cxxflags += ['-Wno-null-dereference']
|
||||||
@ -316,6 +321,13 @@ class SMConfig(object):
|
|||||||
cxx.cxxflags += ['-Wno-deprecated']
|
cxx.cxxflags += ['-Wno-deprecated']
|
||||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
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:
|
if have_gcc:
|
||||||
cxx.cflags += ['-mfpmath=sse']
|
cxx.cflags += ['-mfpmath=sse']
|
||||||
cxx.cflags += ['-Wno-maybe-uninitialized']
|
cxx.cflags += ['-Wno-maybe-uninitialized']
|
||||||
@ -379,16 +391,16 @@ class SMConfig(object):
|
|||||||
cxx.linkflags += ['-static-libgcc']
|
cxx.linkflags += ['-static-libgcc']
|
||||||
elif cxx.family == 'clang':
|
elif cxx.family == 'clang':
|
||||||
cxx.linkflags += ['-lgcc_eh']
|
cxx.linkflags += ['-lgcc_eh']
|
||||||
|
cxx.linkflags += ['-static-libstdc++']
|
||||||
|
|
||||||
def configure_mac(self, cxx):
|
def configure_mac(self, cxx):
|
||||||
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
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 += [
|
cxx.linkflags += [
|
||||||
'-mmacosx-version-min=10.5',
|
'-mmacosx-version-min=10.7',
|
||||||
'-lstdc++',
|
'-stdlib=libc++',
|
||||||
'-stdlib=libstdc++',
|
|
||||||
]
|
]
|
||||||
cxx.cxxflags += ['-stdlib=libstdc++']
|
cxx.cxxflags += ['-stdlib=libc++']
|
||||||
|
|
||||||
def configure_windows(self, cxx):
|
def configure_windows(self, cxx):
|
||||||
cxx.defines += ['WIN32', '_WINDOWS']
|
cxx.defines += ['WIN32', '_WINDOWS']
|
||||||
@ -538,9 +550,11 @@ class SMConfig(object):
|
|||||||
if builder.target.platform in ['linux', 'mac']:
|
if builder.target.platform in ['linux', 'mac']:
|
||||||
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
||||||
|
|
||||||
if sdk.name in ['csgo', 'blade'] and builder.target.platform == 'linux':
|
if builder.target.platform == 'linux':
|
||||||
compiler.linkflags += ['-lstdc++']
|
if sdk.name in ['csgo', 'blade']:
|
||||||
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
compiler.linkflags.remove('-static-libstdc++')
|
||||||
|
compiler.linkflags += ['-lstdc++']
|
||||||
|
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||||
|
@ -35,8 +35,7 @@ for arch in SM.archs:
|
|||||||
'smn_maplists.cpp',
|
'smn_maplists.cpp',
|
||||||
'ADTFactory.cpp',
|
'ADTFactory.cpp',
|
||||||
'smn_adt_stack.cpp',
|
'smn_adt_stack.cpp',
|
||||||
'thread/ThreadWorker.cpp',
|
'BaseWorker.cpp',
|
||||||
'thread/BaseWorker.cpp',
|
|
||||||
'ThreadSupport.cpp',
|
'ThreadSupport.cpp',
|
||||||
'smn_float.cpp',
|
'smn_float.cpp',
|
||||||
'TextParsers.cpp',
|
'TextParsers.cpp',
|
||||||
@ -90,9 +89,4 @@ for arch in SM.archs:
|
|||||||
if arch == 'x64':
|
if arch == 'x64':
|
||||||
binary.sources += ['PseudoAddrManager.cpp']
|
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)]
|
SM.binaries += [builder.Add(binary)]
|
||||||
|
@ -43,6 +43,7 @@ class BaseWorker;
|
|||||||
class SWThreadHandle : public IThreadHandle
|
class SWThreadHandle : public IThreadHandle
|
||||||
{
|
{
|
||||||
friend class BaseWorker;
|
friend class BaseWorker;
|
||||||
|
friend class CompatWorker;
|
||||||
public:
|
public:
|
||||||
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
||||||
IThread *GetThread();
|
IThread *GetThread();
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 sw=4 :
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod
|
* SourceMod
|
||||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
@ -29,17 +29,515 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
#include <sm_platform.h>
|
#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 "ThreadSupport.h"
|
||||||
#include "common_logic.h"
|
#include "common_logic.h"
|
||||||
|
|
||||||
#if defined PLATFORM_POSIX
|
static constexpr unsigned int DEFAULT_THINK_TIME_MS = 20;
|
||||||
#include "thread/PosixThreads.h"
|
|
||||||
#elif defined PLATFORM_WINDOWS
|
|
||||||
#include "thread/WinThreads.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MainThreader g_MainThreader;
|
class CompatWorker final : public IThreadWorker
|
||||||
IThreader *g_pThreader = &g_MainThreader;
|
{
|
||||||
|
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
|
class RegThreadStuff : public SMGlobalClass
|
||||||
{
|
{
|
||||||
|
@ -32,49 +32,14 @@
|
|||||||
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <IThreader.h>
|
#include <IThreader.h>
|
||||||
#include <am-thread-utils.h>
|
#include <am-thread-utils.h>
|
||||||
#include <am-utility.h>
|
#include <am-utility.h>
|
||||||
|
|
||||||
using namespace SourceMod;
|
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;
|
extern IThreader *g_pThreader;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
#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
|
* SourceMod
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* 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
|
class IEventSignal
|
||||||
{
|
{
|
||||||
@ -326,7 +328,7 @@ namespace SourceMod
|
|||||||
* @return Number of tasks processed.
|
* @return Number of tasks processed.
|
||||||
*/
|
*/
|
||||||
virtual unsigned int RunFrame() =0;
|
virtual unsigned int RunFrame() =0;
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* @brief Pauses the worker.
|
* @brief Pauses the worker.
|
||||||
*
|
*
|
||||||
@ -446,9 +448,9 @@ namespace SourceMod
|
|||||||
virtual void ThreadSleep(unsigned int ms) =0;
|
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;
|
virtual IEventSignal *MakeEventSignal() =0;
|
||||||
|
|
||||||
|
2
tools/checkout-deps.sh
vendored
2
tools/checkout-deps.sh
vendored
@ -136,7 +136,7 @@ if [ $? -eq 1 ]; then
|
|||||||
checkout
|
checkout
|
||||||
|
|
||||||
cd ambuild
|
cd ambuild
|
||||||
if [ $iswin -eq 1 ]; then
|
if [ $iswin -eq 1 ] || [ $ismac -eq 1 ]; then
|
||||||
python setup.py install
|
python setup.py install
|
||||||
else
|
else
|
||||||
python setup.py build
|
python setup.py build
|
||||||
|
Loading…
Reference in New Issue
Block a user