mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Worker basic prototype implementation.
This commit is contained in:
parent
cd506d4814
commit
be0e5bd6d2
@ -46,6 +46,7 @@ extern void TerminatePrivileges();
|
||||
extern void TerminateRoutines();
|
||||
extern void TerminateCommands();
|
||||
extern void TerminateSignals();
|
||||
extern void TerminateWorkers();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern Buffer GetRealFilePath(CSStr path);
|
||||
@ -496,6 +497,8 @@ void Core::Terminate(bool shutdown)
|
||||
TerminateAreas();
|
||||
// Release privilege managers
|
||||
TerminatePrivileges();
|
||||
// Terminate workers
|
||||
TerminateWorkers();
|
||||
// In case there's a payload for reload
|
||||
m_ReloadPayload.Release();
|
||||
// Release null objects in case any reference to valid objects is stored in them
|
||||
|
@ -4,10 +4,438 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMODE_DECL_TYPENAME(SqWorker, _SC("SqWorker"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Worker::Container Worker::sm_Workers{};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(CCStr str)
|
||||
: Parameter()
|
||||
{
|
||||
// Make sure there's a string
|
||||
if (str)
|
||||
{
|
||||
mSize = static_cast< uint32_t >(std::strlen(str));
|
||||
mString = new SQChar[mSize+1];
|
||||
std::strcpy(mString, str);
|
||||
}
|
||||
// Even an empty string should still be marked as a string
|
||||
mType = T_STRING;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(CCStr str, size_t len)
|
||||
: Parameter()
|
||||
{
|
||||
// Make sure there's a string
|
||||
if (str && len)
|
||||
{
|
||||
mSize = ConvTo< uint32_t >::From(len);
|
||||
mString = new SQChar[mSize+1];
|
||||
std::strncpy(mString, str, mSize);
|
||||
mString[mSize] = '\0'; // Null terminator
|
||||
}
|
||||
// Even an empty string should still be marked as a string
|
||||
mType = T_STRING;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(ArrayType && v)
|
||||
: mType(T_ARRAY), mSize(static_cast< uint32_t >(v.size()))
|
||||
, mArray(new ArrayType(std::forward< ArrayType >(v)))
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(const ArrayType & v)
|
||||
: mType(T_ARRAY), mSize(static_cast< uint32_t >(v.size()))
|
||||
, mArray(new ArrayType(v))
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(TableType && v)
|
||||
: mType(T_ARRAY), mSize(static_cast< uint32_t >(v.size()))
|
||||
, mTable(new TableType(std::forward< TableType >(v)))
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(const TableType & v)
|
||||
: mType(T_ARRAY), mSize(static_cast< uint32_t >(v.size()))
|
||||
, mTable(new TableType(v))
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(const Parameter & o)
|
||||
: mType(o.mType), mSize(o.mSize), mData(o.mData)
|
||||
{
|
||||
// Identify the type to be copied
|
||||
switch (mType)
|
||||
{
|
||||
// Fundamental types can be copied bit-wise (which we did)
|
||||
case T_NULL:
|
||||
case T_INT:
|
||||
case T_BOOL:
|
||||
case T_FLOAT: break;
|
||||
case T_STRING:
|
||||
if (mSize)
|
||||
{
|
||||
mString = new SQChar[mSize];
|
||||
std::strncpy(mString, o.mString, mSize);
|
||||
mString[mSize] = '\0'; // Null terminator
|
||||
}
|
||||
else
|
||||
{
|
||||
mString = nullptr; // Empty string?
|
||||
}
|
||||
break;
|
||||
case T_ARRAY:
|
||||
mArray = o.mArray ? new ArrayType(*o.mArray) : nullptr;
|
||||
break;
|
||||
case T_TABLE:
|
||||
mTable = o.mTable ? new TableType(*o.mTable) : nullptr;
|
||||
break;
|
||||
// How did we get here?
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Parameter::Parameter(Parameter && o)
|
||||
: mType(o.mType), mSize(o.mSize), mData(o.mData)
|
||||
{
|
||||
o.Discard(); // Take ownership
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Parameter::operator == (const Parameter & o) const noexcept
|
||||
{
|
||||
// If they're not the same type then there's no point in comparing
|
||||
if (mType != o.mType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Identify which type to compare
|
||||
switch (mType)
|
||||
{
|
||||
// Null is same regardless
|
||||
case T_NULL: return true;
|
||||
// Boolean is stored as integer
|
||||
case T_INT:
|
||||
case T_BOOL: return (mInt == o.mInt);
|
||||
// Take into account precision errors
|
||||
case T_FLOAT: return EpsEq(mFloat, o.mFloat);
|
||||
case T_STRING:
|
||||
// Only perform a comparison if there's actually a string to compare
|
||||
if (mSize && mSize == o.mSize)
|
||||
{
|
||||
return std::strncmp(mString, o.mString, mSize) == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // If they're not the same size then they can't be the same
|
||||
}
|
||||
// For table or arrays we only test if they're the same rather then each value individually
|
||||
case T_ARRAY: return (mArray == o.mArray);
|
||||
case T_TABLE: return (mTable == o.mTable);
|
||||
// How did we get here?
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parameter::Assign(const Parameter & o)
|
||||
{
|
||||
// Avoid self assignment
|
||||
if (this == &o) return;
|
||||
/* We could probably optimize this by reusing current container memory.
|
||||
* But chances are we would complicate code for the simpler case.
|
||||
* And the simpler case is likely to be the more common scenario.
|
||||
*/
|
||||
// Discard current information
|
||||
Clear();
|
||||
// The size and type are copied bit-wise
|
||||
mType = o.mType;
|
||||
mSize = o.mSize;
|
||||
// Identify the type to be copied
|
||||
switch (mType)
|
||||
{
|
||||
// Fundamental types can be copied bit-wise
|
||||
case T_NULL:
|
||||
case T_INT:
|
||||
case T_BOOL:
|
||||
case T_FLOAT:
|
||||
mData = o.mData;
|
||||
break;
|
||||
// Strings require memory to be allocated
|
||||
case T_STRING:
|
||||
if (mSize)
|
||||
{
|
||||
mString = new SQChar[mSize];
|
||||
std::strncpy(mString, o.mString, mSize);
|
||||
mString[mSize] = '\0'; // Null terminator
|
||||
}
|
||||
else
|
||||
{
|
||||
mString = nullptr; // Empty string?
|
||||
}
|
||||
break;
|
||||
case T_ARRAY:
|
||||
mArray = o.mArray ? new ArrayType(*o.mArray) : nullptr;
|
||||
break;
|
||||
case T_TABLE:
|
||||
mTable = o.mTable ? new TableType(*o.mTable) : nullptr;
|
||||
break;
|
||||
// How did we get here?
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parameter::Assign(Parameter && o)
|
||||
{
|
||||
// Avoid self assignment
|
||||
if (this == &o) return;
|
||||
// Discard current information
|
||||
Clear();
|
||||
// We don't care about the type since we take ownership
|
||||
mType = o.mType;
|
||||
mSize = o.mSize;
|
||||
mData = o.mData;
|
||||
// Take ownership
|
||||
o.Discard();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parameter::Clear()
|
||||
{
|
||||
switch (mType)
|
||||
{
|
||||
case T_STRING: delete[] mString; break;
|
||||
case T_ARRAY: delete mArray; break;
|
||||
case T_TABLE: delete mTable; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Thread::Thread( Worker * worker)
|
||||
: mWorker(worker)
|
||||
, mObject(worker)
|
||||
, mThread(&Worker::Start, worker)
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Thread::Thread(Thread && o) noexcept
|
||||
: mWorker(o.mWorker)
|
||||
, mObject(std::forward< LightObj >(o.mObject))
|
||||
, mThread(std::forward< std::thread >(o.mThread))
|
||||
{
|
||||
o.mWorker = nullptr;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Worker::Worker(SQInteger stack, String && str, size_t h)
|
||||
: m_PendingJobs(4096), m_FinishedJobs(4096)
|
||||
, m_Running()
|
||||
, m_VM(nullptr)
|
||||
, m_Mutex()
|
||||
, m_Hash(h)
|
||||
, m_Name(std::forward< String >(str))
|
||||
, m_StackSize(stack)
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Worker::~Worker()
|
||||
{
|
||||
// Instruct the thread to stop whenever possible
|
||||
Stop();
|
||||
// Locate our self in the list
|
||||
std::unique_ptr< Thread > & t = sm_Workers[m_Hash];
|
||||
// Wait for the thread to finish
|
||||
if (t->mThread.joinable())
|
||||
{
|
||||
t->mThread.join();
|
||||
}
|
||||
// Remove ourselves from the list
|
||||
sm_Workers.erase(m_Hash);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Worker::Terminate()
|
||||
{
|
||||
// Attempt to stop workers
|
||||
for (auto & t : sm_Workers)
|
||||
{
|
||||
// Tell the thread to stop as soon as it can
|
||||
t.second->mWorker->Stop();
|
||||
// Wait for it to stop
|
||||
if (t.second->mThread.joinable())
|
||||
{
|
||||
t.second->mThread.join();
|
||||
}
|
||||
}
|
||||
// Simply get rid of them
|
||||
sm_Workers.clear();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Worker::Process(size_t jobs)
|
||||
{
|
||||
std::vector< Worker * > workers;
|
||||
workers.reserve(sm_Workers.size());
|
||||
for (auto & t : sm_Workers)
|
||||
{
|
||||
workers.push_back(t.second->mWorker);
|
||||
}
|
||||
for (auto & t : workers)
|
||||
{
|
||||
for (size_t n = 0; n < jobs; ++n)
|
||||
{
|
||||
std::unique_ptr< Job > job;
|
||||
// Try to get a job from the queue
|
||||
if (!t->m_FinishedJobs.try_dequeue(job))
|
||||
{
|
||||
break; // No jobs
|
||||
}
|
||||
// Does it have a callback?
|
||||
if (!job->mCallback.IsNull())
|
||||
{
|
||||
job->mCallback.Execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj Worker::Create(SQInteger stack, StackStrF & str)
|
||||
{
|
||||
HSQUIRRELVM vm = SqVM();
|
||||
// Make sure there's a name
|
||||
if (str.mLen <= 0)
|
||||
{
|
||||
STHROWF("Invalid or empty worker name");
|
||||
}
|
||||
// Extract the worker name
|
||||
String name(str.mPtr, static_cast< size_t >(str.mLen));
|
||||
// Create the name hash
|
||||
size_t name_hash = std::hash< String >{}(name);
|
||||
// Make sure this worker doesn't exist
|
||||
if (sm_Workers.exists(name_hash))
|
||||
{
|
||||
STHROWF("Worker already exists");
|
||||
}
|
||||
// Attempt to create a routine instance
|
||||
DeleteGuard< Worker > dg(new Worker(stack, std::move(name), name_hash));
|
||||
ClassType< Worker >::PushInstance(vm, dg.Get());
|
||||
Worker * worker = dg.Grab();
|
||||
// Create the worker thread
|
||||
std::unique_ptr< Thread > & th = sm_Workers.emplace_back(name_hash, new Thread{worker});
|
||||
// Return the worker object
|
||||
return th->mObject;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Worker::Start()
|
||||
{
|
||||
// Initialize
|
||||
{
|
||||
// Acquire exclusive access to this instance
|
||||
std::lock_guard< std::mutex > lg(m_Mutex);
|
||||
// This should never be the case but why not
|
||||
if (m_VM)
|
||||
{
|
||||
STHROWF("Worker was already started.");
|
||||
}
|
||||
// Create the JS state
|
||||
m_VM = sq_open(m_StackSize);
|
||||
// Tell the VM to use these functions to output user on error messages
|
||||
sq_setprintfunc(m_VM, PrintFunc, ErrorFunc);
|
||||
// This is now running
|
||||
m_Running.test_and_set();
|
||||
}
|
||||
// Process
|
||||
while (m_Running.test_and_set())
|
||||
{
|
||||
// Acquire exclusive access to this instance
|
||||
std::lock_guard< std::mutex > lg(m_Mutex);
|
||||
// Do the actual processing
|
||||
Work();
|
||||
}
|
||||
// Cleanup
|
||||
{
|
||||
// Acquire exclusive access to this instance
|
||||
std::lock_guard< std::mutex > lg(m_Mutex);
|
||||
// We're out of the process loop
|
||||
sq_close(m_VM);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Worker::Work()
|
||||
{
|
||||
std::unique_ptr< Job > job;
|
||||
// Try to get a job from the queue
|
||||
if (!m_PendingJobs.try_dequeue(job))
|
||||
{
|
||||
return; // No jobs
|
||||
}
|
||||
// Identify the job type
|
||||
switch (job->mType)
|
||||
{
|
||||
// This type of job demands no work
|
||||
case Job::Type::Null: break;
|
||||
case Job::Type::Stop:
|
||||
|
||||
break;
|
||||
case Job::Type::Eval:
|
||||
sq_compilebuffer(m_VM, job->mPayload.data(), job->mPayload.size(), nullptr, SQFalse);
|
||||
break;
|
||||
case Job::Type::Exec:
|
||||
|
||||
break;
|
||||
// We're not qualified for this job
|
||||
default: break;
|
||||
}
|
||||
// This job was finished
|
||||
m_FinishedJobs.enqueue(std::move(job));
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Worker::PrintFunc(HSQUIRRELVM /*vm*/, CSStr msg, ...)
|
||||
{
|
||||
// Initialize the variable argument list
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
// Forward the message to the logger
|
||||
std::vprintf(msg, args);
|
||||
// Finalize the variable argument list
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Worker::ErrorFunc(HSQUIRRELVM /*vm*/, CSStr msg, ...)
|
||||
{
|
||||
// Initialize the variable argument list
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
// Tell the logger to display debugging information
|
||||
std::vprintf(msg, args);
|
||||
// Finalize the variable argument list
|
||||
va_end(args);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TerminateWorkers()
|
||||
{
|
||||
Worker::Terminate();
|
||||
}
|
||||
// ================================================================================================
|
||||
void Register_Worker(HSQUIRRELVM vm)
|
||||
{
|
||||
Table thns(vm);
|
||||
|
||||
thns.Bind(_SC("Worker"),
|
||||
Class< Worker, NoConstructor< Worker > >(vm, SqWorker::Str)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqWorker::Fn)
|
||||
// Properties
|
||||
.Prop(_SC("Name"), &Worker::GetName)
|
||||
// Core Methods
|
||||
.CbFunc(_SC("Evaluate"), &Worker::Evaluate)
|
||||
// Static Member Methods
|
||||
);
|
||||
|
||||
thns.FmtFunc(_SC("Process"), &Worker::Process);
|
||||
thns.FmtFunc(_SC("Create"), &Worker::Create);
|
||||
|
||||
RootTable(vm).Bind(_SC("SqThread"), thns);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
@ -2,5 +2,532 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Base/Shared.hpp"
|
||||
#include "Base/VecMap.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <condition_variable>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <concurrentqueue.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
using namespace moodycamel;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct Worker;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Used to transmit values between workers in a language agnostic way.
|
||||
*/
|
||||
struct Parameter
|
||||
{
|
||||
enum
|
||||
{
|
||||
T_NULL=0, // Null/undefined type.
|
||||
T_INT, // Integer type.
|
||||
T_BOOL, // Boolean type.
|
||||
T_FLOAT, // Floating point type.
|
||||
T_STRING, // String type.
|
||||
T_ARRAY, // Array type.
|
||||
T_TABLE // Table type.
|
||||
};
|
||||
// --------------------------------------------------------------------------------------------
|
||||
using ArrayType = std::vector< Parameter >; // Parameter array.
|
||||
using TableType = VecMap< Parameter, Parameter >; // Parameter table.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
uint32_t mType; // Type of value stored in the parameter.
|
||||
uint32_t mSize; // Container size. Mostly used for the string because there's space from padding.
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
union {
|
||||
int64_t mInt; // Parameter value represented as integer.
|
||||
uint64_t mData; // Parameter value represented as raw bits.
|
||||
double mFloat; // Parameter value represented as floating point.
|
||||
CStr mString; // Parameter value represented as string pointer.
|
||||
ArrayType * mArray; // Parameter value represented as array pointer.
|
||||
TableType * mTable; // Parameter value represented as table pointer.
|
||||
};
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor (null).
|
||||
*/
|
||||
Parameter() noexcept
|
||||
: Parameter(nullptr)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Null constructor.
|
||||
*/
|
||||
explicit Parameter(std::nullptr_t)
|
||||
: mType(T_NULL), mSize(0), mData(0ull)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(int8_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(uint8_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(int16_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(uint16_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(int32_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(uint32_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(int64_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Integer constructor.
|
||||
*/
|
||||
explicit Parameter(uint64_t v)
|
||||
: mType(T_INT), mSize(sizeof(v)), mInt(static_cast< int64_t >(v))
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Boolean constructor.
|
||||
*/
|
||||
explicit Parameter(bool SQ_UNUSED_ARG(v)) //static analyzer shat the bed
|
||||
: mType(T_BOOL), mSize(1), mInt(v ? 1 : 0)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Floating point constructor.
|
||||
*/
|
||||
explicit Parameter(float v)
|
||||
: mType(T_FLOAT), mSize(sizeof(v)), mFloat(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Floating point constructor.
|
||||
*/
|
||||
explicit Parameter(double v)
|
||||
: mType(T_FLOAT), mSize(sizeof(v)), mFloat(v)
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* String constructor.
|
||||
*/
|
||||
explicit Parameter(CCStr str);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* String constructor.
|
||||
*/
|
||||
explicit Parameter(CCStr str, size_t len);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Array constructor.
|
||||
*/
|
||||
explicit Parameter(ArrayType && v);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Array constructor.
|
||||
*/
|
||||
explicit Parameter(const ArrayType & v);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Table constructor.
|
||||
*/
|
||||
explicit Parameter(TableType && v);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Table constructor.
|
||||
*/
|
||||
explicit Parameter(const TableType & v);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
Parameter(const Parameter & o);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
Parameter(Parameter && o);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Parameter()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
Parameter & operator = (const Parameter & o)
|
||||
{
|
||||
Assign(o);
|
||||
return *this;
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
Parameter & operator = (Parameter && o)
|
||||
{
|
||||
Assign(std::forward< Parameter >(o));
|
||||
return *this;
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Equality comparison operator.
|
||||
*/
|
||||
bool operator == (const Parameter & o) const noexcept;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Inequality comparison operator.
|
||||
*/
|
||||
bool operator != (const Parameter & o) const noexcept
|
||||
{
|
||||
return !(*this == o);
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Discard any current information and set to null.
|
||||
*/
|
||||
void Reset()
|
||||
{
|
||||
Clear(nullptr);
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Swap parameter contents.
|
||||
*/
|
||||
void Swap(Parameter & o) noexcept
|
||||
{
|
||||
std::swap(mType, o.mType);
|
||||
std::swap(mSize, o.mSize);
|
||||
std::swap(mData, o.mData);
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Assign a copy of another parameter.
|
||||
*/
|
||||
void Assign(const Parameter & o);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Assign a ownership of another parameter.
|
||||
*/
|
||||
void Assign(Parameter && o);
|
||||
private:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Discard any and all information without performing any release of memory.
|
||||
*/
|
||||
void Discard() noexcept
|
||||
{
|
||||
mType = T_NULL;
|
||||
mSize = 0;
|
||||
mData = 0ull;
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear/release any stored value and reset to default. Does not set to null.
|
||||
*/
|
||||
void Clear();
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear/release any stored value and reset to default. Specialization which sets to null.
|
||||
*/
|
||||
void Clear(std::nullptr_t)
|
||||
{
|
||||
Clear(); // Do a regular clear first
|
||||
Discard(); // Now we can forget about it
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Used to represent a job that a worker must do, as well as a reply from the worker with the result.
|
||||
*/
|
||||
struct Job
|
||||
{
|
||||
using Parameters = Parameter::ArrayType;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Describe the typeof job a worker must do.
|
||||
*/
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
Null=0, // Null/non existent job.
|
||||
Stop, // Inform the worker to stop.
|
||||
Eval, // Inform the worker to evaluate some code.
|
||||
Exec // Inform the worker to execute a file.
|
||||
};
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Type mType; // Job type.
|
||||
String mTarget; // Where to perform the job.
|
||||
String mPayload; // Where to perform the job.
|
||||
Function mCallback; // Function to call once completed.
|
||||
Parameter mResponse; // The value given by the worker.
|
||||
Parameters mParameters; // Job parameters.
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Job()
|
||||
: mType(Type::Null), mTarget(), mPayload(), mCallback(), mResponse(), mParameters()
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Job(Function && callback)
|
||||
: mType(Type::Null), mTarget(), mPayload()
|
||||
, mCallback(std::forward< Function >(callback)), mResponse(), mParameters()
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
Job(const Job & o) = default;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
Job(Job && o) noexcept = default;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Job() = default;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment.
|
||||
*/
|
||||
Job & operator = (const Job & o) = default;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment.
|
||||
*/
|
||||
Job & operator = (Job && o) = default;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Thread.
|
||||
*/
|
||||
struct Thread
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Worker * mWorker; // Worker pointer.
|
||||
LightObj mObject; // Worker object.
|
||||
std::thread mThread; // Worker thread.
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Thread()
|
||||
: mWorker(nullptr), mObject(), mThread()
|
||||
{
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
Thread(Worker * worker);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor (disabled).
|
||||
*/
|
||||
Thread(const Thread & o) = delete;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor (disabled).
|
||||
*/
|
||||
Thread(Thread && o) noexcept;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Thread()
|
||||
{
|
||||
End();
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment (disabled).
|
||||
*/
|
||||
Thread & operator = (const Thread & o) = delete;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment (disabled).
|
||||
*/
|
||||
Thread & operator = (Thread && o) = delete;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
void End()
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
struct Worker
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
Worker(SQInteger stack, String && str, size_t h);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor (disabled).
|
||||
*/
|
||||
Worker(const Worker & o) = delete;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor (disabled).
|
||||
*/
|
||||
Worker(Worker && o) = delete;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~Worker();
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator (disabled).
|
||||
*/
|
||||
Worker & operator = (const Worker & o) = delete;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator (disabled).
|
||||
*/
|
||||
Worker & operator = (Worker && o) = delete;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
static void Terminate();
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
static void Process(size_t jobs);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
static LightObj Create(SQInteger stack, StackStrF & str);
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoke the actual process loop only if the worker was not requested to stop.
|
||||
*/
|
||||
void Start();
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Stop the worker but do not remove from container.
|
||||
*/
|
||||
void Kill()
|
||||
{
|
||||
std::lock_guard< std::mutex > lg(m_Mutex);
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Stop the worker and remove from container.
|
||||
*/
|
||||
void Stop()
|
||||
{
|
||||
m_Running.clear(); // Stop running as soon as you finish what you're doing
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the worker name.
|
||||
*/
|
||||
const String & GetName() const
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
void Evaluate(StackStrF & str, Function & callback)
|
||||
{
|
||||
// Is there something to evaluate?
|
||||
if (str.mLen <= 0)
|
||||
{
|
||||
STHROWF("Nothing to evaluate");
|
||||
}
|
||||
// Create the job
|
||||
std::unique_ptr< Job > job(new Job(std::move(callback)));
|
||||
// Assign data
|
||||
job->mPayload.assign(str.mPtr, static_cast< size_t >(str.mLen));
|
||||
// Submit job
|
||||
m_PendingJobs.enqueue(std::move(job));
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
void EvaluateTarget(StackStrF & str)
|
||||
{
|
||||
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
void Execute(StackStrF & str)
|
||||
{
|
||||
|
||||
}
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
void ExecuteTarget(StackStrF & str)
|
||||
{
|
||||
|
||||
}
|
||||
private:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Worker thread container.
|
||||
*/
|
||||
using Container = VecMap< size_t, std::unique_ptr< Thread > >;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* List of active worker threads.
|
||||
*/
|
||||
static Container sm_Workers;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
using Jobs = ConcurrentQueue< std::unique_ptr< Job > >;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Job queue.
|
||||
*/
|
||||
Jobs m_PendingJobs;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Job queue.
|
||||
*/
|
||||
Jobs m_FinishedJobs;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Loop state.
|
||||
*/
|
||||
std::atomic_flag m_Running;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Script state.
|
||||
*/
|
||||
HSQUIRRELVM m_VM;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Instance mutex.
|
||||
*/
|
||||
std::mutex m_Mutex;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Cached name hash.
|
||||
*/
|
||||
size_t m_Hash;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Worker name string.
|
||||
*/
|
||||
String m_Name;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Cached name hash.
|
||||
*/
|
||||
SQInteger m_StackSize;
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Take jobs from the queue and perform them.
|
||||
*/
|
||||
void Work();
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Script output handlers.
|
||||
*/
|
||||
static void PrintFunc(HSQUIRRELVM vm, CSStr msg, ...);
|
||||
static void ErrorFunc(HSQUIRRELVM vm, CSStr msg, ...);
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
Loading…
Reference in New Issue
Block a user