From 535e00626b7e93b32d5a99638d784ede66313cf6 Mon Sep 17 00:00:00 2001 From: osch Date: Tue, 21 Aug 2018 20:44:03 +0200 Subject: new method thread:interrupt() --- src/llthread.c | 27 +++++++++++++++++++++++++++ src/lua/llthreads2/ex.lua | 9 +++++++++ 2 files changed, 36 insertions(+) diff --git a/src/llthread.c b/src/llthread.c index 3155113..c78d766 100644 --- a/src/llthread.c +++ b/src/llthread.c @@ -694,6 +694,32 @@ static int l_llthread_new(lua_State *L) { return 1; } +static void llthread_interrupt1(lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); /* reset hook */ + luaL_error(L, "interrupted!"); +} +static void llthread_interrupt2(lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + luaL_error(L, "interrupted!"); +} + +static int l_llthread_interrupt(lua_State *L) { + llthread_t *this = l_llthread_at(L, 1); + llthread_child_t *child = this->child; + lua_Hook hook = llthread_interrupt1; + if (!lua_isnoneornil(L, 2)) + hook = lua_toboolean(L, 2) ? llthread_interrupt2 : NULL; + if (child) { + if (hook) + lua_sethook(child->L, hook, LUA_MASKCALL|LUA_MASKRET|LUA_MASKCOUNT, 1); + else + lua_sethook(child->L, NULL, 0, 0); /* reset hook */ + } + return 0; +} + + static const struct luaL_Reg l_llthread_meth[] = { {"start", l_llthread_start }, {"join", l_llthread_join }, @@ -701,6 +727,7 @@ static const struct luaL_Reg l_llthread_meth[] = { {"started", l_llthread_started }, {"detached", l_llthread_detached }, {"joinable", l_llthread_joinable }, + {"interrupt", l_llthread_interrupt }, {"__gc", l_llthread_delete }, {NULL, NULL} diff --git a/src/lua/llthreads2/ex.lua b/src/lua/llthreads2/ex.lua index f0c27d9..b943f5b 100644 --- a/src/lua/llthreads2/ex.lua +++ b/src/lua/llthreads2/ex.lua @@ -141,6 +141,15 @@ function thread_mt:joinable() return self.thread:joinable() end +--- Interrupt thread +-- The thread is interrupted by installing a debug hook that +-- creates an error. +-- @tparam ?boolean if not given, interrupt only once, +-- otherwise this arg sets or unsets permanent interrupt. +function thread_mt:interrupt(arg) + return self.thread:interrupt(arg) +end + end ------------------------------------------------------------------------------- -- cgit v1.2.3-55-g6feb From e09400b21d004b174d1a6e07ed4a98c5648a2ab8 Mon Sep 17 00:00:00 2001 From: osch Date: Wed, 22 Aug 2018 09:29:19 +0200 Subject: test_interrupt.lua --- appveyor.yml | 1 + lakefile | 1 + test/test_interrupt.lua | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 test/test_interrupt.lua diff --git a/appveyor.yml b/appveyor.yml index db2206e..46a3235 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -72,6 +72,7 @@ test_script: - lua test_threads_ex_opt_2.lua - lua test_threads_attr.lua - lua test_integer.lua + - lua test_interrupt.lua # - lua test_register_llthreads.lua after_test: diff --git a/lakefile b/lakefile index fab4646..af9661e 100644 --- a/lakefile +++ b/lakefile @@ -44,6 +44,7 @@ target('test', install, function() run_test('test_threads_ex_opt.lua') run_test('test_threads_ex_opt_2.lua') run_test('test_threads_attr.lua') + run_test('test_interrupt.lua') if not test_summary() then diff --git a/test/test_interrupt.lua b/test/test_interrupt.lua new file mode 100644 index 0000000..6a7a255 --- /dev/null +++ b/test/test_interrupt.lua @@ -0,0 +1,58 @@ +local llthreads = require"llthreads" +local utils = require "utils" +local sleep = utils.sleep + +local include = utils.thread_init .. [[ +local llthreads = require"llthreads" +local sleep = require "utils".sleep +]] + +do + local thread = llthreads.new(include .. [[ + for i = 1, 10 do sleep(1) end + ]]) + + thread:start() + sleep(1) + thread:interrupt() + + local ok, err = thread:join() + print("thread1:join(): ", ok, err) + assert(ok == false and err:match("interrupted!"), "thread1 result") + print("--- Done interrupt1!") +end + + +do + local thread = llthreads.new(include .. [[ + local ok, err = pcall(function() for i = 1, 10 do sleep(1) end end) + print("thread2:", ok, err) + assert(ok == false and err:match("interrupted!"), "interrupt2 result") + ]]) + + thread:start() + sleep(1) + thread:interrupt() + + local ok, err = thread:join() + print("thread2:join(): ", ok, err) + assert(ok, "thread2 result") + print("--- Done interrupt2!") +end + +do + local thread = llthreads.new(include .. [[ + local ok, err = pcall(function() for i = 1, 10 do sleep(1) end end) + print("thread3:", ok, err) + ]]) + + thread:start() + sleep(1) + thread:interrupt(true) + + local ok, err = thread:join() + print("thread3:join(): ", ok, err) + assert(ok == false and err:match("interrupted!"), "thread3 result") + print("--- Done interrupt3!") +end + -- cgit v1.2.3-55-g6feb From 99e9a506b4f0f2dcefb1844092553ca4ffa81087 Mon Sep 17 00:00:00 2001 From: osch Date: Wed, 22 Aug 2018 09:39:32 +0200 Subject: invoke test_interrupt.lua also in .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d629f05..19f6f5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,6 +57,7 @@ script: - lua test_threads_ex_opt_2.lua - lua test_threads_attr.lua - lua test_integer.lua + - lua test_interrupt.lua # - lua test_register_llthreads.lua notifications: -- cgit v1.2.3-55-g6feb From cd91518d79388d5d42820a2b48918a7bf1e6d1a2 Mon Sep 17 00:00:00 2001 From: osch Date: Mon, 27 Aug 2018 19:06:15 +0200 Subject: interrupted error message now contains llthreads module name as prefix and is also available in the public api --- src/llthread.c | 14 ++++++++++++-- test/test_interrupt.lua | 6 +++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/llthread.c b/src/llthread.c index c78d766..66efe7c 100644 --- a/src/llthread.c +++ b/src/llthread.c @@ -98,11 +98,17 @@ typedef pthread_t os_thread_t; #define LLTHREAD_OPEN_NAME LLTHREAD_OPEN_NAME_IMPL(LLTHREAD_MODULE_NAME) +#define LLTHREAD_STRINGIFY(x) #x +#define LLTHREAD_TOSTRING(x) LLTHREAD_STRINGIFY(x) +#define LLTHREAD_MODULE_NAME_STRING LLTHREAD_TOSTRING(LLTHREAD_MODULE_NAME) + + LLTHREADS_EXPORT_API int LLTHREAD_OPEN_NAME(lua_State *L); #define LLTHREAD_NAME "LLThread" static const char *LLTHREAD_TAG = LLTHREAD_NAME; static const char *LLTHREAD_LOGGER_HOLDER = LLTHREAD_NAME " logger holder"; +static const char* LLTHREAD_INTERRUPTED_ERROR = LLTHREAD_MODULE_NAME_STRING ": thread was interrupted"; typedef struct llthread_child_t { lua_State *L; @@ -697,11 +703,11 @@ static int l_llthread_new(lua_State *L) { static void llthread_interrupt1(lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ lua_sethook(L, NULL, 0, 0); /* reset hook */ - luaL_error(L, "interrupted!"); + luaL_error(L, LLTHREAD_INTERRUPTED_ERROR); } static void llthread_interrupt2(lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ - luaL_error(L, "interrupted!"); + luaL_error(L, LLTHREAD_INTERRUPTED_ERROR); } static int l_llthread_interrupt(lua_State *L) { @@ -796,5 +802,9 @@ LLTHREADS_EXPORT_API int LLTHREAD_OPEN_NAME(lua_State *L) { l_llthread_push_version(L); lua_rawset(L, -3); + lua_pushliteral(L, "interrupted_error"); + lua_pushstring(L, LLTHREAD_INTERRUPTED_ERROR); + lua_rawset(L, -3); + return 1; } diff --git a/test/test_interrupt.lua b/test/test_interrupt.lua index 6a7a255..22c168e 100644 --- a/test/test_interrupt.lua +++ b/test/test_interrupt.lua @@ -18,7 +18,7 @@ do local ok, err = thread:join() print("thread1:join(): ", ok, err) - assert(ok == false and err:match("interrupted!"), "thread1 result") + assert(ok == false and err:match(llthreads.interrupted_error), "thread1 result") print("--- Done interrupt1!") end @@ -27,7 +27,7 @@ do local thread = llthreads.new(include .. [[ local ok, err = pcall(function() for i = 1, 10 do sleep(1) end end) print("thread2:", ok, err) - assert(ok == false and err:match("interrupted!"), "interrupt2 result") + assert(ok == false and err:match(llthreads.interrupted_error), "interrupt2 result") ]]) thread:start() @@ -52,7 +52,7 @@ do local ok, err = thread:join() print("thread3:join(): ", ok, err) - assert(ok == false and err:match("interrupted!"), "thread3 result") + assert(ok == false and err:match(llthreads.interrupted_error), "thread3 result") print("--- Done interrupt3!") end -- cgit v1.2.3-55-g6feb