LuaEngine/Thread.cpp

184 lines
3.4 KiB
C++
Raw Normal View History

2020-05-24 05:24:13 +08:00
#include "include.h"
#include <thread>
#include <queue>
#include <atomic>
2020-05-24 05:24:13 +08:00
using namespace std;
class LuaThread
2020-05-24 05:24:13 +08:00
{
private:
void _WorkerEntry()
{
status = 1;
if (lua_pcall(L, nArgs, LUA_MULTRET, 0))
{
status = 3;
}
else
{
status = 2;
}
}
2020-05-24 05:24:13 +08:00
public:
lua_State* L;
int nArgs;
// 0 Not started 1 Running 2 Finished 3 Errored
atomic<int> status;
thread td;
2020-05-24 05:24:13 +08:00
LuaThread(lua_State* subLVM, int subArgs) : L(subLVM), nArgs(subArgs), status(0), td(&LuaThread::_WorkerEntry, this)
2020-05-24 05:24:13 +08:00
{
}
~LuaThread()
2020-05-24 05:24:13 +08:00
{
if (td.joinable())
2020-05-24 05:24:13 +08:00
{
td.join();
2020-05-24 05:24:13 +08:00
}
lua_close(L);
2020-05-24 05:24:13 +08:00
}
};
2020-05-24 05:24:13 +08:00
int thread_dtor(lua_State* L)
{
auto t = lua_checkblock<LuaThread>(L, 1, "LuaThread");
t->~LuaThread();
2020-05-24 05:24:13 +08:00
return 0;
}
int thread_wait(lua_State* L)
2020-05-24 05:24:13 +08:00
{
auto t = lua_checkblock<LuaThread>(L, 1, "LuaThread");
if (t->td.joinable())
2020-05-24 05:24:13 +08:00
{
t->td.join();
lua_pushboolean(L, 1);
2020-05-24 05:24:13 +08:00
}
else
{
lua_pushboolean(L, 0);
2020-05-24 05:24:13 +08:00
}
return 1;
2020-05-24 05:24:13 +08:00
}
int thread_get(lua_State* L)
{
auto t = lua_checkblock<LuaThread>(L, 1, "LuaThread");
if (t->td.joinable())
2020-05-24 05:24:13 +08:00
{
t->td.join();
2020-05-24 05:24:13 +08:00
}
if (t->status == 2)
2020-05-24 05:24:13 +08:00
{
lua_pushboolean(L, 1);
2020-05-24 05:24:13 +08:00
}
else
{
lua_pushboolean(L, 0);
2020-05-24 05:24:13 +08:00
}
int stackTop = lua_gettop(t->L);
for (int i = 1; i <= stackTop; i++)
2020-05-24 05:24:13 +08:00
{
switch (lua_type(t->L, i))
2020-05-24 05:24:13 +08:00
{
case LUA_TNIL:
lua_pushnil(L);
break;
case LUA_TNUMBER:
lua_pushnumber(L, lua_tonumber(t->L, i));
break;
case LUA_TBOOLEAN:
lua_pushboolean(L, lua_toboolean(t->L, i));
break;
case LUA_TSTRING:
lua_pushstring(L, lua_tostring(t->L, i));
break;
default:
return luaL_error(L, "thread_get: return value #%d has unsupported type: %s", i, lua_typename(t->L, lua_type(t->L, i)));
2020-05-24 05:24:13 +08:00
}
}
return stackTop + 1;
2020-05-24 05:24:13 +08:00
}
int thread_status(lua_State* L)
2020-05-24 05:24:13 +08:00
{
auto t = lua_checkblock<LuaThread>(L, 1, "LuaThread");
lua_pushinteger(L, t->status);
return 1;
}
2020-05-24 05:24:13 +08:00
int thread_new(lua_State* L)
{
size_t codelen;
const char* code = luaL_checklstring(L, 1, &codelen);
lua_State* subL = CreateLuaEngine();
// compile
if (luaL_loadbuffer(subL, code, codelen, "ThreadMain"))
{
// Compile error, cannot load. Return error message to caller.
lua_pushnil(L);
lua_pushstring(L, lua_tostring(subL, 1));
lua_close(subL);
return 2;
2020-05-24 05:24:13 +08:00
}
// push args
int stackTop = lua_gettop(L);
for (int idx = 2; idx <= stackTop; idx++)
2020-05-24 05:24:13 +08:00
{
switch (lua_type(L, idx))
2020-05-24 05:24:13 +08:00
{
case LUA_TNIL:
lua_pushnil(subL);
break;
case LUA_TNUMBER:
lua_pushnumber(subL, lua_tonumber(L, idx));
break;
case LUA_TBOOLEAN:
lua_pushboolean(subL, lua_toboolean(L, idx));
break;
case LUA_TSTRING:
2020-05-24 05:24:13 +08:00
{
size_t datalen;
const char* data = lua_tolstring(L, idx, &datalen);
lua_pushlstring(subL, data, datalen);
break;
}
default:
lua_pushnil(L);
lua_pushfstring(L, "thread_create: parameter #%d has unsupported type: %s", idx, lua_typename(L, lua_type(L, idx)));
lua_close(subL);
return 2;
2020-05-24 05:24:13 +08:00
}
}
auto c = new (lua_newblock<LuaThread>(L)) LuaThread(subL, stackTop - 1);
if (luaL_newmetatable(L, "LuaThread"))
2020-05-24 05:24:13 +08:00
{
lua_setfield_function(L, "__gc", thread_dtor);
lua_newtable(L);
lua_setfield_function(L, "wait", thread_wait);
2020-05-24 05:24:13 +08:00
lua_setfield_function(L, "get", thread_get);
lua_setfield_function(L, "status", thread_status);
2020-05-24 05:24:13 +08:00
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}
void InitThread(lua_State* L)
{
lua_getglobal(L, "package");
lua_getfield(L, -1, "loaded");
lua_pushcfunction(L, thread_new);
lua_setfield(L, -2, "Thread");
lua_pop(L, 2);
}