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 |
