From af09c42e8067dfc832f7e1dce92860e1022c75fa Mon Sep 17 00:00:00 2001 From: amelia squires Date: Tue, 14 Oct 2025 21:46:38 -0500 Subject: tons of thread changed, more testing needed --- library/lullaby/thread.lua | 7 +++++- makefile | 3 +++ src/net.c | 1 - src/thread.c | 60 ++++++++++++++++++++++++++++++++++++++++++---- src/thread.h | 4 ++++ tests/kill.lua | 15 ++++++++++++ tests/tests.lua | 1 - 7 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 tests/kill.lua diff --git a/library/lullaby/thread.lua b/library/lullaby/thread.lua index 6015a0b..f529049 100644 --- a/library/lullaby/thread.lua +++ b/library/lullaby/thread.lua @@ -16,11 +16,16 @@ function async.await(T) end ---@return nil function async.clean(T) end ----stops the thread +---stops the thread, may be unavaliable on some systems (android) and will call async:kill instead ---@param T async-table ---@return nil function async.close(T) end +---stops the thread forcefully, may cause problems +---@param T async-table +---@return nil +function async.kill(T) end + ---contains data for the thread ---@deprecated ---@type lightuserdata diff --git a/makefile b/makefile index 2e82331..3c69707 100644 --- a/makefile +++ b/makefile @@ -57,6 +57,9 @@ debug: all san: CFLAGS += -ggdb3 -static-libasan -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls san: all +tsan: CFLAGS += -ggdb3 -static-libasan -fsanitize=undefined -fsanitize=thread -fno-omit-frame-pointer -fno-optimize-sibling-calls +tsan: all + reg: rm src/reg.o diff --git a/src/net.c b/src/net.c index 0abfe04..71168c0 100644 --- a/src/net.c +++ b/src/net.c @@ -928,7 +928,6 @@ net_end: lua_close(L); threads--; - printf("out\n"); return NULL; } diff --git a/src/thread.c b/src/thread.c index b113915..da4bcb5 100644 --- a/src/thread.c +++ b/src/thread.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "types/str.h" #include "util.h" @@ -15,7 +16,7 @@ struct thread_info { lua_State* L; int return_count, done; pthread_t tid; - pthread_mutex_t* lock; + pthread_mutex_t* lock, *ready_lock; }; #include "io.h" @@ -168,11 +169,23 @@ int l_res(lua_State* L){ return 1; } +void _thread_exit_signal(int i){ + pthread_exit(NULL); +} + void* handle_thread(void* _args){ struct thread_info* args = (struct thread_info*)_args; lua_State* L = args->L; + pthread_mutex_lock(&*args->lock); + +#ifdef SUPPORTS_PTHREAD_CANCEL pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); +#endif + pthread_detach(args->tid); + signal(SIGUSR1, _thread_exit_signal); + + pthread_mutex_unlock(&*args->ready_lock); lua_newtable(L); int res_idx = lua_gettop(L); @@ -202,9 +215,11 @@ int _thread_await(lua_State* L){ lua_pushstring(L, "_"); lua_gettable(L, 1); struct thread_info* info = lua_touserdata(L, -1); - if(info->L == NULL) luaI_error(L, -1, "thread was already closed") - if(!info->done) pthread_mutex_lock(&*info->lock); + //maybe error here if tid is zero + if(!info->done && info->tid != 0){ + pthread_mutex_lock(&*info->lock); + } info->done = 1; env_table(info->L, 0); @@ -245,6 +260,14 @@ int _thread_clean(lua_State* L){ if(info != NULL && info->L != NULL){ luaI_tsetnil(L, 1, "_"); + if(info->tid != 0){ +#ifdef SUPPORTS_PTHREAD_CANCEL + pthread_cancel(info->tid); +#else + pthread_kill(info->tid, SIGUSR1); +#endif + } + //lua_gc(info->L, LUA_GCRESTART); lua_gc(info->L, LUA_GCCOLLECT); @@ -254,18 +277,37 @@ int _thread_clean(lua_State* L){ pthread_mutex_destroy(&*info->lock); free(info->lock); - pthread_cancel(info->tid); + free(info); } return 0; } + int _thread_close(lua_State* L){ +#ifdef SUPPORTS_PTHREAD_CANCEL + lua_pushstring(L, "_"); lua_gettable(L, 1); struct thread_info* info = lua_touserdata(L, -1); pthread_cancel(info->tid); + info->tid = 0; + + return 0; +#else + return _thread_kill(L); +#endif +} + + +int _thread_kill(lua_State* L){ + lua_pushstring(L, "_"); + lua_gettable(L, 1); + struct thread_info* info = lua_touserdata(L, -1); + + pthread_kill(info->tid, SIGUSR1); + info->tid = 0; return 0; } @@ -280,20 +322,28 @@ int l_async(lua_State* oL){ struct thread_info* args = calloc(1, sizeof * args); args->L = L; args->lock = malloc(sizeof * args->lock); + args->ready_lock = malloc(sizeof * args->ready_lock); pthread_mutex_init(&*args->lock, NULL); - pthread_mutex_lock(&*args->lock); + pthread_mutex_init(&*args->ready_lock, NULL); args->return_count = 0; args->function = str_init(""); lua_pushvalue(oL, 1); lua_dump(oL, writer, (void*)args->function, 0); + pthread_mutex_lock(&*args->ready_lock); pthread_create(&args->tid, NULL, handle_thread, (void*)args); + pthread_mutex_lock(&*args->ready_lock); + + pthread_mutex_unlock(&*args->ready_lock); + pthread_mutex_destroy(&*args->ready_lock); + free(args->ready_lock); lua_newtable(oL); int res_idx = lua_gettop(oL); luaI_tsetcf(oL, res_idx, "await", _thread_await); luaI_tsetcf(oL, res_idx, "clean", _thread_clean); + luaI_tsetcf(oL, res_idx, "kill", _thread_kill); luaI_tsetcf(oL, res_idx, "close", _thread_close); luaI_tsetlud(oL, res_idx, "_", args); diff --git a/src/thread.h b/src/thread.h index 0b3a27d..4fa0e04 100644 --- a/src/thread.h +++ b/src/thread.h @@ -1,6 +1,10 @@ #include "lua.h" #include "config.h" +#ifndef __ANDROID__ +#define SUPPORTS_PTHREAD_CANCEL +#endif + int l_async(lua_State*); int l_tlock(lua_State*); int l_tunlock(lua_State*); diff --git a/tests/kill.lua b/tests/kill.lua new file mode 100644 index 0000000..53344dc --- /dev/null +++ b/tests/kill.lua @@ -0,0 +1,15 @@ +local llby = require"lullaby" + +local t = llby.thread.async(function(res) + for i = 1, 50 do + print(i) + os.execute("sleep 1") + end +end) + +os.execute("sleep 5") + +print("killing") +t:close() +t:await() +print("after kill") diff --git a/tests/tests.lua b/tests/tests.lua index 6dae570..39c4d12 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -20,7 +20,6 @@ end local handle = assert(io.popen("find tests/units/".. search .." -type f")) for file in handle:lines() do - print(_G._locals) total = total + 1 local f = loadfile(file)() -- cgit v1.2.3