1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-01-19 03:57:14 +01:00

Use polymorphism to deliver jobs.

This commit is contained in:
Sandu Liviu Catalin 2020-09-06 23:09:54 +03:00
parent 38b874f444
commit 50a61c69e6
5 changed files with 305 additions and 109 deletions

View File

@ -82,16 +82,12 @@ void Worker::Process(size_t jobs)
{ {
for (size_t n = 0; n < jobs; ++n) for (size_t n = 0; n < jobs; ++n)
{ {
std::unique_ptr< Job > job; std::unique_ptr< BaseJob > job;
// Try to get a job from the queue // Try to get a job from the queue
if (!t->m_FinishedJobs.try_dequeue(job)) if (t->m_FinishedJobs.try_dequeue(job))
{ {
break; // No jobs // Allow the job to finish
} job->Finish(t->m_VM, *t);
// Does it have a callback?
if (!job->mCallback.IsNull())
{
job->mCallback.Execute();
} }
} }
} }
@ -161,40 +157,22 @@ void Worker::Start()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Worker::Work() void Worker::Work()
{ {
std::unique_ptr< Job > job; std::unique_ptr< BaseJob > job;
// Try to get a job from the queue // Try to get a job from the queue
if (!m_PendingJobs.try_dequeue(job)) if (!m_PendingJobs.try_dequeue(job))
{ {
using namespace std::chrono_literals; using namespace std::chrono_literals;
// Do not hammer the CPU if there are no jobs // Do not hammer the CPU if there are no jobs
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
// Try again
return;
} }
// Identify the job type else
switch (job->mType)
{ {
// This type of job demands no work // Do the job
case Job::Type::Null: break; job->Start(m_VM, *this);
case Job::Type::Stop:
break;
case Job::Type::Eval: {
sq_compilebuffer(m_VM, job->mPayload.data(), job->mPayload.size(), _SC("eval"), SQTrue);
SQInteger top = sq_gettop(m_VM);
sq_pushroottable(m_VM);
sq_call(m_VM, 1, false, true);
sq_settop(m_VM, top);
} break;
case Job::Type::Exec:
break;
// We're not qualified for this job
default: break;
}
// This job was finished // This job was finished
m_FinishedJobs.enqueue(std::move(job)); m_FinishedJobs.enqueue(std::move(job));
} }
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Worker::PrintFunc(HSQUIRRELVM /*vm*/, CSStr msg, ...) void Worker::PrintFunc(HSQUIRRELVM /*vm*/, CSStr msg, ...)
{ {
@ -237,7 +215,7 @@ void Register_Worker(HSQUIRRELVM vm)
// Properties // Properties
.Prop(_SC("Name"), &Worker::GetName) .Prop(_SC("Name"), &Worker::GetName)
// Core Methods // Core Methods
.CbFunc(_SC("Evaluate"), &Worker::Evaluate) .Func(_SC("Enqueue"), &Worker::Enqueue)
// Static Member Methods // Static Member Methods
); );

View File

@ -144,42 +144,9 @@ struct Worker
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* *
*/ */
void Evaluate(StackStrF & str, Function & callback) void Enqueue(JobWrapperBase & job)
{ {
// Is there something to evaluate? m_PendingJobs.enqueue(job.Grab());
if (str.mLen <= 0)
{
STHROWF("Nothing to evaluate");
}
// Create the job
std::unique_ptr< Job > job(new Job(std::move(callback)));
// Define type
job->mType = Job::Type::Eval;
// 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: private:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -193,13 +160,13 @@ private:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* *
*/ */
using Jobs = ConcurrentQueue< std::unique_ptr< Job > >; using Jobs = ConcurrentQueue< std::unique_ptr< BaseJob > >;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Job queue. * BaseJob queue.
*/ */
Jobs m_PendingJobs; Jobs m_PendingJobs;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Job queue. * BaseJob queue.
*/ */
Jobs m_FinishedJobs; Jobs m_FinishedJobs;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------

View File

@ -4,11 +4,56 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQMODE_DECL_TYPENAME(SqBaseJob, _SC("SqBaseJob"))
SQMODE_DECL_TYPENAME(SqEvaluateJob, _SC("SqEvaluateJob"))
SQMODE_DECL_TYPENAME(SqExecuteJob, _SC("SqExecuteJob"))
// ================================================================================================ // ================================================================================================
void Register_Job(HSQUIRRELVM vm) void Register_Job(HSQUIRRELVM vm)
{ {
Table jbns(vm); Table jbns(vm);
{
using Type = JobWrapperBase;
jbns.Bind(_SC("Base"),
Class< Type, NoConstructor< Type > >(vm, SqBaseJob::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqBaseJob::Fn)
// Properties
.Prop(_SC("Callback"), &Type::GetCallback, &Type::SetCallback)
// Core Methods
.CbFunc(_SC("SetCallback"), &Type::SetCallback)
);
}
{
using Type = JobWrapper< EvaluateJob >;
jbns.Bind(_SC("Evaluate"),
DerivedClass< Type, JobWrapperBase, NoCopy< Type > >(vm, SqEvaluateJob::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqEvaluateJob::Fn)
// Properties
.Prop(_SC("Code"), &Type::GetCode, &Type::SetCode)
.Prop(_SC("Name"), &Type::GetName, &Type::SetName)
// Core Methods
.CbFunc(_SC("SetCode"), &Type::SetCode)
.FmtFunc(_SC("SetName"), &Type::ApplyName)
);
}
{
using Type = JobWrapper< ExecuteJob >;
jbns.Bind(_SC("Execute"),
DerivedClass< Type, JobWrapperBase, NoCopy< Type > >(vm, SqExecuteJob::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqExecuteJob::Fn)
);
}
RootTable(vm).Bind(_SC("SqJob"), jbns); RootTable(vm).Bind(_SC("SqJob"), jbns);
} }

View File

@ -4,70 +4,276 @@
#include "Base/Shared.hpp" #include "Base/Shared.hpp"
#include "Library/Worker/Parameter.hpp" #include "Library/Worker/Parameter.hpp"
// ------------------------------------------------------------------------------------------------
#include <memory>
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Handle validation.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
#define SQMOD_VALIDATE(x) (x).Validate(__FILE__, __LINE__)
#else
#define SQMOD_VALIDATE(x) (x).Validate()
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
struct Worker; struct Worker;
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Used to represent a job that a worker must do, as well as a reply from the worker with the result. * Used to represent a job that a worker must do, as well as a reply from the worker with the result.
*/ */
struct Job struct BaseJob
{ {
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. Function mCallback; // Function to call once completed.
Parameter mResponse; // The value given by the worker.
Parameters mParameters; // Job parameters.
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Default constructor. * Default constructor.
*/ */
Job() BaseJob()
: mType(Type::Null), mTarget(), mPayload(), mCallback(), mResponse(), mParameters() : mCallback()
{ {
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Default constructor. * Copy constructor (disabled).
*/ */
Job(Function && callback) BaseJob(const BaseJob & o) = delete;
: mType(Type::Null), mTarget(), mPayload()
, mCallback(std::forward< Function >(callback)), mResponse(), mParameters()
{
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy constructor. * Move constructor (disabled).
*/ */
Job(const Job & o) = default; BaseJob(BaseJob && o) noexcept = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
Job(Job && o) noexcept = default;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Destructor. * Destructor.
*/ */
~Job() = default; virtual ~BaseJob() = default;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy assignment. * Copy assignment operator (disabled).
*/ */
Job & operator = (const Job & o) = default; BaseJob & operator = (const BaseJob & o) = delete;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Move assignment. * Move assignment operator (disabled).
*/ */
Job & operator = (Job && o) = default; BaseJob & operator = (BaseJob && o) = delete;
/* --------------------------------------------------------------------------------------------
* Create a new job that will replace the specified job.
*/
virtual BaseJob * New(BaseJob & job) = 0;
/* --------------------------------------------------------------------------------------------
* Invoked inside a worker to perform the job.
*/
virtual bool Start(HSQUIRRELVM vm, Worker & worker) = 0;
/* --------------------------------------------------------------------------------------------
* Invoked inside a worker to perform the job.
*/
virtual void Finish(HSQUIRRELVM vm, Worker & worker)
{
// Do we have a callback?
if (!mCallback.IsNull())
{
mCallback.Execute();
}
}
};
/* ------------------------------------------------------------------------------------------------
* Tell the worker to evaluate a piece of code.
*/
struct EvaluateJob : public BaseJob
{
// --------------------------------------------------------------------------------------------
String mCode; // The code to evaluate.
String mName; // How to refer to this code in errors.
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
EvaluateJob()
: BaseJob(), mCode(), mName()
{
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
virtual ~EvaluateJob() override = default;
/* --------------------------------------------------------------------------------------------
* Create a new job that will replace the specified job.
*/
BaseJob * New(BaseJob & job) override
{
return new EvaluateJob();
}
/* --------------------------------------------------------------------------------------------
*
*/
bool Start(HSQUIRRELVM vm, Worker & worker) override
{
sq_compilebuffer(vm, mCode.data(), mCode.size(), mName.data(), SQTrue);
SQInteger top = sq_gettop(vm);
sq_pushroottable(vm);
sq_call(vm, 1, false, true);
sq_settop(vm, top);
return true;
}
};
/* ------------------------------------------------------------------------------------------------
* Tell the worker to execute the code from a file.
*/
struct ExecuteJob : public BaseJob
{
// --------------------------------------------------------------------------------------------
String mFile; // The file to evaluate.
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
ExecuteJob()
: BaseJob()
{
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
virtual ~ExecuteJob() override = default;
/* --------------------------------------------------------------------------------------------
* Create a new job that will replace the specified job.
*/
BaseJob * New(BaseJob & job) override
{
return new ExecuteJob();
}
/* --------------------------------------------------------------------------------------------
*
*/
bool Start(HSQUIRRELVM vm, Worker & worker) override
{
std::puts("Executing...");
return true;
}
};
/* ------------------------------------------------------------------------------------------------
* Used internally to wrap a job and expose it to the script.
*/
struct JobWrapperBase
{
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
JobWrapperBase(const JobWrapperBase & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
JobWrapperBase(JobWrapperBase && o) noexcept = delete;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~JobWrapperBase()
{
// There should always be an instance
delete m_Inst;
m_Inst = nullptr;
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
JobWrapperBase & operator = (const JobWrapperBase & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator (disabled).
*/
JobWrapperBase & operator = (JobWrapperBase && o) = delete;
/* --------------------------------------------------------------------------------------------
* Retrieve a raw pointer to the managed instance.
*/
BaseJob * Get() const
{
return m_Inst;
}
/* --------------------------------------------------------------------------------------------
* Retrieve a managed pointer managed instance and yield ownership.
*/
std::unique_ptr< BaseJob > Grab()
{
std::unique_ptr< BaseJob > ptr(m_Inst);
m_Inst = ptr->New(*m_Inst);
return ptr;
}
/* --------------------------------------------------------------------------------------------
*
*/
void SetCallback(Function & cb)
{
m_Inst->mCallback = std::move(cb);
}
/* --------------------------------------------------------------------------------------------
*
*/
const Function & GetCallback() const
{
return m_Inst->mCallback;
}
protected:
/* --------------------------------------------------------------------------------------------
* Instance of the wrapped job.
*/
BaseJob * m_Inst;
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
JobWrapperBase(BaseJob * job) noexcept
: m_Inst(job)
{
}
};
/* ------------------------------------------------------------------------------------------------
* Used internally to wrap a job and expose it to the script.
*/
template < class T > struct JobWrapper : public JobWrapperBase
{
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
JobWrapper()
: JobWrapperBase(new T)
{
}
/* --------------------------------------------------------------------------------------------
*
*/
void SetCode(StackStrF & str)
{
static_cast< T * >(m_Inst)->mCode.assign(str.mPtr, static_cast< size_t >(str.mLen));
}
/* --------------------------------------------------------------------------------------------
*
*/
const String & GetCode() const
{
return static_cast< T * >(m_Inst)->mCode;
}
/* --------------------------------------------------------------------------------------------
*
*/
void SetName(StackStrF & str)
{
static_cast< T * >(m_Inst)->mName.assign(str.mPtr, static_cast< size_t >(str.mLen));
}
/* --------------------------------------------------------------------------------------------
*
*/
JobWrapper< T > & ApplyName(StackStrF & str)
{
SetName(str);
return *this;
}
/* --------------------------------------------------------------------------------------------
*
*/
const String & GetName() const
{
return static_cast< T * >(m_Inst)->mName;
}
}; };
} // Namespace:: SqMod } // Namespace:: SqMod