mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 13:21:34 +00:00
Add mutexes to sync access to shared data
This commit is contained in:
parent
63dde0bc7b
commit
0b3e3d90c0
@ -217,39 +217,45 @@ void set_app_params(lua_State* L, const Params& params);
|
||||
|
||||
#define RUNNING_TASKS "RunningTasks"
|
||||
|
||||
RunScriptTask::RunScriptTask(lua_State* L, int nelems, Func&& func)
|
||||
std::mutex runningTasksMutex;
|
||||
|
||||
RunScriptTask::RunScriptTask(lua_State* L, int nelems, const std::string& description, Func&& func)
|
||||
: m_LRef(LUA_REFNIL)
|
||||
, m_description(description)
|
||||
{
|
||||
m_mainL = L;
|
||||
m_L = lua_newthread(m_mainL);
|
||||
m_L = lua_newthread(L);
|
||||
// Move the thread object in the parent thread stack to the new thread stack.
|
||||
lua_xmove(L, m_L, 1);
|
||||
// Save a reference to the lua thread in the registry to avoid garbage collection
|
||||
// before it gets executed.
|
||||
m_LRef = luaL_ref(m_mainL, LUA_REGISTRYINDEX);
|
||||
m_LRef = luaL_ref(m_L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Move nelems stack elements from main thread to the child lua thread.
|
||||
lua_xmove(m_mainL, m_L, nelems);
|
||||
lua_xmove(L, m_L, nelems);
|
||||
|
||||
// We use a global table to have access to the state of all the currently
|
||||
// running scripts
|
||||
int type = lua_getglobal(m_L, RUNNING_TASKS);
|
||||
if (type == LUA_TNIL) {
|
||||
lua_newtable(m_L);
|
||||
lua_pushvalue(m_L, -1);
|
||||
lua_setglobal(m_L, RUNNING_TASKS);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(runningTasksMutex);
|
||||
int type = lua_getglobal(m_L, RUNNING_TASKS);
|
||||
if (type == LUA_TNIL) {
|
||||
lua_newtable(m_L);
|
||||
lua_pushvalue(m_L, -1);
|
||||
lua_setglobal(m_L, RUNNING_TASKS);
|
||||
}
|
||||
|
||||
lua_pushlightuserdata(m_L, this);
|
||||
lua_rawsetp(m_L, -2, m_L);
|
||||
lua_pop(m_L, 1);
|
||||
}
|
||||
|
||||
lua_pushlightuserdata(m_L, m_L);
|
||||
lua_pushlightuserdata(m_L, this);
|
||||
lua_settable(m_L, -3);
|
||||
lua_pop(m_L, 1);
|
||||
|
||||
lua_sethook(
|
||||
m_L,
|
||||
[](lua_State* L, lua_Debug* ar) {
|
||||
if (ar->event == LUA_HOOKCOUNT) {
|
||||
std::lock_guard<std::mutex> lock(runningTasksMutex);
|
||||
int type = lua_getglobal(L, RUNNING_TASKS);
|
||||
if (type == LUA_TTABLE) {
|
||||
lua_pushlightuserdata(L, L);
|
||||
lua_gettable(L, -2);
|
||||
lua_rawgetp(L, -1, L);
|
||||
RunScriptTask* task = (RunScriptTask*)lua_topointer(L, -1);
|
||||
lua_pop(L, 2);
|
||||
if (task->wantsToStop()) {
|
||||
@ -268,7 +274,15 @@ RunScriptTask::RunScriptTask(lua_State* L, int nelems, Func&& func)
|
||||
|
||||
RunScriptTask::~RunScriptTask()
|
||||
{
|
||||
luaL_unref(m_mainL, LUA_REGISTRYINDEX, m_LRef);
|
||||
std::lock_guard<std::mutex> lock(runningTasksMutex);
|
||||
int type = lua_getglobal(m_L, RUNNING_TASKS);
|
||||
if (type == LUA_TTABLE) {
|
||||
lua_pushlightuserdata(m_L, nullptr);
|
||||
lua_rawsetp(m_L, -2, m_L);
|
||||
}
|
||||
lua_pop(m_L, 1);
|
||||
|
||||
luaL_unref(m_L, LUA_REGISTRYINDEX, m_LRef);
|
||||
|
||||
// Collect script garbage.
|
||||
lua_gc(m_L, LUA_GCCOLLECT);
|
||||
@ -601,8 +615,11 @@ Engine::~Engine()
|
||||
void Engine::destroy()
|
||||
{
|
||||
// Stop all running tasks.
|
||||
for (auto& task : m_tasks) {
|
||||
task->stop();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (auto& task : m_tasks) {
|
||||
task->stop();
|
||||
}
|
||||
}
|
||||
m_threadPool.wait_all();
|
||||
|
||||
@ -717,9 +734,9 @@ bool Engine::evalFile(const std::string& filename, const Params& params)
|
||||
return result;
|
||||
}
|
||||
|
||||
void Engine::callInTask(lua_State* parentL, int nargs)
|
||||
void Engine::callInTask(lua_State* parentL, int nargs, const std::string& description)
|
||||
{
|
||||
executeTask(parentL, nargs + 1, [this, nargs](lua_State* L) {
|
||||
executeTask(parentL, nargs + 1, description, [this, nargs](lua_State* L) {
|
||||
try {
|
||||
if (lua_pcall(L, nargs, 0, 0)) {
|
||||
if (const char* s = lua_tostring(L, -1))
|
||||
@ -735,17 +752,24 @@ void Engine::callInTask(lua_State* parentL, int nargs)
|
||||
});
|
||||
}
|
||||
|
||||
void Engine::executeTask(lua_State* parentL, int nelems, RunScriptTask::Func&& func)
|
||||
void Engine::executeTask(lua_State* parentL,
|
||||
int nelems,
|
||||
const std::string& description,
|
||||
RunScriptTask::Func&& func)
|
||||
{
|
||||
auto task = std::make_unique<RunScriptTask>(parentL, nelems, std::move(func));
|
||||
auto task = std::make_unique<RunScriptTask>(parentL, nelems, description, std::move(func));
|
||||
auto* taskPtr = task.get();
|
||||
task->onDone([this, taskPtr](base::task_token&) { onTaskDone(taskPtr); });
|
||||
m_tasks.push_back(std::move(task));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_tasks.push_back(std::move(task));
|
||||
}
|
||||
taskPtr->execute(m_threadPool);
|
||||
}
|
||||
|
||||
void Engine::onTaskDone(const RunScriptTask* task)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (auto it = m_tasks.begin(); it != m_tasks.end(); ++it) {
|
||||
if ((*it).get() == task) {
|
||||
m_tasks.erase(it);
|
||||
@ -756,7 +780,7 @@ void Engine::onTaskDone(const RunScriptTask* task)
|
||||
|
||||
bool Engine::evalUserFileInTask(const std::string& filename, const Params& params)
|
||||
{
|
||||
executeTask(L, 0, [filename, params, this](lua_State* L) {
|
||||
executeTask(L, 0, filename, [filename, params, this](lua_State* L) {
|
||||
std::string absFilename = base::get_absolute_path(filename);
|
||||
// Set the _SCRIPT_PATH global so require() can find .lua files from
|
||||
// the script path.
|
||||
@ -787,8 +811,7 @@ bool Engine::evalUserFileInTask(const std::string& filename, const Params& param
|
||||
lua_pcall(L, 0, 1, 0)) {
|
||||
const char* s = lua_tostring(L, -1);
|
||||
if (s)
|
||||
TRACE("Error: %s\n", s);
|
||||
// onConsoleError(s);
|
||||
onConsoleError(s);
|
||||
ok = false;
|
||||
returnCode = -1;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ class RunScriptTask {
|
||||
public:
|
||||
typedef std::function<void(lua_State* L)> Func;
|
||||
|
||||
RunScriptTask(lua_State* L, int nelems, Func&& func);
|
||||
RunScriptTask(lua_State* L, int nelems, const std::string& description, Func&& func);
|
||||
~RunScriptTask();
|
||||
|
||||
void onDone(base::task::func_t&& funcDone) { m_task.on_done(std::move(funcDone)); }
|
||||
@ -98,14 +98,16 @@ public:
|
||||
void stop();
|
||||
bool wantsToStop() const { return m_wantsToStop; }
|
||||
|
||||
int ref() const { return m_LRef; }
|
||||
const std::string& description() const { return m_description; }
|
||||
|
||||
private:
|
||||
// Lua's main thread state.
|
||||
lua_State* m_mainL;
|
||||
// Lua's thread state based on m_mainL.
|
||||
// Lua's thread state.
|
||||
lua_State* m_L;
|
||||
int m_LRef = LUA_REFNIL;
|
||||
int m_LRef;
|
||||
base::task m_task;
|
||||
bool m_wantsToStop = false;
|
||||
std::string m_description;
|
||||
};
|
||||
|
||||
class Engine {
|
||||
@ -130,7 +132,15 @@ public:
|
||||
bool evalUserFileInTask(const std::string& filename, const Params& params = Params());
|
||||
// Calls the function in the stack with the number of arguments specified by nargs in
|
||||
// a new RunScriptTask.
|
||||
void callInTask(lua_State* L, int nargs);
|
||||
void callInTask(lua_State* L, int nargs, const std::string& description);
|
||||
std::vector<const RunScriptTask*> tasks() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
std::vector<const RunScriptTask*> tasks(m_tasks.size());
|
||||
for (const auto& task : m_tasks)
|
||||
tasks.push_back(task.get());
|
||||
return tasks;
|
||||
}
|
||||
|
||||
void handleException(const std::exception& ex);
|
||||
void handleException(lua_State* L, const std::exception& ex);
|
||||
@ -151,13 +161,17 @@ private:
|
||||
void onConsolePrint(const char* text);
|
||||
// Creates a new RunScriptTask based on parentL and moving nelems from parentL's stack
|
||||
// to the child lua thread stack
|
||||
void executeTask(lua_State* parentL, int nelems, RunScriptTask::Func&& func);
|
||||
void executeTask(lua_State* parentL,
|
||||
int nelems,
|
||||
const std::string& description,
|
||||
RunScriptTask::Func&& func);
|
||||
void onTaskDone(const RunScriptTask* task);
|
||||
static void checkProgress(lua_State* L, lua_Debug* ar);
|
||||
|
||||
lua_State* L;
|
||||
EngineDelegate* m_delegate;
|
||||
base::thread_pool m_threadPool;
|
||||
mutable std::mutex m_mutex;
|
||||
Tasks m_tasks;
|
||||
bool m_printLastResult;
|
||||
int m_returnCode;
|
||||
|
Loading…
x
Reference in New Issue
Block a user