diff options
author | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2019-04-26 12:20:06 +0200 |
---|---|---|
committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2019-04-26 12:20:06 +0200 |
commit | 9c84074c89661cd1e776eff3d4aa5329a2ac9524 (patch) | |
tree | 3c424371c1f21f4dee493793c8316059bf8217c6 /src | |
parent | 32f8cdfc73ed90dcf88ffcf4bfc1a3e4d5a69e6c (diff) | |
download | lanes-9c84074c89661cd1e776eff3d4aa5329a2ac9524.tar.gz lanes-9c84074c89661cd1e776eff3d4aa5329a2ac9524.tar.bz2 lanes-9c84074c89661cd1e776eff3d4aa5329a2ac9524.zip |
Lane cancellation rework
opt.cancelstep is gone, hook is installed by lane:cancel() if requested
lane:cancel() rework (see doc)
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/cancel.c | 117 | ||||
-rw-r--r-- | src/cancel.h | 15 | ||||
-rw-r--r-- | src/lanes.c | 67 | ||||
-rw-r--r-- | src/lanes.h | 2 | ||||
-rw-r--r-- | src/lanes.lua | 17 | ||||
-rw-r--r-- | src/lanes_private.h | 3 |
7 files changed, 133 insertions, 90 deletions
diff --git a/src/Makefile b/src/Makefile index aff06ba..9dc75a1 100644 --- a/src/Makefile +++ b/src/Makefile | |||
@@ -7,7 +7,7 @@ | |||
7 | 7 | ||
8 | MODULE=lanes | 8 | MODULE=lanes |
9 | 9 | ||
10 | SRC=lanes.c compat.c threading.c tools.c linda.c deep.c keeper.c universe.c | 10 | SRC=lanes.c cancel.c compat.c threading.c tools.c linda.c deep.c keeper.c universe.c |
11 | 11 | ||
12 | OBJ=$(SRC:.c=.o) | 12 | OBJ=$(SRC:.c=.o) |
13 | 13 | ||
diff --git a/src/cancel.c b/src/cancel.c index 11e100d..8ce00c8 100644 --- a/src/cancel.c +++ b/src/cancel.c | |||
@@ -77,12 +77,13 @@ LUAG_FUNC( cancel_test) | |||
77 | // ################################################################################################ | 77 | // ################################################################################################ |
78 | // ################################################################################################ | 78 | // ################################################################################################ |
79 | 79 | ||
80 | void cancel_hook( lua_State* L, lua_Debug* ar) | 80 | static void cancel_hook( lua_State* L, lua_Debug* ar) |
81 | { | 81 | { |
82 | (void)ar; | 82 | (void)ar; |
83 | DEBUGSPEW_CODE( fprintf( stderr, "cancel_hook\n")); | 83 | DEBUGSPEW_CODE( fprintf( stderr, "cancel_hook\n")); |
84 | if( cancel_test( L) != CANCEL_NONE) | 84 | if( cancel_test( L) != CANCEL_NONE) |
85 | { | 85 | { |
86 | lua_sethook( L, NULL, 0, 0); | ||
86 | cancel_error( L); | 87 | cancel_error( L); |
87 | } | 88 | } |
88 | } | 89 | } |
@@ -110,10 +111,10 @@ void cancel_hook( lua_State* L, lua_Debug* ar) | |||
110 | 111 | ||
111 | // ################################################################################################ | 112 | // ################################################################################################ |
112 | 113 | ||
113 | static cancel_result thread_cancel_soft( Lane* s, bool_t wake_lindas_) | 114 | static cancel_result thread_cancel_soft( Lane* s, double secs_, bool_t wake_lindas_) |
114 | { | 115 | { |
115 | s->cancel_request = CANCEL_SOFT; // it's now signaled to stop | 116 | s->cancel_request = CANCEL_SOFT; // it's now signaled to stop |
116 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own | 117 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own |
117 | if( wake_lindas_) // wake the thread so that execution returns from any pending linda operation if desired | 118 | if( wake_lindas_) // wake the thread so that execution returns from any pending linda operation if desired |
118 | { | 119 | { |
119 | SIGNAL_T *waiting_on = s->waiting_on; | 120 | SIGNAL_T *waiting_on = s->waiting_on; |
@@ -122,8 +123,8 @@ static cancel_result thread_cancel_soft( Lane* s, bool_t wake_lindas_) | |||
122 | SIGNAL_ALL( waiting_on); | 123 | SIGNAL_ALL( waiting_on); |
123 | } | 124 | } |
124 | } | 125 | } |
125 | // say we succeeded though | 126 | |
126 | return CR_Cancelled; | 127 | return THREAD_WAIT( &s->thread, secs_, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout; |
127 | } | 128 | } |
128 | 129 | ||
129 | // ################################################################################################ | 130 | // ################################################################################################ |
@@ -163,9 +164,9 @@ static cancel_result thread_cancel_hard( lua_State* L, Lane* s, double secs_, bo | |||
163 | (void) waitkill_timeout_; // unused | 164 | (void) waitkill_timeout_; // unused |
164 | (void) L; // unused | 165 | (void) L; // unused |
165 | #endif // THREADAPI == THREADAPI_PTHREAD | 166 | #endif // THREADAPI == THREADAPI_PTHREAD |
166 | s->mstatus = KILLED; // mark 'gc' to wait for it | 167 | s->mstatus = KILLED; // mark 'gc' to wait for it |
167 | // note that s->status value must remain to whatever it was at the time of the kill | 168 | // note that s->status value must remain to whatever it was at the time of the kill |
168 | // because we need to know if we can lua_close() the Lua State or not. | 169 | // because we need to know if we can lua_close() the Lua State or not. |
169 | result = CR_Killed; | 170 | result = CR_Killed; |
170 | } | 171 | } |
171 | return result; | 172 | return result; |
@@ -173,7 +174,7 @@ static cancel_result thread_cancel_hard( lua_State* L, Lane* s, double secs_, bo | |||
173 | 174 | ||
174 | // ################################################################################################ | 175 | // ################################################################################################ |
175 | 176 | ||
176 | cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_) | 177 | cancel_result thread_cancel( lua_State* L, Lane* s, CancelOp op_, double secs_, bool_t force_, double waitkill_timeout_) |
177 | { | 178 | { |
178 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here | 179 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here |
179 | // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) | 180 | // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) |
@@ -190,9 +191,9 @@ cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, | |||
190 | 191 | ||
191 | // signal the linda the wake up the thread so that it can react to the cancel query | 192 | // signal the linda the wake up the thread so that it can react to the cancel query |
192 | // let us hope we never land here with a pointer on a linda that has been destroyed... | 193 | // let us hope we never land here with a pointer on a linda that has been destroyed... |
193 | if( secs_ < 0.0) | 194 | if( op_ == CO_Soft) |
194 | { | 195 | { |
195 | return thread_cancel_soft( s, force_); | 196 | return thread_cancel_soft( s, secs_, force_); |
196 | } | 197 | } |
197 | 198 | ||
198 | return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_); | 199 | return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_); |
@@ -201,49 +202,97 @@ cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, | |||
201 | // ################################################################################################ | 202 | // ################################################################################################ |
202 | // ################################################################################################ | 203 | // ################################################################################################ |
203 | 204 | ||
204 | // lane_h:cancel( [timeout] [, force [, forcekill_timeout]]) | 205 | // > 0: the mask |
206 | // = 0: soft | ||
207 | // < 0: hard | ||
208 | static CancelOp which_op( lua_State* L, int idx_) | ||
209 | { | ||
210 | if( lua_type( L, idx_) == LUA_TSTRING) | ||
211 | { | ||
212 | CancelOp op = CO_Invalid; | ||
213 | char const* str = lua_tostring( L, idx_); | ||
214 | if( strcmp( str, "soft") == 0) | ||
215 | { | ||
216 | op = CO_Soft; | ||
217 | } | ||
218 | else if( strcmp( str, "count") == 0) | ||
219 | { | ||
220 | op = CO_Count; | ||
221 | } | ||
222 | else if( strcmp( str, "line") == 0) | ||
223 | { | ||
224 | op = CO_Line; | ||
225 | } | ||
226 | else if( strcmp( str, "call") == 0) | ||
227 | { | ||
228 | op = CO_Call; | ||
229 | } | ||
230 | else if( strcmp( str, "ret") == 0) | ||
231 | { | ||
232 | op = CO_Ret; | ||
233 | } | ||
234 | else if( strcmp( str, "hard") == 0) | ||
235 | { | ||
236 | op = CO_Hard; | ||
237 | } | ||
238 | lua_remove( L, idx_); // argument is processed, remove it | ||
239 | if( op == CO_Invalid) | ||
240 | { | ||
241 | luaL_error( L, "invalid hook option %s", str); | ||
242 | } | ||
243 | return op; | ||
244 | } | ||
245 | return CO_Hard; | ||
246 | } | ||
247 | // ################################################################################################ | ||
248 | |||
249 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, force [, forcekill_timeout]]) | ||
205 | LUAG_FUNC( thread_cancel) | 250 | LUAG_FUNC( thread_cancel) |
206 | { | 251 | { |
207 | Lane* s = lua_toLane( L, 1); | 252 | Lane* s = lua_toLane( L, 1); |
208 | double secs = 0.0; | 253 | double secs = 0.0; |
209 | int force_i = 2; | 254 | CancelOp op = which_op( L, 2); // this removes the op string from the stack |
210 | int forcekill_timeout_i = 3; | ||
211 | 255 | ||
212 | if( lua_isnumber( L, 2)) | 256 | if( op > 0) // hook is requested |
213 | { | 257 | { |
214 | secs = lua_tonumber( L, 2); | 258 | int hook_count = (int) lua_tointeger( L, 2); |
215 | if( secs < 0.0 && lua_gettop( L) > 3) | 259 | lua_remove( L, 2); // argument is processed, remove it |
260 | if( hook_count < 1) | ||
216 | { | 261 | { |
217 | return luaL_error( L, "can't force_kill a soft cancel"); | 262 | return luaL_error( L, "hook count cannot be < 1"); |
218 | } | 263 | } |
219 | // negative timeout and force flag means we want to wake linda-waiting threads | 264 | lua_sethook( s->L, cancel_hook, op, hook_count); |
220 | ++ force_i; | ||
221 | ++ forcekill_timeout_i; | ||
222 | } | 265 | } |
223 | else if( lua_isnil( L, 2)) | 266 | |
267 | if( lua_type( L, 2) == LUA_TNUMBER) | ||
224 | { | 268 | { |
225 | ++ force_i; | 269 | secs = lua_tonumber( L, 2); |
226 | ++ forcekill_timeout_i; | 270 | lua_remove( L, 2); // argument is processed, remove it |
271 | if( secs < 0.0) | ||
272 | { | ||
273 | return luaL_error( L, "cancel timeout cannot be < 0"); | ||
274 | } | ||
227 | } | 275 | } |
228 | 276 | ||
229 | { | 277 | { |
230 | bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there | 278 | bool_t force = lua_toboolean( L, 2); // FALSE if nothing there |
231 | double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0); | 279 | double forcekill_timeout = luaL_optnumber( L, 3, 0.0); |
232 | 280 | ||
233 | switch( thread_cancel( L, s, secs, force, forcekill_timeout)) | 281 | switch( thread_cancel( L, s, op, secs, force, forcekill_timeout)) |
234 | { | 282 | { |
235 | case CR_Timeout: | 283 | case CR_Timeout: |
236 | lua_pushboolean( L, 0); | 284 | lua_pushboolean( L, 0); |
237 | lua_pushstring( L, "timeout"); | 285 | lua_pushstring( L, "timeout"); |
238 | return 2; | 286 | return 2; |
239 | 287 | ||
240 | case CR_Cancelled: | 288 | case CR_Cancelled: |
241 | lua_pushboolean( L, 1); | 289 | lua_pushboolean( L, 1); |
242 | return 1; | 290 | push_thread_status( L, s); |
291 | return 2; | ||
243 | 292 | ||
244 | case CR_Killed: | 293 | case CR_Killed: |
245 | lua_pushboolean( L, 0); | 294 | lua_pushboolean( L, 1); |
246 | lua_pushstring( L, "killed"); | 295 | push_thread_status( L, s); |
247 | return 2; | 296 | return 2; |
248 | } | 297 | } |
249 | } | 298 | } |
diff --git a/src/cancel.h b/src/cancel.h index 3112809..e7656ac 100644 --- a/src/cancel.h +++ b/src/cancel.h | |||
@@ -29,15 +29,24 @@ typedef enum | |||
29 | CR_Killed | 29 | CR_Killed |
30 | } cancel_result; | 30 | } cancel_result; |
31 | 31 | ||
32 | typedef enum | ||
33 | { | ||
34 | CO_Invalid = -2, | ||
35 | CO_Hard = -1, | ||
36 | CO_Soft = 0, | ||
37 | CO_Count = LUA_MASKCOUNT, | ||
38 | CO_Line = LUA_MASKLINE, | ||
39 | CO_Call = LUA_MASKCALL, | ||
40 | CO_Ret = LUA_MASKRET, | ||
41 | } CancelOp; | ||
42 | |||
32 | // crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/ | 43 | // crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/ |
33 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_ERROR, 0xe97d41626cc97577); // 'cancel_error' sentinel | 44 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_ERROR, 0xe97d41626cc97577); // 'cancel_error' sentinel |
34 | 45 | ||
35 | // crc64/we of string "CANCEL_TEST_KEY" generated at http://www.nitrxgen.net/hashgen/ | 46 | // crc64/we of string "CANCEL_TEST_KEY" generated at http://www.nitrxgen.net/hashgen/ |
36 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_TEST_KEY, 0xe66f5960c57d133a); // used as registry key | 47 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_TEST_KEY, 0xe66f5960c57d133a); // used as registry key |
37 | 48 | ||
38 | void cancel_hook( lua_State* L, lua_Debug* ar); | 49 | cancel_result thread_cancel( lua_State* L, Lane* s, CancelOp op_, double secs_, bool_t force_, double waitkill_timeout_); |
39 | |||
40 | cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_); | ||
41 | 50 | ||
42 | static inline int cancel_error( lua_State* L) | 51 | static inline int cancel_error( lua_State* L) |
43 | { | 52 | { |
diff --git a/src/lanes.c b/src/lanes.c index cbac6da..8f159a9 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -452,7 +452,7 @@ static int selfdestruct_gc( lua_State* L) | |||
452 | while( s != SELFDESTRUCT_END) | 452 | while( s != SELFDESTRUCT_END) |
453 | { | 453 | { |
454 | // attempt a regular unforced hard cancel with a small timeout | 454 | // attempt a regular unforced hard cancel with a small timeout |
455 | bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( L, s, 0.0001, FALSE, 0.0); | 455 | bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( L, s, CO_Hard, 0.0001, FALSE, 0.0); |
456 | // if we failed, and we know the thread is waiting on a linda | 456 | // if we failed, and we know the thread is waiting on a linda |
457 | if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL) | 457 | if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL) |
458 | { | 458 | { |
@@ -1027,7 +1027,6 @@ static DECLARE_CONST_UNIQUE_KEY( GCCB_KEY, 0xcfb1f046ef074e88); | |||
1027 | //--- | 1027 | //--- |
1028 | // lane_ud = lane_new( function | 1028 | // lane_ud = lane_new( function |
1029 | // , [libs_str] | 1029 | // , [libs_str] |
1030 | // , [cancelstep_uint=0] | ||
1031 | // , [priority_int=0] | 1030 | // , [priority_int=0] |
1032 | // , [globals_tbl] | 1031 | // , [globals_tbl] |
1033 | // , [package_tbl] | 1032 | // , [package_tbl] |
@@ -1044,14 +1043,13 @@ LUAG_FUNC( lane_new) | |||
1044 | Lane** ud; | 1043 | Lane** ud; |
1045 | 1044 | ||
1046 | char const* libs_str = lua_tostring( L, 2); | 1045 | char const* libs_str = lua_tostring( L, 2); |
1047 | uint_t cancelstep_idx = luaG_optunsigned( L, 3, 0); | 1046 | int const priority = (int) luaL_optinteger( L, 3, 0); |
1048 | int const priority = (int) luaL_optinteger( L, 4, 0); | 1047 | uint_t globals_idx = lua_isnoneornil( L, 4) ? 0 : 4; |
1049 | uint_t globals_idx = lua_isnoneornil( L, 5) ? 0 : 5; | 1048 | uint_t package_idx = lua_isnoneornil( L, 5) ? 0 : 5; |
1050 | uint_t package_idx = lua_isnoneornil( L, 6) ? 0 : 6; | 1049 | uint_t required_idx = lua_isnoneornil( L, 6) ? 0 : 6; |
1051 | uint_t required_idx = lua_isnoneornil( L, 7) ? 0 : 7; | 1050 | uint_t gc_cb_idx = lua_isnoneornil( L, 7) ? 0 : 7; |
1052 | uint_t gc_cb_idx = lua_isnoneornil( L, 8) ? 0 : 8; | 1051 | |
1053 | 1052 | #define FIXED_ARGS 7 | |
1054 | #define FIXED_ARGS 8 | ||
1055 | int const nargs = lua_gettop(L) - FIXED_ARGS; | 1053 | int const nargs = lua_gettop(L) - FIXED_ARGS; |
1056 | Universe* U = universe_get( L); | 1054 | Universe* U = universe_get( L); |
1057 | ASSERT_L( nargs >= 0); | 1055 | ASSERT_L( nargs >= 0); |
@@ -1074,7 +1072,7 @@ LUAG_FUNC( lane_new) | |||
1074 | STACK_GROW( L2, nargs + 3); // | 1072 | STACK_GROW( L2, nargs + 3); // |
1075 | STACK_CHECK( L2, 0); | 1073 | STACK_CHECK( L2, 0); |
1076 | 1074 | ||
1077 | STACK_GROW( L, 3); // func libs cancelstep priority globals package required gc_cb [... args ...] | 1075 | STACK_GROW( L, 3); // func libs priority globals package required gc_cb [... args ...] |
1078 | STACK_CHECK( L, 0); | 1076 | STACK_CHECK( L, 0); |
1079 | 1077 | ||
1080 | // give a default "Lua" name to the thread to see VM name in Decoda debugger | 1078 | // give a default "Lua" name to the thread to see VM name in Decoda debugger |
@@ -1103,8 +1101,8 @@ LUAG_FUNC( lane_new) | |||
1103 | return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required_idx)); | 1101 | return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required_idx)); |
1104 | } | 1102 | } |
1105 | 1103 | ||
1106 | lua_pushnil( L); // func libs cancelstep priority globals package required gc_cb [... args ...] nil | 1104 | lua_pushnil( L); // func libs priority globals package required gc_cb [... args ...] nil |
1107 | while( lua_next( L, required_idx) != 0) // func libs cancelstep priority globals package required gc_cb [... args ...] n "modname" | 1105 | while( lua_next( L, required_idx) != 0) // func libs priority globals package required gc_cb [... args ...] n "modname" |
1108 | { | 1106 | { |
1109 | if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) | 1107 | if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) |
1110 | { | 1108 | { |
@@ -1130,7 +1128,7 @@ LUAG_FUNC( lane_new) | |||
1130 | if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode | 1128 | if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode |
1131 | { | 1129 | { |
1132 | // propagate error to main state if any | 1130 | // propagate error to main state if any |
1133 | luaG_inter_move( U, L2, L, 1, eLM_LaneBody); // func libs cancelstep priority globals package required gc_cb [... args ...] n "modname" error | 1131 | luaG_inter_move( U, L2, L, 1, eLM_LaneBody); // func libs priority globals package required gc_cb [... args ...] n "modname" error |
1134 | return lua_error( L); | 1132 | return lua_error( L); |
1135 | } | 1133 | } |
1136 | // after requiring the module, register the functions it exported in our name<->function database | 1134 | // after requiring the module, register the functions it exported in our name<->function database |
@@ -1138,9 +1136,9 @@ LUAG_FUNC( lane_new) | |||
1138 | lua_pop( L2, 1); // | 1136 | lua_pop( L2, 1); // |
1139 | } | 1137 | } |
1140 | } | 1138 | } |
1141 | lua_pop( L, 1); // func libs cancelstep priority globals package required gc_cb [... args ...] n | 1139 | lua_pop( L, 1); // func libs priority globals package required gc_cb [... args ...] n |
1142 | ++ nbRequired; | 1140 | ++ nbRequired; |
1143 | } // func libs cancelstep priority globals package required gc_cb [... args ...] | 1141 | } // func libs priority globals package required gc_cb [... args ...] |
1144 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | 1142 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); |
1145 | } | 1143 | } |
1146 | STACK_MID( L, 0); | 1144 | STACK_MID( L, 0); |
@@ -1158,16 +1156,16 @@ LUAG_FUNC( lane_new) | |||
1158 | } | 1156 | } |
1159 | 1157 | ||
1160 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 1158 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
1161 | lua_pushnil( L); // func libs cancelstep priority globals package required gc_cb [... args ...] nil | 1159 | lua_pushnil( L); // func libs priority globals package required gc_cb [... args ...] nil |
1162 | // Lua 5.2 wants us to push the globals table on the stack | 1160 | // Lua 5.2 wants us to push the globals table on the stack |
1163 | lua_pushglobaltable( L2); // _G | 1161 | lua_pushglobaltable( L2); // _G |
1164 | while( lua_next( L, globals_idx)) // func libs cancelstep priority globals package required gc_cb [... args ...] k v | 1162 | while( lua_next( L, globals_idx)) // func libs priority globals package required gc_cb [... args ...] k v |
1165 | { | 1163 | { |
1166 | luaG_inter_copy( U, L, L2, 2, eLM_LaneBody); // _G k v | 1164 | luaG_inter_copy( U, L, L2, 2, eLM_LaneBody); // _G k v |
1167 | // assign it in L2's globals table | 1165 | // assign it in L2's globals table |
1168 | lua_rawset( L2, -3); // _G | 1166 | lua_rawset( L2, -3); // _G |
1169 | lua_pop( L, 1); // func libs cancelstep priority globals package required gc_cb [... args ...] k | 1167 | lua_pop( L, 1); // func libs priority globals package required gc_cb [... args ...] k |
1170 | } // func libs cancelstep priority globals package required gc_cb [... args ...] | 1168 | } // func libs priority globals package required gc_cb [... args ...] |
1171 | lua_pop( L2, 1); // | 1169 | lua_pop( L2, 1); // |
1172 | 1170 | ||
1173 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | 1171 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); |
@@ -1181,8 +1179,8 @@ LUAG_FUNC( lane_new) | |||
1181 | int res; | 1179 | int res; |
1182 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END)); | 1180 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END)); |
1183 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 1181 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
1184 | lua_pushvalue( L, 1); // func libs cancelstep priority globals package required gc_cb [... args ...] func | 1182 | lua_pushvalue( L, 1); // func libs priority globals package required gc_cb [... args ...] func |
1185 | res = luaG_inter_move( U, L, L2, 1, eLM_LaneBody); // func libs cancelstep priority globals package required gc_cb [... args ...] // func | 1183 | res = luaG_inter_move( U, L, L2, 1, eLM_LaneBody); // func libs priority globals package required gc_cb [... args ...] // func |
1186 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | 1184 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); |
1187 | if( res != 0) | 1185 | if( res != 0) |
1188 | { | 1186 | { |
@@ -1207,7 +1205,7 @@ LUAG_FUNC( lane_new) | |||
1207 | int res; | 1205 | int res; |
1208 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END)); | 1206 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END)); |
1209 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 1207 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
1210 | res = luaG_inter_move( U, L, L2, nargs, eLM_LaneBody); // func libs cancelstep priority globals package required gc_cb // func [... args ...] | 1208 | res = luaG_inter_move( U, L, L2, nargs, eLM_LaneBody); // func libs priority globals package required gc_cb // func [... args ...] |
1211 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | 1209 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); |
1212 | if( res != 0) | 1210 | if( res != 0) |
1213 | { | 1211 | { |
@@ -1222,7 +1220,7 @@ LUAG_FUNC( lane_new) | |||
1222 | // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) | 1220 | // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) |
1223 | // | 1221 | // |
1224 | // a Lane full userdata needs a single uservalue | 1222 | // a Lane full userdata needs a single uservalue |
1225 | ud = lua_newuserdatauv( L, sizeof( Lane*), 1); // func libs cancelstep priority globals package required gc_cb lane | 1223 | ud = lua_newuserdatauv( L, sizeof( Lane*), 1); // func libs priority globals package required gc_cb lane |
1226 | s = *ud = (Lane*) malloc( sizeof( Lane)); | 1224 | s = *ud = (Lane*) malloc( sizeof( Lane)); |
1227 | if( s == NULL) | 1225 | if( s == NULL) |
1228 | { | 1226 | { |
@@ -1252,8 +1250,8 @@ LUAG_FUNC( lane_new) | |||
1252 | 1250 | ||
1253 | // Set metatable for the userdata | 1251 | // Set metatable for the userdata |
1254 | // | 1252 | // |
1255 | lua_pushvalue( L, lua_upvalueindex( 1)); // func libs cancelstep priority globals package required gc_cb lane mt | 1253 | lua_pushvalue( L, lua_upvalueindex( 1)); // func libs priority globals package required gc_cb lane mt |
1256 | lua_setmetatable( L, -2); // func libs cancelstep priority globals package required gc_cb lane | 1254 | lua_setmetatable( L, -2); // func libs priority globals package required gc_cb lane |
1257 | STACK_MID( L, 1); | 1255 | STACK_MID( L, 1); |
1258 | 1256 | ||
1259 | // Create uservalue for the userdata | 1257 | // Create uservalue for the userdata |
@@ -1263,21 +1261,16 @@ LUAG_FUNC( lane_new) | |||
1263 | // Store the gc_cb callback in the uservalue | 1261 | // Store the gc_cb callback in the uservalue |
1264 | if( gc_cb_idx > 0) | 1262 | if( gc_cb_idx > 0) |
1265 | { | 1263 | { |
1266 | push_unique_key( L, GCCB_KEY); // func libs cancelstep priority globals package required gc_cb lane uv k | 1264 | push_unique_key( L, GCCB_KEY); // func libs priority globals package required gc_cb lane uv k |
1267 | lua_pushvalue( L, gc_cb_idx); // func libs cancelstep priority globals package required gc_cb lane uv k gc_cb | 1265 | lua_pushvalue( L, gc_cb_idx); // func libs priority globals package required gc_cb lane uv k gc_cb |
1268 | lua_rawset( L, -3); // func libs cancelstep priority globals package required gc_cb lane uv | 1266 | lua_rawset( L, -3); // func libs priority globals package required gc_cb lane uv |
1269 | } | 1267 | } |
1270 | 1268 | ||
1271 | lua_setiuservalue( L, -2, 1); // func libs cancelstep priority globals package required gc_cb lane | 1269 | lua_setiuservalue( L, -2, 1); // func libs priority globals package required gc_cb lane |
1272 | 1270 | ||
1273 | // Store 's' in the lane's registry, for 'cancel_test()' (even if 'cs'==0 we still do cancel tests at pending send/receive). | 1271 | // Store 's' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). |
1274 | REGISTRY_SET( L2, CANCEL_TEST_KEY, lua_pushlightuserdata( L2, s)); // func [... args ...] | 1272 | REGISTRY_SET( L2, CANCEL_TEST_KEY, lua_pushlightuserdata( L2, s)); // func [... args ...] |
1275 | 1273 | ||
1276 | if( cancelstep_idx) | ||
1277 | { | ||
1278 | lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cancelstep_idx); | ||
1279 | } | ||
1280 | |||
1281 | STACK_END( L, 1); | 1274 | STACK_END( L, 1); |
1282 | STACK_END( L2, 1 + nargs); | 1275 | STACK_END( L2, 1 + nargs); |
1283 | 1276 | ||
@@ -1402,7 +1395,7 @@ static char const * thread_status_string( Lane* s) | |||
1402 | return str; | 1395 | return str; |
1403 | } | 1396 | } |
1404 | 1397 | ||
1405 | static int push_thread_status( lua_State* L, Lane* s) | 1398 | int push_thread_status( lua_State* L, Lane* s) |
1406 | { | 1399 | { |
1407 | char const* const str = thread_status_string( s); | 1400 | char const* const str = thread_status_string( s); |
1408 | ASSERT_L( str); | 1401 | ASSERT_L( str); |
diff --git a/src/lanes.h b/src/lanes.h index de60d6d..da0dd26 100644 --- a/src/lanes.h +++ b/src/lanes.h | |||
@@ -11,7 +11,7 @@ | |||
11 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 11 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
12 | 12 | ||
13 | #define LANES_VERSION_MAJOR 3 | 13 | #define LANES_VERSION_MAJOR 3 |
14 | #define LANES_VERSION_MINOR 13 | 14 | #define LANES_VERSION_MINOR 14 |
15 | #define LANES_VERSION_PATCH 0 | 15 | #define LANES_VERSION_PATCH 0 |
16 | 16 | ||
17 | #define LANES_MIN_VERSION_REQUIRED(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR>MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR>MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH>=PATCH)))) | 17 | #define LANES_MIN_VERSION_REQUIRED(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR>MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR>MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH>=PATCH)))) |
diff --git a/src/lanes.lua b/src/lanes.lua index ba9da81..4d6deac 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -146,7 +146,7 @@ lanes.configure = function( settings_) | |||
146 | author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>", | 146 | author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>", |
147 | description= "Running multiple Lua states in parallel", | 147 | description= "Running multiple Lua states in parallel", |
148 | license= "MIT/X11", | 148 | license= "MIT/X11", |
149 | copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-18, Benoit Germain", | 149 | copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-19, Benoit Germain", |
150 | version = assert( core.version) | 150 | version = assert( core.version) |
151 | } | 151 | } |
152 | 152 | ||
@@ -198,13 +198,6 @@ lanes.configure = function( settings_) | |||
198 | -- | 198 | -- |
199 | -- 'opt': .priority: int (-3..+3) smaller is lower priority (0 = default) | 199 | -- 'opt': .priority: int (-3..+3) smaller is lower priority (0 = default) |
200 | -- | 200 | -- |
201 | -- .cancelstep: bool | uint | ||
202 | -- false: cancellation check only at pending Linda operations | ||
203 | -- (send/receive) so no runtime performance penalty (default) | ||
204 | -- true: adequate cancellation check (same as 100) | ||
205 | -- >0: cancellation check every x Lua lines (small number= faster | ||
206 | -- reaction but more performance overhead) | ||
207 | -- | ||
208 | -- .globals: table of globals to set for a new thread (passed by value) | 201 | -- .globals: table of globals to set for a new thread (passed by value) |
209 | -- | 202 | -- |
210 | -- .required: table of packages to require | 203 | -- .required: table of packages to require |
@@ -246,10 +239,6 @@ lanes.configure = function( settings_) | |||
246 | local tv = type( v_) | 239 | local tv = type( v_) |
247 | return (tv == "number") and v_ or raise_option_error( "priority", tv, v_) | 240 | return (tv == "number") and v_ or raise_option_error( "priority", tv, v_) |
248 | end, | 241 | end, |
249 | cancelstep = function( v_) | ||
250 | local tv = type( v_) | ||
251 | return (tv == "number") and v_ or (v_ == true) and 100 or (v_ == false) and 0 or raise_option_error( "cancelstep", tv, v_) | ||
252 | end, | ||
253 | globals = function( v_) | 242 | globals = function( v_) |
254 | local tv = type( v_) | 243 | local tv = type( v_) |
255 | return (tv == "table") and v_ or raise_option_error( "globals", tv, v_) | 244 | return (tv == "table") and v_ or raise_option_error( "globals", tv, v_) |
@@ -334,10 +323,10 @@ lanes.configure = function( settings_) | |||
334 | end | 323 | end |
335 | end | 324 | end |
336 | 325 | ||
337 | local cancelstep, priority, globals, package, required, gc_cb = opt.cancelstep, opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb | 326 | local priority, globals, package, required, gc_cb = opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb |
338 | return function( ...) | 327 | return function( ...) |
339 | -- must pass functions args last else they will be truncated to the first one | 328 | -- must pass functions args last else they will be truncated to the first one |
340 | return core_lane_new( func, libs, cancelstep, priority, globals, package, required, gc_cb, ...) | 329 | return core_lane_new( func, libs, priority, globals, package, required, gc_cb, ...) |
341 | end | 330 | end |
342 | end -- gen() | 331 | end -- gen() |
343 | 332 | ||
diff --git a/src/lanes_private.h b/src/lanes_private.h index ac05129..1a15969 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h | |||
@@ -89,4 +89,7 @@ static inline Lane* get_lane_from_registry( lua_State* L) | |||
89 | return s; | 89 | return s; |
90 | } | 90 | } |
91 | 91 | ||
92 | int push_thread_status( lua_State* L, Lane* s); | ||
93 | |||
94 | |||
92 | #endif // __lanes_private_h__ \ No newline at end of file | 95 | #endif // __lanes_private_h__ \ No newline at end of file |