1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00
SqMod/module/Library/Worker/Job.hpp
Sandu Liviu Catalin d6f3f52eec Rewrite logger to account for multiple-threads.
Implement error handling for worker VMs.
2020-09-08 22:44:04 +03:00

294 lines
10 KiB
C++

#pragma once
// ------------------------------------------------------------------------------------------------
#include "Base/Shared.hpp"
#include "Library/Worker/Parameter.hpp"
// ------------------------------------------------------------------------------------------------
#include <memory>
// ------------------------------------------------------------------------------------------------
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;
/* ------------------------------------------------------------------------------------------------
* Used to represent a job that a worker must do, as well as a reply from the worker with the result.
*/
struct BaseJob
{
// --------------------------------------------------------------------------------------------
Function mCallback; // Function to call once completed.
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
BaseJob()
: mCallback()
{
}
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
BaseJob(const BaseJob & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
BaseJob(BaseJob && o) noexcept = delete;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
virtual ~BaseJob() = default;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
BaseJob & operator = (const BaseJob & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator (disabled).
*/
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
{
SQRESULT r = sq_compilebuffer(vm, mCode.data(), mCode.size(), mName.data(), SQTrue);
// See if the code could be compiled
if (SQ_FAILED(r))
{
return false; // Job failed
}
// Backup the stack top
SQInteger top = sq_gettop(vm);
// Push the root table as environment
sq_pushroottable(vm);
// Attempt to invoke the compiled code
r = sq_call(vm, 1, SQFalse, SQTrue);
// Restore the stack top
sq_settop(vm, top);
// See if the code could be evaluated
if (SQ_FAILED(r))
{
return false; // Job failed
}
// Job completed
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
{
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