diff options
| author | Alexey Melnichuk <alexeymelnichuck@gmail.com> | 2018-08-27 20:24:22 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-27 20:24:22 +0300 |
| commit | 00ca97711b657c7d395d91212364a82dac1d4625 (patch) | |
| tree | 07d166e87c2f294a0864501756e48d3c313309bb | |
| parent | e33999a890c8bfdb0c1f753820e4261dabb67faa (diff) | |
| parent | cd91518d79388d5d42820a2b48918a7bf1e6d1a2 (diff) | |
| download | lua-llthreads2-00ca97711b657c7d395d91212364a82dac1d4625.tar.gz lua-llthreads2-00ca97711b657c7d395d91212364a82dac1d4625.tar.bz2 lua-llthreads2-00ca97711b657c7d395d91212364a82dac1d4625.zip | |
Merge pull request #16 from osch/master
new method thread:interrupt()
| -rw-r--r-- | .travis.yml | 1 | ||||
| -rw-r--r-- | appveyor.yml | 1 | ||||
| -rw-r--r-- | lakefile | 1 | ||||
| -rw-r--r-- | src/llthread.c | 37 | ||||
| -rw-r--r-- | src/lua/llthreads2/ex.lua | 9 | ||||
| -rw-r--r-- | test/test_interrupt.lua | 58 |
6 files changed, 107 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml index d629f05..19f6f5b 100644 --- a/.travis.yml +++ b/.travis.yml | |||
| @@ -57,6 +57,7 @@ script: | |||
| 57 | - lua test_threads_ex_opt_2.lua | 57 | - lua test_threads_ex_opt_2.lua |
| 58 | - lua test_threads_attr.lua | 58 | - lua test_threads_attr.lua |
| 59 | - lua test_integer.lua | 59 | - lua test_integer.lua |
| 60 | - lua test_interrupt.lua | ||
| 60 | # - lua test_register_llthreads.lua | 61 | # - lua test_register_llthreads.lua |
| 61 | 62 | ||
| 62 | notifications: | 63 | notifications: |
diff --git a/appveyor.yml b/appveyor.yml index db2206e..46a3235 100644 --- a/appveyor.yml +++ b/appveyor.yml | |||
| @@ -72,6 +72,7 @@ test_script: | |||
| 72 | - lua test_threads_ex_opt_2.lua | 72 | - lua test_threads_ex_opt_2.lua |
| 73 | - lua test_threads_attr.lua | 73 | - lua test_threads_attr.lua |
| 74 | - lua test_integer.lua | 74 | - lua test_integer.lua |
| 75 | - lua test_interrupt.lua | ||
| 75 | # - lua test_register_llthreads.lua | 76 | # - lua test_register_llthreads.lua |
| 76 | 77 | ||
| 77 | after_test: | 78 | after_test: |
| @@ -44,6 +44,7 @@ target('test', install, function() | |||
| 44 | run_test('test_threads_ex_opt.lua') | 44 | run_test('test_threads_ex_opt.lua') |
| 45 | run_test('test_threads_ex_opt_2.lua') | 45 | run_test('test_threads_ex_opt_2.lua') |
| 46 | run_test('test_threads_attr.lua') | 46 | run_test('test_threads_attr.lua') |
| 47 | run_test('test_interrupt.lua') | ||
| 47 | 48 | ||
| 48 | 49 | ||
| 49 | if not test_summary() then | 50 | if not test_summary() then |
diff --git a/src/llthread.c b/src/llthread.c index 3155113..66efe7c 100644 --- a/src/llthread.c +++ b/src/llthread.c | |||
| @@ -98,11 +98,17 @@ typedef pthread_t os_thread_t; | |||
| 98 | 98 | ||
| 99 | #define LLTHREAD_OPEN_NAME LLTHREAD_OPEN_NAME_IMPL(LLTHREAD_MODULE_NAME) | 99 | #define LLTHREAD_OPEN_NAME LLTHREAD_OPEN_NAME_IMPL(LLTHREAD_MODULE_NAME) |
| 100 | 100 | ||
| 101 | #define LLTHREAD_STRINGIFY(x) #x | ||
| 102 | #define LLTHREAD_TOSTRING(x) LLTHREAD_STRINGIFY(x) | ||
| 103 | #define LLTHREAD_MODULE_NAME_STRING LLTHREAD_TOSTRING(LLTHREAD_MODULE_NAME) | ||
| 104 | |||
| 105 | |||
| 101 | LLTHREADS_EXPORT_API int LLTHREAD_OPEN_NAME(lua_State *L); | 106 | LLTHREADS_EXPORT_API int LLTHREAD_OPEN_NAME(lua_State *L); |
| 102 | 107 | ||
| 103 | #define LLTHREAD_NAME "LLThread" | 108 | #define LLTHREAD_NAME "LLThread" |
| 104 | static const char *LLTHREAD_TAG = LLTHREAD_NAME; | 109 | static const char *LLTHREAD_TAG = LLTHREAD_NAME; |
| 105 | static const char *LLTHREAD_LOGGER_HOLDER = LLTHREAD_NAME " logger holder"; | 110 | static const char *LLTHREAD_LOGGER_HOLDER = LLTHREAD_NAME " logger holder"; |
| 111 | static const char* LLTHREAD_INTERRUPTED_ERROR = LLTHREAD_MODULE_NAME_STRING ": thread was interrupted"; | ||
| 106 | 112 | ||
| 107 | typedef struct llthread_child_t { | 113 | typedef struct llthread_child_t { |
| 108 | lua_State *L; | 114 | lua_State *L; |
| @@ -694,6 +700,32 @@ static int l_llthread_new(lua_State *L) { | |||
| 694 | return 1; | 700 | return 1; |
| 695 | } | 701 | } |
| 696 | 702 | ||
| 703 | static void llthread_interrupt1(lua_State *L, lua_Debug *ar) { | ||
| 704 | (void)ar; /* unused arg. */ | ||
| 705 | lua_sethook(L, NULL, 0, 0); /* reset hook */ | ||
| 706 | luaL_error(L, LLTHREAD_INTERRUPTED_ERROR); | ||
| 707 | } | ||
| 708 | static void llthread_interrupt2(lua_State *L, lua_Debug *ar) { | ||
| 709 | (void)ar; /* unused arg. */ | ||
| 710 | luaL_error(L, LLTHREAD_INTERRUPTED_ERROR); | ||
| 711 | } | ||
| 712 | |||
| 713 | static int l_llthread_interrupt(lua_State *L) { | ||
| 714 | llthread_t *this = l_llthread_at(L, 1); | ||
| 715 | llthread_child_t *child = this->child; | ||
| 716 | lua_Hook hook = llthread_interrupt1; | ||
| 717 | if (!lua_isnoneornil(L, 2)) | ||
| 718 | hook = lua_toboolean(L, 2) ? llthread_interrupt2 : NULL; | ||
| 719 | if (child) { | ||
| 720 | if (hook) | ||
| 721 | lua_sethook(child->L, hook, LUA_MASKCALL|LUA_MASKRET|LUA_MASKCOUNT, 1); | ||
| 722 | else | ||
| 723 | lua_sethook(child->L, NULL, 0, 0); /* reset hook */ | ||
| 724 | } | ||
| 725 | return 0; | ||
| 726 | } | ||
| 727 | |||
| 728 | |||
| 697 | static const struct luaL_Reg l_llthread_meth[] = { | 729 | static const struct luaL_Reg l_llthread_meth[] = { |
| 698 | {"start", l_llthread_start }, | 730 | {"start", l_llthread_start }, |
| 699 | {"join", l_llthread_join }, | 731 | {"join", l_llthread_join }, |
| @@ -701,6 +733,7 @@ static const struct luaL_Reg l_llthread_meth[] = { | |||
| 701 | {"started", l_llthread_started }, | 733 | {"started", l_llthread_started }, |
| 702 | {"detached", l_llthread_detached }, | 734 | {"detached", l_llthread_detached }, |
| 703 | {"joinable", l_llthread_joinable }, | 735 | {"joinable", l_llthread_joinable }, |
| 736 | {"interrupt", l_llthread_interrupt }, | ||
| 704 | {"__gc", l_llthread_delete }, | 737 | {"__gc", l_llthread_delete }, |
| 705 | 738 | ||
| 706 | {NULL, NULL} | 739 | {NULL, NULL} |
| @@ -769,5 +802,9 @@ LLTHREADS_EXPORT_API int LLTHREAD_OPEN_NAME(lua_State *L) { | |||
| 769 | l_llthread_push_version(L); | 802 | l_llthread_push_version(L); |
| 770 | lua_rawset(L, -3); | 803 | lua_rawset(L, -3); |
| 771 | 804 | ||
| 805 | lua_pushliteral(L, "interrupted_error"); | ||
| 806 | lua_pushstring(L, LLTHREAD_INTERRUPTED_ERROR); | ||
| 807 | lua_rawset(L, -3); | ||
| 808 | |||
| 772 | return 1; | 809 | return 1; |
| 773 | } | 810 | } |
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() | |||
| 141 | return self.thread:joinable() | 141 | return self.thread:joinable() |
| 142 | end | 142 | end |
| 143 | 143 | ||
| 144 | --- Interrupt thread | ||
| 145 | -- The thread is interrupted by installing a debug hook that | ||
| 146 | -- creates an error. | ||
| 147 | -- @tparam ?boolean if not given, interrupt only once, | ||
| 148 | -- otherwise this arg sets or unsets permanent interrupt. | ||
| 149 | function thread_mt:interrupt(arg) | ||
| 150 | return self.thread:interrupt(arg) | ||
| 151 | end | ||
| 152 | |||
| 144 | end | 153 | end |
| 145 | ------------------------------------------------------------------------------- | 154 | ------------------------------------------------------------------------------- |
| 146 | 155 | ||
diff --git a/test/test_interrupt.lua b/test/test_interrupt.lua new file mode 100644 index 0000000..22c168e --- /dev/null +++ b/test/test_interrupt.lua | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | local llthreads = require"llthreads" | ||
| 2 | local utils = require "utils" | ||
| 3 | local sleep = utils.sleep | ||
| 4 | |||
| 5 | local include = utils.thread_init .. [[ | ||
| 6 | local llthreads = require"llthreads" | ||
| 7 | local sleep = require "utils".sleep | ||
| 8 | ]] | ||
| 9 | |||
| 10 | do | ||
| 11 | local thread = llthreads.new(include .. [[ | ||
| 12 | for i = 1, 10 do sleep(1) end | ||
| 13 | ]]) | ||
| 14 | |||
| 15 | thread:start() | ||
| 16 | sleep(1) | ||
| 17 | thread:interrupt() | ||
| 18 | |||
| 19 | local ok, err = thread:join() | ||
| 20 | print("thread1:join(): ", ok, err) | ||
| 21 | assert(ok == false and err:match(llthreads.interrupted_error), "thread1 result") | ||
| 22 | print("--- Done interrupt1!") | ||
| 23 | end | ||
| 24 | |||
| 25 | |||
| 26 | do | ||
| 27 | local thread = llthreads.new(include .. [[ | ||
| 28 | local ok, err = pcall(function() for i = 1, 10 do sleep(1) end end) | ||
| 29 | print("thread2:", ok, err) | ||
| 30 | assert(ok == false and err:match(llthreads.interrupted_error), "interrupt2 result") | ||
| 31 | ]]) | ||
| 32 | |||
| 33 | thread:start() | ||
| 34 | sleep(1) | ||
| 35 | thread:interrupt() | ||
| 36 | |||
| 37 | local ok, err = thread:join() | ||
| 38 | print("thread2:join(): ", ok, err) | ||
| 39 | assert(ok, "thread2 result") | ||
| 40 | print("--- Done interrupt2!") | ||
| 41 | end | ||
| 42 | |||
| 43 | do | ||
| 44 | local thread = llthreads.new(include .. [[ | ||
| 45 | local ok, err = pcall(function() for i = 1, 10 do sleep(1) end end) | ||
| 46 | print("thread3:", ok, err) | ||
| 47 | ]]) | ||
| 48 | |||
| 49 | thread:start() | ||
| 50 | sleep(1) | ||
| 51 | thread:interrupt(true) | ||
| 52 | |||
| 53 | local ok, err = thread:join() | ||
| 54 | print("thread3:join(): ", ok, err) | ||
| 55 | assert(ok == false and err:match(llthreads.interrupted_error), "thread3 result") | ||
| 56 | print("--- Done interrupt3!") | ||
| 57 | end | ||
| 58 | |||
