From 499bfa99a328ceccfcd3a7b60df31061dd41af61 Mon Sep 17 00:00:00 2001 From: Firew0lf Date: Sun, 17 Jan 2016 12:18:39 +0100 Subject: [PATCH] ADDED THREAD ! Minor changes on other libs. To communicate with a thread, use sockets on localhost, this should work. Or use the return code, or the "last error", but that's crappy. For the return code, just `return `; only works with integers. --- source/audio.c | 4 +- source/ctr.c | 8 +++ source/fs.c | 25 +++++--- source/gfx.c | 6 +- source/httpc.c | 7 ++- source/thread.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 196 insertions(+), 14 deletions(-) create mode 100644 source/thread.c diff --git a/source/audio.c b/source/audio.c index 1f72900..2222999 100644 --- a/source/audio.c +++ b/source/audio.c @@ -887,7 +887,9 @@ int luaopen_audio_lib(lua_State *L) { } void load_audio_lib(lua_State *L) { - isAudioInitialized = !ndspInit(); // ndspInit returns 0 in case of success + if (!isAudioInitialized) { + isAudioInitialized = !ndspInit(); // ndspInit returns 0 in case of success + } luaL_requiref(L, "ctr.audio", luaopen_audio_lib, false); } diff --git a/source/ctr.c b/source/ctr.c index 06f7292..64f55e5 100644 --- a/source/ctr.c +++ b/source/ctr.c @@ -114,6 +114,13 @@ The `ctr.mic` module. */ void load_mic_lib(lua_State *L); +/*** +The `ctr.thread` module. +@table thread +@see ctr.thread +*/ +void load_thread_lib(lua_State *L); + /*** Return whether or not the program should continue. @function run @@ -171,6 +178,7 @@ struct { char *name; void (*load)(lua_State *L); void (*unload)(lua_State *L); } { "audio", load_audio_lib, unload_audio_lib }, { "apt", load_apt_lib, NULL }, { "mic", load_mic_lib, NULL }, + { "thread", load_thread_lib, NULL }, { NULL, NULL } }; diff --git a/source/fs.c b/source/fs.c index f442999..68e13e3 100644 --- a/source/fs.c +++ b/source/fs.c @@ -14,6 +14,8 @@ The `fs` module. #include #include +bool isFsInitialized = false; + Handle *fsuHandle; FS_Archive sdmcArchive; #ifdef ROMFS @@ -211,18 +213,21 @@ int luaopen_fs_lib(lua_State *L) { } void load_fs_lib(lua_State *L) { - fsInit(); + if (!isFsInitialized) { + fsInit(); - fsuHandle = fsGetSessionHandle(); - FSUSER_Initialize(*fsuHandle); - - sdmcArchive = (FS_Archive){ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")}; - FSUSER_OpenArchive(&sdmcArchive); - #ifdef ROMFS - romfsArchive = (FS_Archive){ARCHIVE_ROMFS, fsMakePath(PATH_EMPTY, "")}; - FSUSER_OpenArchive(&romfsArchive); - #endif + fsuHandle = fsGetSessionHandle(); + FSUSER_Initialize(*fsuHandle); + sdmcArchive = (FS_Archive){ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")}; + FSUSER_OpenArchive(&sdmcArchive); + #ifdef ROMFS + romfsArchive = (FS_Archive){ARCHIVE_ROMFS, fsMakePath(PATH_EMPTY, "")}; + FSUSER_OpenArchive(&romfsArchive); + #endif + isFsInitialized = true; + } + luaL_requiref(L, "ctr.fs", luaopen_fs_lib, false); } diff --git a/source/gfx.c b/source/gfx.c index 9bae7ca..18a110b 100644 --- a/source/gfx.c +++ b/source/gfx.c @@ -456,8 +456,10 @@ int luaopen_gfx_lib(lua_State *L) { } void load_gfx_lib(lua_State *L) { - sf2d_init(); - sftd_init(); + if (!isGfxInitialized) { + sf2d_init(); + sftd_init(); + } isGfxInitialized = true; diff --git a/source/httpc.c b/source/httpc.c index e104e18..eed4590 100644 --- a/source/httpc.c +++ b/source/httpc.c @@ -13,6 +13,8 @@ The `httpc` module. #include #include +bool isHttpcInitialized = false; + /*** Create a HTTP Context. @function context @@ -205,7 +207,10 @@ int luaopen_httpc_lib(lua_State *L) { } void load_httpc_lib(lua_State *L) { - httpcInit(); + if (!isHttpcInitialized) { + httpcInit(); + isHttpcInitialized = true; + } luaL_requiref(L, "ctr.httpc", luaopen_httpc_lib, false); } diff --git a/source/thread.c b/source/thread.c new file mode 100644 index 0000000..4fc8836 --- /dev/null +++ b/source/thread.c @@ -0,0 +1,160 @@ +/*** +The `thread` module. +@module ctr.thread +@usage local thread = require("ctr.thread") +*/ + +#include +#include +#include + +#include <3ds/types.h> +#include <3ds/thread.h> +#include <3ds/services/apt.h> + +#include +#include + +void load_ctr_lib(lua_State *L); + +typedef struct { + Thread thread; + const char *code; + char *error; +} thread_userdata; + +void entryPoint(void *thread) { + lua_State *T = luaL_newstate(); + luaL_openlibs(T); + load_ctr_lib(T); + + if (luaL_dostring(T, ((thread_userdata*)thread)->code)) { + const char* lerror = luaL_checkstring(T, -1); + ((thread_userdata*)thread)->error = malloc(strlen(lerror)+1); + strcpy(((thread_userdata*)thread)->error, lerror); + } + + int exitCode = 0; + if (lua_isinteger(T, -1)) { + exitCode = lua_tointeger(T, -1); + } + lua_close(T); + threadExit(exitCode); +} + +// module +/*** +Set the maximum CPU time allocated to threads on CPU #1. +@function setCpuLimit +@tparam number time in percents. +*/ +static int thread_setCpuLimit(lua_State *L) { + u32 percent = luaL_checkinteger(L, 1); + APT_SetAppCpuTimeLimit(percent); + + return 0; +} + +/*** +Start a new thread. +@function start +@tparam string code Lua code to load in the new thread. May not work with dumped functions. +@tparam[opt=0] number cpu must be >= 0 and < 2 for 3ds or < 4 for new3ds +@tparam[opt=0x27] number priority must be > 0x18 and < 0x3f; the lower is higher. +@tparam[opt=0x100000] number stacksize size of the stack, increase it in case of OoM +@treturn thread a new thread object +*/ +static int thread_start(lua_State *L) { + const char* code = luaL_checkstring(L, 1); + s32 processor = luaL_optinteger(L, 2, 0); + s32 priority = luaL_optinteger(L, 3, 0x27); + size_t stackSize = luaL_optinteger(L, 4, 0x100000); + + thread_userdata *thread = lua_newuserdata(L, sizeof(thread_userdata*)); + luaL_getmetatable(L, "LThread"); + lua_setmetatable(L, -2); + + thread->code = code; + thread->error = NULL; + thread->thread = threadCreate(entryPoint, thread, stackSize, priority, processor, true); + + return 1; +} + +/*** +Wait for a thread to finish. +@function :join +@tparam[opt=2^32-1] number timeout in ns +@treturn number exit code +@treturn string last error, or nil +*/ +static int thread_join(lua_State *L) { + thread_userdata *thread = luaL_checkudata(L, 1, "LThread"); + u64 timeout = luaL_optinteger(L, 2, 4294967295); + + threadJoin(thread->thread, timeout); + + lua_pushinteger(L, threadGetExitCode(thread->thread)); + if (thread->error != NULL) { + lua_pushstring(L, thread->error); + return 2; + } + return 1; +} + +/*** +Return the last error of a thread. +@function :lastError +@treturn string last error, or nil +*/ +static int thread_lastError(lua_State *L) { + thread_userdata *thread = luaL_checkudata(L, 1, "LThread"); + + if (thread->error == NULL) { + lua_pushnil(L); + } else { + lua_pushstring(L, thread->error); + } + return 1; +} + +/*** +Destroy a finished thread. +@function :destroy +*/ +static int thread_destroy(lua_State *L) { + thread_userdata *thread = luaL_checkudata(L, 1, "LThread"); + + threadFree(thread->thread); + free(thread->error); + + return 0; +} + +static const struct luaL_Reg thread_lib[] = { + {"start", thread_start}, + {"setCpuLimit", thread_setCpuLimit}, + {NULL, NULL} +}; + +static const struct luaL_Reg thread_methods[] = { + {"join", thread_join}, + {"lastError", thread_lastError}, + {"destroy", thread_destroy}, + {"__gc", thread_destroy}, + {NULL, NULL} +}; + +int luaopen_thread_lib(lua_State *L) { + luaL_newmetatable(L, "LThread"); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, thread_methods, 0); + + luaL_newlib(L, thread_lib); + return 1; +} + +void load_thread_lib(lua_State *L) { + luaL_requiref(L, "ctr.thread", luaopen_thread_lib, 0); +}