mirror of https://github.com/bjornbytes/lovr.git
120 lines
2.9 KiB
C
120 lines
2.9 KiB
C
#include "api.h"
|
|
#include "data/blob.h"
|
|
#include "event/event.h"
|
|
#include "thread/thread.h"
|
|
#include "core/os.h"
|
|
#include "util.h"
|
|
#include <lualib.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static void threadRun(void* L) {
|
|
int top = lua_gettop(L);
|
|
int status = lua_pcall(L, top - 2, 0, 1);
|
|
lua_pushinteger(L, status);
|
|
}
|
|
|
|
static char* threadRunner(Thread* thread, Blob* body, Variant* arguments, uint32_t argumentCount) {
|
|
lua_State* L = luaL_newstate();
|
|
luaL_openlibs(L);
|
|
luax_preload(L);
|
|
|
|
lua_pushcfunction(L, luax_getstack);
|
|
|
|
if (!luaL_loadbuffer(L, body->data, body->size, "thread")) {
|
|
for (uint32_t i = 0; i < argumentCount; i++) {
|
|
luax_pushvariant(L, &arguments[i]);
|
|
}
|
|
|
|
lovrTry(threadRun, L, luax_vthrow, L);
|
|
|
|
if (lua_tointeger(L, -1) == 0) {
|
|
lua_close(L);
|
|
return NULL;
|
|
} else {
|
|
lua_pop(L, 1);
|
|
}
|
|
}
|
|
|
|
size_t length;
|
|
const char* message = lua_tolstring(L, -1, &length);
|
|
|
|
if (message) {
|
|
char* error = lovrMalloc(length + 1);
|
|
memcpy(error, message, length + 1);
|
|
lua_close(L);
|
|
return error;
|
|
}
|
|
|
|
lua_close(L);
|
|
return NULL;
|
|
}
|
|
|
|
static int l_lovrThreadNewThread(lua_State* L) {
|
|
uint32_t defer = lovrDeferPush();
|
|
Blob* blob = luax_totype(L, 1, Blob);
|
|
if (!blob) {
|
|
size_t length;
|
|
const char* str = luaL_checklstring(L, 1, &length);
|
|
if (memchr(str, '\n', MIN(1024, length))) {
|
|
void* data = lovrMalloc(length + 1);
|
|
memcpy(data, str, length + 1);
|
|
blob = lovrBlobCreate(data, length, "thread code");
|
|
} else {
|
|
void* code = luax_readfile(str, &length);
|
|
lovrAssert(code, "Could not read thread code from file '%s'", str);
|
|
blob = lovrBlobCreate(code, length, str);
|
|
}
|
|
lovrDeferRelease(blob, lovrBlobDestroy);
|
|
}
|
|
Thread* thread = lovrThreadCreate(threadRunner, blob);
|
|
luax_pushtype(L, Thread, thread);
|
|
lovrRelease(thread, lovrThreadDestroy);
|
|
lovrDeferPop(defer);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrThreadGetChannel(lua_State* L) {
|
|
const char* name = luaL_checkstring(L, 1);
|
|
Channel* channel = lovrThreadGetChannel(name);
|
|
luax_pushtype(L, Channel, channel);
|
|
// Note: Channels are intentionally not released here (see thread.h)
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg lovrThreadModule[] = {
|
|
{ "newThread", l_lovrThreadNewThread },
|
|
{ "getChannel", l_lovrThreadGetChannel },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
extern const luaL_Reg lovrThread[];
|
|
extern const luaL_Reg lovrChannel[];
|
|
|
|
int luaopen_lovr_thread(lua_State* L) {
|
|
lua_newtable(L);
|
|
luax_register(L, lovrThreadModule);
|
|
luax_registertype(L, Thread);
|
|
luax_registertype(L, Channel);
|
|
|
|
int32_t workers = -1;
|
|
|
|
luax_pushconf(L);
|
|
if (lua_istable(L, -1)) {
|
|
lua_getfield(L, -1, "thread");
|
|
if (lua_istable(L, -1)) {
|
|
lua_getfield(L, -1, "workers");
|
|
if (lua_type(L, -1) == LUA_TNUMBER) {
|
|
workers = lua_tointeger(L, -1);
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lovrThreadModuleInit(workers);
|
|
luax_atexit(L, lovrThreadModuleDestroy);
|
|
return 1;
|
|
}
|