diff options
Diffstat (limited to '')
-rw-r--r-- | src/lanes.cpp | 170 |
1 files changed, 87 insertions, 83 deletions
diff --git a/src/lanes.cpp b/src/lanes.cpp index d549449..1a4e8b7 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
@@ -189,7 +189,7 @@ static void lane_main(Lane* lane); | |||
189 | void Lane::startThread(int priority_) | 189 | void Lane::startThread(int priority_) |
190 | { | 190 | { |
191 | m_thread = std::jthread([this]() { lane_main(this); }); | 191 | m_thread = std::jthread([this]() { lane_main(this); }); |
192 | if (priority_ != THREAD_PRIO_DEFAULT) | 192 | if (priority_ != kThreadPrioDefault) |
193 | { | 193 | { |
194 | JTHREAD_SET_PRIORITY(m_thread, priority_, U->m_sudo); | 194 | JTHREAD_SET_PRIORITY(m_thread, priority_, U->m_sudo); |
195 | } | 195 | } |
@@ -218,8 +218,8 @@ static void securize_debug_threadname(lua_State* L, Lane* lane_) | |||
218 | 218 | ||
219 | #if ERROR_FULL_STACK | 219 | #if ERROR_FULL_STACK |
220 | [[nodiscard]] static int lane_error(lua_State* L); | 220 | [[nodiscard]] static int lane_error(lua_State* L); |
221 | // crc64/we of string "STACKTRACE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | 221 | // xxh64 of string "kStackTraceRegKey" generated at https://www.pelock.com/products/hash-calculator |
222 | static constexpr RegistryUniqueKey STACKTRACE_REGKEY{ 0x534AF7D3226A429Full }; | 222 | static constexpr RegistryUniqueKey kStackTraceRegKey{ 0x3F327747CACAA904ull }; |
223 | #endif // ERROR_FULL_STACK | 223 | #endif // ERROR_FULL_STACK |
224 | 224 | ||
225 | /* | 225 | /* |
@@ -230,8 +230,8 @@ static constexpr RegistryUniqueKey STACKTRACE_REGKEY{ 0x534AF7D3226A429Full }; | |||
230 | * error (and maybe stack trace) parameters to the finalizer functions would | 230 | * error (and maybe stack trace) parameters to the finalizer functions would |
231 | * anyways complicate that approach. | 231 | * anyways complicate that approach. |
232 | */ | 232 | */ |
233 | // crc64/we of string "FINALIZER_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | 233 | // xxh64 of string "kFinalizerRegKey" generated at https://www.pelock.com/products/hash-calculator |
234 | static constexpr RegistryUniqueKey FINALIZER_REGKEY{ 0x188FCCB8BF348E09ull }; | 234 | static constexpr RegistryUniqueKey kFinalizerRegKey{ 0xFE936BFAA718FEEAull }; |
235 | 235 | ||
236 | // ################################################################################################# | 236 | // ################################################################################################# |
237 | 237 | ||
@@ -260,13 +260,13 @@ static void push_finalizers_table(lua_State* L) | |||
260 | STACK_GROW(L, 3); | 260 | STACK_GROW(L, 3); |
261 | STACK_CHECK_START_REL(L, 0); | 261 | STACK_CHECK_START_REL(L, 0); |
262 | 262 | ||
263 | FINALIZER_REGKEY.pushValue(L); // ? | 263 | kFinalizerRegKey.pushValue(L); // ? |
264 | if (lua_isnil(L, -1)) // nil? | 264 | if (lua_isnil(L, -1)) // nil? |
265 | { | 265 | { |
266 | lua_pop(L, 1); // | 266 | lua_pop(L, 1); // |
267 | // store a newly created table in the registry, but leave it on the stack too | 267 | // store a newly created table in the registry, but leave it on the stack too |
268 | lua_newtable(L); // t | 268 | lua_newtable(L); // t |
269 | FINALIZER_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // t | 269 | kFinalizerRegKey.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // t |
270 | } | 270 | } |
271 | STACK_CHECK(L, 1); | 271 | STACK_CHECK(L, 1); |
272 | } | 272 | } |
@@ -312,12 +312,12 @@ static void push_stack_trace(lua_State* L, int rc_, int stk_base_) | |||
312 | // fetch the call stack table from the registry where the handler stored it | 312 | // fetch the call stack table from the registry where the handler stored it |
313 | STACK_GROW(L, 1); | 313 | STACK_GROW(L, 1); |
314 | // yields nil if no stack was generated (in case of cancellation for example) | 314 | // yields nil if no stack was generated (in case of cancellation for example) |
315 | STACKTRACE_REGKEY.pushValue(L); // err trace|nil | 315 | kStackTraceRegKey.pushValue(L); // err trace|nil |
316 | STACK_CHECK(L, 1); | 316 | STACK_CHECK(L, 1); |
317 | 317 | ||
318 | // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed | 318 | // For cancellation the error message is kCancelError, and a stack trace isn't placed |
319 | // For other errors, the message can be whatever was thrown, and we should have a stack trace table | 319 | // For other errors, the message can be whatever was thrown, and we should have a stack trace table |
320 | LUA_ASSERT(L, lua_type(L, 1 + stk_base_) == (CANCEL_ERROR.equals(L, stk_base_) ? LUA_TNIL : LUA_TTABLE)); | 320 | LUA_ASSERT(L, lua_type(L, 1 + stk_base_) == (kCancelError.equals(L, stk_base_) ? LUA_TNIL : LUA_TTABLE)); |
321 | // Just leaving the stack trace table on the stack is enough to get it through to the master. | 321 | // Just leaving the stack trace table on the stack is enough to get it through to the master. |
322 | break; | 322 | break; |
323 | } | 323 | } |
@@ -326,8 +326,8 @@ static void push_stack_trace(lua_State* L, int rc_, int stk_base_) | |||
326 | case LUA_ERRMEM: // memory allocation error (handler not called) | 326 | case LUA_ERRMEM: // memory allocation error (handler not called) |
327 | case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) | 327 | case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) |
328 | default: | 328 | default: |
329 | // we should have a single value which is either a string (the error message) or CANCEL_ERROR | 329 | // we should have a single value which is either a string (the error message) or kCancelError |
330 | LUA_ASSERT(L, (lua_gettop(L) == stk_base_) && ((lua_type(L, stk_base_) == LUA_TSTRING) || CANCEL_ERROR.equals(L, stk_base_))); | 330 | LUA_ASSERT(L, (lua_gettop(L) == stk_base_) && ((lua_type(L, stk_base_) == LUA_TSTRING) || kCancelError.equals(L, stk_base_))); |
331 | break; | 331 | break; |
332 | } | 332 | } |
333 | } | 333 | } |
@@ -349,7 +349,7 @@ static void push_stack_trace(lua_State* L, int rc_, int stk_base_) | |||
349 | 349 | ||
350 | [[nodiscard]] static int run_finalizers(lua_State* L, int lua_rc_) | 350 | [[nodiscard]] static int run_finalizers(lua_State* L, int lua_rc_) |
351 | { | 351 | { |
352 | FINALIZER_REGKEY.pushValue(L); // ... finalizers? | 352 | kFinalizerRegKey.pushValue(L); // ... finalizers? |
353 | if (lua_isnil(L, -1)) | 353 | if (lua_isnil(L, -1)) |
354 | { | 354 | { |
355 | lua_pop(L, 1); | 355 | lua_pop(L, 1); |
@@ -373,7 +373,7 @@ static void push_stack_trace(lua_State* L, int rc_, int stk_base_) | |||
373 | LUA_ASSERT(L, finalizers_index == 2 || finalizers_index == 3); | 373 | LUA_ASSERT(L, finalizers_index == 2 || finalizers_index == 3); |
374 | //char const* err_msg = lua_tostring(L, 1); | 374 | //char const* err_msg = lua_tostring(L, 1); |
375 | lua_pushvalue(L, 1); // ... finalizers lane_error finalizer err_msg | 375 | lua_pushvalue(L, 1); // ... finalizers lane_error finalizer err_msg |
376 | // note we don't always have a stack trace for example when CANCEL_ERROR, or when we got an error that doesn't call our handler, such as LUA_ERRMEM | 376 | // note we don't always have a stack trace for example when kCancelError, or when we got an error that doesn't call our handler, such as LUA_ERRMEM |
377 | if (finalizers_index == 3) | 377 | if (finalizers_index == 3) |
378 | { | 378 | { |
379 | lua_pushvalue(L, 2); // ... finalizers lane_error finalizer err_msg stack_trace | 379 | lua_pushvalue(L, 2); // ... finalizers lane_error finalizer err_msg stack_trace |
@@ -633,8 +633,8 @@ LUAG_FUNC( set_singlethreaded) | |||
633 | */ | 633 | */ |
634 | #if ERROR_FULL_STACK | 634 | #if ERROR_FULL_STACK |
635 | 635 | ||
636 | // crc64/we of string "EXTENDED_STACKTRACE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | 636 | // xxh64 of string "kExtendedStackTraceRegKey" generated at https://www.pelock.com/products/hash-calculator |
637 | static constexpr RegistryUniqueKey EXTENDED_STACKTRACE_REGKEY{ 0x2357C69A7C92C936ull }; // used as registry key | 637 | static constexpr RegistryUniqueKey kExtendedStackTraceRegKey{ 0x38147AD48FB426E2ull }; // used as registry key |
638 | 638 | ||
639 | LUAG_FUNC( set_error_reporting) | 639 | LUAG_FUNC( set_error_reporting) |
640 | { | 640 | { |
@@ -648,7 +648,7 @@ LUAG_FUNC( set_error_reporting) | |||
648 | return luaL_error(L, "unsupported error reporting model %s", mode); | 648 | return luaL_error(L, "unsupported error reporting model %s", mode); |
649 | } | 649 | } |
650 | 650 | ||
651 | EXTENDED_STACKTRACE_REGKEY.setValue(L, [extended](lua_State* L) { lua_pushboolean(L, extended ? 1 : 0); }); | 651 | kExtendedStackTraceRegKey.setValue(L, [extended](lua_State* L) { lua_pushboolean(L, extended ? 1 : 0); }); |
652 | return 0; | 652 | return 0; |
653 | } | 653 | } |
654 | 654 | ||
@@ -659,16 +659,16 @@ LUAG_FUNC( set_error_reporting) | |||
659 | 659 | ||
660 | // Don't do stack survey for cancelled lanes. | 660 | // Don't do stack survey for cancelled lanes. |
661 | // | 661 | // |
662 | if (CANCEL_ERROR.equals(L, 1)) | 662 | if (kCancelError.equals(L, 1)) |
663 | { | 663 | { |
664 | return 1; // just pass on | 664 | return 1; // just pass on |
665 | } | 665 | } |
666 | 666 | ||
667 | STACK_GROW(L, 3); | 667 | STACK_GROW(L, 3); |
668 | bool const extended{ EXTENDED_STACKTRACE_REGKEY.readBoolValue(L) }; | 668 | bool const extended{ kExtendedStackTraceRegKey.readBoolValue(L) }; |
669 | STACK_CHECK(L, 1); | 669 | STACK_CHECK(L, 1); |
670 | 670 | ||
671 | // Place stack trace at 'registry[STACKTRACE_REGKEY]' for the 'lua_pcall()' | 671 | // Place stack trace at 'registry[kStackTraceRegKey]' for the 'lua_pcall()' |
672 | // caller to fetch. This bypasses the Lua 5.1 limitation of only one | 672 | // caller to fetch. This bypasses the Lua 5.1 limitation of only one |
673 | // return value from error handler to 'lua_pcall()' caller. | 673 | // return value from error handler to 'lua_pcall()' caller. |
674 | 674 | ||
@@ -719,7 +719,7 @@ LUAG_FUNC( set_error_reporting) | |||
719 | } | 719 | } |
720 | 720 | ||
721 | // store the stack trace table in the registry | 721 | // store the stack trace table in the registry |
722 | STACKTRACE_REGKEY.setValue(L, [](lua_State* L) { lua_insert(L, -2); }); // some_error | 722 | kStackTraceRegKey.setValue(L, [](lua_State* L) { lua_insert(L, -2); }); // some_error |
723 | 723 | ||
724 | STACK_CHECK(L, 1); | 724 | STACK_CHECK(L, 1); |
725 | return 1; // the untouched error value | 725 | return 1; // the untouched error value |
@@ -767,9 +767,9 @@ LUAG_FUNC(set_thread_priority) | |||
767 | // public Lanes API accepts a generic range -3/+3 | 767 | // public Lanes API accepts a generic range -3/+3 |
768 | // that will be remapped into the platform-specific scheduler priority scheme | 768 | // that will be remapped into the platform-specific scheduler priority scheme |
769 | // On some platforms, -3 is equivalent to -2 and +3 to +2 | 769 | // On some platforms, -3 is equivalent to -2 and +3 to +2 |
770 | if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) | 770 | if (prio < kThreadPrioMin || prio > kThreadPrioMax) |
771 | { | 771 | { |
772 | return luaL_error(L, "priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio); | 772 | return luaL_error(L, "priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, prio); |
773 | } | 773 | } |
774 | THREAD_SET_PRIORITY(static_cast<int>(prio), universe_get(L)->m_sudo); | 774 | THREAD_SET_PRIORITY(static_cast<int>(prio), universe_get(L)->m_sudo); |
775 | return 0; | 775 | return 0; |
@@ -870,7 +870,7 @@ static void lane_main(Lane* lane) | |||
870 | // in case of error and if it exists, fetch stack trace from registry and push it | 870 | // in case of error and if it exists, fetch stack trace from registry and push it |
871 | push_stack_trace(L, rc, 1); // retvals|error [trace] | 871 | push_stack_trace(L, rc, 1); // retvals|error [trace] |
872 | 872 | ||
873 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name(rc), CANCEL_ERROR.equals(L, 1) ? "cancelled" : lua_typename(L, lua_type(L, 1)))); | 873 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name(rc), kCancelError.equals(L, 1) ? "cancelled" : lua_typename(L, lua_type(L, 1)))); |
874 | // Call finalizers, if the script has set them up. | 874 | // Call finalizers, if the script has set them up. |
875 | // | 875 | // |
876 | int rc2{ run_finalizers(L, rc) }; | 876 | int rc2{ run_finalizers(L, rc) }; |
@@ -901,7 +901,7 @@ static void lane_main(Lane* lane) | |||
901 | { | 901 | { |
902 | // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them | 902 | // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them |
903 | 903 | ||
904 | Lane::Status st = (rc == LUA_OK) ? Lane::Done : CANCEL_ERROR.equals(L, 1) ? Lane::Cancelled : Lane::Error; | 904 | Lane::Status st = (rc == LUA_OK) ? Lane::Done : kCancelError.equals(L, 1) ? Lane::Cancelled : Lane::Error; |
905 | 905 | ||
906 | { | 906 | { |
907 | // 'm_done_mutex' protects the -> Done|Error|Cancelled state change | 907 | // 'm_done_mutex' protects the -> Done|Error|Cancelled state change |
@@ -959,8 +959,8 @@ LUAG_FUNC(register) | |||
959 | 959 | ||
960 | // ################################################################################################# | 960 | // ################################################################################################# |
961 | 961 | ||
962 | // crc64/we of string "GCCB_KEY" generated at http://www.nitrxgen.net/hashgen/ | 962 | // xxh64 of string "kLaneGC" generated at https://www.pelock.com/products/hash-calculator |
963 | static constexpr UniqueKey GCCB_KEY{ 0xCFB1F046EF074E88ull }; | 963 | static constexpr UniqueKey kLaneGC{ 0x5D6122141727F960ull }; |
964 | 964 | ||
965 | //--- | 965 | //--- |
966 | // lane_ud = lane_new( function | 966 | // lane_ud = lane_new( function |
@@ -978,23 +978,23 @@ LUAG_FUNC(lane_new) | |||
978 | { | 978 | { |
979 | char const* const libs_str{ lua_tostring(L, 2) }; | 979 | char const* const libs_str{ lua_tostring(L, 2) }; |
980 | bool const have_priority{ !lua_isnoneornil(L, 3) }; | 980 | bool const have_priority{ !lua_isnoneornil(L, 3) }; |
981 | int const priority{ have_priority ? (int) lua_tointeger(L, 3) : THREAD_PRIO_DEFAULT }; | 981 | int const priority{ have_priority ? (int) lua_tointeger(L, 3) : kThreadPrioDefault }; |
982 | int const globals_idx{ lua_isnoneornil(L, 4) ? 0 : 4 }; | 982 | int const globals_idx{ lua_isnoneornil(L, 4) ? 0 : 4 }; |
983 | int const package_idx{ lua_isnoneornil(L, 5) ? 0 : 5 }; | 983 | int const package_idx{ lua_isnoneornil(L, 5) ? 0 : 5 }; |
984 | int const required_idx{ lua_isnoneornil(L, 6) ? 0 : 6 }; | 984 | int const required_idx{ lua_isnoneornil(L, 6) ? 0 : 6 }; |
985 | int const gc_cb_idx{ lua_isnoneornil(L, 7) ? 0 : 7 }; | 985 | int const gc_cb_idx{ lua_isnoneornil(L, 7) ? 0 : 7 }; |
986 | 986 | ||
987 | static constexpr int FIXED_ARGS{ 7 }; | 987 | static constexpr int kFixedArgsIdx{ 7 }; |
988 | int const nargs{ lua_gettop(L) - FIXED_ARGS }; | 988 | int const nargs{ lua_gettop(L) - kFixedArgsIdx }; |
989 | Universe* const U{ universe_get(L) }; | 989 | Universe* const U{ universe_get(L) }; |
990 | LUA_ASSERT(L, nargs >= 0); | 990 | LUA_ASSERT(L, nargs >= 0); |
991 | 991 | ||
992 | // public Lanes API accepts a generic range -3/+3 | 992 | // public Lanes API accepts a generic range -3/+3 |
993 | // that will be remapped into the platform-specific scheduler priority scheme | 993 | // that will be remapped into the platform-specific scheduler priority scheme |
994 | // On some platforms, -3 is equivalent to -2 and +3 to +2 | 994 | // On some platforms, -3 is equivalent to -2 and +3 to +2 |
995 | if (have_priority && (priority < THREAD_PRIO_MIN || priority > THREAD_PRIO_MAX)) | 995 | if (have_priority && (priority < kThreadPrioMin || priority > kThreadPrioMax)) |
996 | { | 996 | { |
997 | return luaL_error(L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, priority); | 997 | return luaL_error(L, "Priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, priority); |
998 | } | 998 | } |
999 | 999 | ||
1000 | /* --- Create and prepare the sub state --- */ | 1000 | /* --- Create and prepare the sub state --- */ |
@@ -1039,7 +1039,7 @@ LUAG_FUNC(lane_new) | |||
1039 | prepareUserData(); | 1039 | prepareUserData(); |
1040 | // leave a single cancel_error on the stack for the caller | 1040 | // leave a single cancel_error on the stack for the caller |
1041 | lua_settop(m_lane->L, 0); | 1041 | lua_settop(m_lane->L, 0); |
1042 | CANCEL_ERROR.pushKey(m_lane->L); | 1042 | kCancelError.pushKey(m_lane->L); |
1043 | { | 1043 | { |
1044 | std::lock_guard lock{ m_lane->m_done_mutex }; | 1044 | std::lock_guard lock{ m_lane->m_done_mutex }; |
1045 | m_lane->m_status = Lane::Cancelled; | 1045 | m_lane->m_status = Lane::Cancelled; |
@@ -1073,7 +1073,7 @@ LUAG_FUNC(lane_new) | |||
1073 | // Store the gc_cb callback in the uservalue | 1073 | // Store the gc_cb callback in the uservalue |
1074 | if (m_gc_cb_idx > 0) | 1074 | if (m_gc_cb_idx > 0) |
1075 | { | 1075 | { |
1076 | GCCB_KEY.pushKey(m_L); // ... lane uv k | 1076 | kLaneGC.pushKey(m_L); // ... lane uv k |
1077 | lua_pushvalue(m_L, m_gc_cb_idx); // ... lane uv k gc_cb | 1077 | lua_pushvalue(m_L, m_gc_cb_idx); // ... lane uv k gc_cb |
1078 | lua_rawset(m_L, -3); // ... lane uv | 1078 | lua_rawset(m_L, -3); // ... lane uv |
1079 | } | 1079 | } |
@@ -1243,10 +1243,10 @@ LUAG_FUNC(lane_new) | |||
1243 | } | 1243 | } |
1244 | } | 1244 | } |
1245 | STACK_CHECK(L, -nargs); | 1245 | STACK_CHECK(L, -nargs); |
1246 | LUA_ASSERT(L, lua_gettop( L) == FIXED_ARGS); | 1246 | LUA_ASSERT(L, lua_gettop(L) == kFixedArgsIdx); |
1247 | 1247 | ||
1248 | // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). | 1248 | // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). |
1249 | LANE_POINTER_REGKEY.setValue(L2, [lane](lua_State* L) { lua_pushlightuserdata(L, lane); }); // func [... args ...] | 1249 | kLanePointerRegKey.setValue(L2, [lane](lua_State* L_) { lua_pushlightuserdata(L_, lane); }); // func [... args ...] |
1250 | STACK_CHECK(L2, 1 + nargs); | 1250 | STACK_CHECK(L2, 1 + nargs); |
1251 | 1251 | ||
1252 | STACK_CHECK_RESET_REL(L, 0); | 1252 | STACK_CHECK_RESET_REL(L, 0); |
@@ -1278,7 +1278,7 @@ LUAG_FUNC(lane_new) | |||
1278 | 1278 | ||
1279 | // if there a gc callback? | 1279 | // if there a gc callback? |
1280 | lua_getiuservalue(L, 1, 1); // ud uservalue | 1280 | lua_getiuservalue(L, 1, 1); // ud uservalue |
1281 | GCCB_KEY.pushKey(L); // ud uservalue __gc | 1281 | kLaneGC.pushKey(L); // ud uservalue __gc |
1282 | lua_rawget(L, -2); // ud uservalue gc_cb|nil | 1282 | lua_rawget(L, -2); // ud uservalue gc_cb|nil |
1283 | if (!lua_isnil(L, -1)) | 1283 | if (!lua_isnil(L, -1)) |
1284 | { | 1284 | { |
@@ -1441,9 +1441,9 @@ LUAG_FUNC(thread_join) | |||
1441 | return ret; | 1441 | return ret; |
1442 | } | 1442 | } |
1443 | 1443 | ||
1444 | // ################################################################################################# | ||
1444 | 1445 | ||
1445 | //--- | 1446 | // lane:__index(key,usr) -> value |
1446 | // thread_index( ud, key) -> value | ||
1447 | // | 1447 | // |
1448 | // If key is found in the environment, return it | 1448 | // If key is found in the environment, return it |
1449 | // If key is numeric, wait until the thread returns and populate the environment with the return values | 1449 | // If key is numeric, wait until the thread returns and populate the environment with the return values |
@@ -1452,44 +1452,43 @@ LUAG_FUNC(thread_join) | |||
1452 | // Else raise an error | 1452 | // Else raise an error |
1453 | LUAG_FUNC(thread_index) | 1453 | LUAG_FUNC(thread_index) |
1454 | { | 1454 | { |
1455 | static constexpr int UD{ 1 }; | 1455 | static constexpr int kSelf{ 1 }; |
1456 | static constexpr int KEY{ 2 }; | 1456 | static constexpr int kKey{ 2 }; |
1457 | static constexpr int USR{ 3 }; | 1457 | Lane* const lane{ ToLane(L, kSelf) }; |
1458 | Lane* const lane{ ToLane(L, UD) }; | ||
1459 | LUA_ASSERT(L, lua_gettop(L) == 2); | 1458 | LUA_ASSERT(L, lua_gettop(L) == 2); |
1460 | 1459 | ||
1461 | STACK_GROW(L, 8); // up to 8 positions are needed in case of error propagation | 1460 | STACK_GROW(L, 8); // up to 8 positions are needed in case of error propagation |
1462 | 1461 | ||
1463 | // If key is numeric, wait until the thread returns and populate the environment with the return values | 1462 | // If key is numeric, wait until the thread returns and populate the environment with the return values |
1464 | if (lua_type(L, KEY) == LUA_TNUMBER) | 1463 | if (lua_type(L, kKey) == LUA_TNUMBER) |
1465 | { | 1464 | { |
1465 | static constexpr int kUsr{ 3 }; | ||
1466 | // first, check that we don't already have an environment that holds the requested value | 1466 | // first, check that we don't already have an environment that holds the requested value |
1467 | { | 1467 | { |
1468 | // If key is found in the uservalue, return it | 1468 | // If key is found in the uservalue, return it |
1469 | lua_getiuservalue(L, UD, 1); | 1469 | lua_getiuservalue(L, kSelf, 1); |
1470 | lua_pushvalue(L, KEY); | 1470 | lua_pushvalue(L, kKey); |
1471 | lua_rawget(L, USR); | 1471 | lua_rawget(L, kUsr); |
1472 | if (!lua_isnil(L, -1)) | 1472 | if (!lua_isnil(L, -1)) |
1473 | { | 1473 | { |
1474 | return 1; | 1474 | return 1; |
1475 | } | 1475 | } |
1476 | lua_pop(L, 1); | 1476 | lua_pop(L, 1); |
1477 | } | 1477 | } |
1478 | { | 1478 | { |
1479 | // check if we already fetched the values from the thread or not | 1479 | // check if we already fetched the values from the thread or not |
1480 | lua_Integer key = lua_tointeger(L, KEY); | ||
1481 | lua_pushinteger(L, 0); | 1480 | lua_pushinteger(L, 0); |
1482 | lua_rawget(L, USR); | 1481 | lua_rawget(L, kUsr); |
1483 | bool const fetched{ !lua_isnil(L, -1) }; | 1482 | bool const fetched{ !lua_isnil(L, -1) }; |
1484 | lua_pop(L, 1); // back to our 2 args + uservalue on the stack | 1483 | lua_pop(L, 1); // back to our 2 args + uservalue on the stack |
1485 | if (!fetched) | 1484 | if (!fetched) |
1486 | { | 1485 | { |
1487 | lua_pushinteger(L, 0); | 1486 | lua_pushinteger(L, 0); |
1488 | lua_pushboolean(L, 1); | 1487 | lua_pushboolean(L, 1); |
1489 | lua_rawset(L, USR); | 1488 | lua_rawset(L, kUsr); |
1490 | // wait until thread has completed | 1489 | // wait until thread has completed |
1491 | lua_pushcfunction(L, LG_thread_join); | 1490 | lua_pushcfunction(L, LG_thread_join); |
1492 | lua_pushvalue(L, UD); | 1491 | lua_pushvalue(L, kSelf); |
1493 | lua_call(L, 1, LUA_MULTRET); // all return values are on the stack, at slots 4+ | 1492 | lua_call(L, 1, LUA_MULTRET); // all return values are on the stack, at slots 4+ |
1494 | switch (lane->m_status) | 1493 | switch (lane->m_status) |
1495 | { | 1494 | { |
@@ -1508,7 +1507,7 @@ LUAG_FUNC(thread_index) | |||
1508 | for (int i = nvalues; i > 0; --i) | 1507 | for (int i = nvalues; i > 0; --i) |
1509 | { | 1508 | { |
1510 | // pop the last element of the stack, to store it in the uservalue at its proper index | 1509 | // pop the last element of the stack, to store it in the uservalue at its proper index |
1511 | lua_rawseti(L, USR, i); | 1510 | lua_rawseti(L, kUsr, i); |
1512 | } | 1511 | } |
1513 | } | 1512 | } |
1514 | break; | 1513 | break; |
@@ -1521,7 +1520,7 @@ LUAG_FUNC(thread_index) | |||
1521 | // store errstring at key -1 | 1520 | // store errstring at key -1 |
1522 | lua_pushnumber(L, -1); | 1521 | lua_pushnumber(L, -1); |
1523 | lua_pushvalue(L, 5); | 1522 | lua_pushvalue(L, 5); |
1524 | lua_rawset(L, USR); | 1523 | lua_rawset(L, kUsr); |
1525 | break; | 1524 | break; |
1526 | 1525 | ||
1527 | case Lane::Cancelled: | 1526 | case Lane::Cancelled: |
@@ -1529,11 +1528,12 @@ LUAG_FUNC(thread_index) | |||
1529 | break; | 1528 | break; |
1530 | } | 1529 | } |
1531 | } | 1530 | } |
1532 | lua_settop(L, 3); // UD KEY ENV | 1531 | lua_settop(L, 3); // self KEY ENV |
1532 | int const key{ static_cast<int>(lua_tointeger(L, kKey)) }; | ||
1533 | if (key != -1) | 1533 | if (key != -1) |
1534 | { | 1534 | { |
1535 | lua_pushnumber(L, -1); // UD KEY ENV -1 | 1535 | lua_pushnumber(L, -1); // self KEY ENV -1 |
1536 | lua_rawget(L, USR); // UD KEY ENV "error" | 1536 | lua_rawget(L, kUsr); // self KEY ENV "error"|nil |
1537 | if (!lua_isnil(L, -1)) // an error was stored | 1537 | if (!lua_isnil(L, -1)) // an error was stored |
1538 | { | 1538 | { |
1539 | // Note: Lua 5.1 interpreter is not prepared to show | 1539 | // Note: Lua 5.1 interpreter is not prepared to show |
@@ -1547,48 +1547,48 @@ LUAG_FUNC(thread_index) | |||
1547 | // Level 3 should show the line where 'h[x]' was read | 1547 | // Level 3 should show the line where 'h[x]' was read |
1548 | // but this only seems to work for string messages | 1548 | // but this only seems to work for string messages |
1549 | // (Lua 5.1.4). No idea, why. --AKa 22-Jan-2009 | 1549 | // (Lua 5.1.4). No idea, why. --AKa 22-Jan-2009 |
1550 | lua_getmetatable(L, UD); // UD KEY ENV "error" mt | 1550 | lua_getmetatable(L, kSelf); // self KEY ENV "error" mt |
1551 | lua_getfield(L, -1, "cached_error"); // UD KEY ENV "error" mt error() | 1551 | lua_getfield(L, -1, "cached_error"); // self KEY ENV "error" mt error() |
1552 | lua_getfield(L, -2, "cached_tostring"); // UD KEY ENV "error" mt error() tostring() | 1552 | lua_getfield(L, -2, "cached_tostring"); // self KEY ENV "error" mt error() tostring() |
1553 | lua_pushvalue(L, 4); // UD KEY ENV "error" mt error() tostring() "error" | 1553 | lua_pushvalue(L, 4); // self KEY ENV "error" mt error() tostring() "error" |
1554 | lua_call(L, 1, 1); // tostring( errstring) -- just in case // UD KEY ENV "error" mt error() "error" | 1554 | lua_call(L, 1, 1); // tostring( errstring) -- just in case // self KEY ENV "error" mt error() "error" |
1555 | lua_pushinteger(L, 3); // UD KEY ENV "error" mt error() "error" 3 | 1555 | lua_pushinteger(L, 3); // self KEY ENV "error" mt error() "error" 3 |
1556 | lua_call(L, 2, 0); // error( tostring( errstring), 3) // UD KEY ENV "error" mt | 1556 | lua_call(L, 2, 0); // error( tostring( errstring), 3) // self KEY ENV "error" mt |
1557 | } | 1557 | } |
1558 | else | 1558 | else |
1559 | { | 1559 | { |
1560 | lua_pop(L, 1); // back to our 3 arguments on the stack | 1560 | lua_pop(L, 1); // self KEY ENV |
1561 | } | 1561 | } |
1562 | } | 1562 | } |
1563 | lua_rawgeti(L, USR, (int)key); | 1563 | lua_rawgeti(L, kUsr, key); |
1564 | } | 1564 | } |
1565 | return 1; | 1565 | return 1; |
1566 | } | 1566 | } |
1567 | if (lua_type(L, KEY) == LUA_TSTRING) | 1567 | if (lua_type(L, kKey) == LUA_TSTRING) |
1568 | { | 1568 | { |
1569 | char const* const keystr{ lua_tostring(L, KEY) }; | 1569 | char const* const keystr{ lua_tostring(L, kKey) }; |
1570 | lua_settop(L, 2); // keep only our original arguments on the stack | 1570 | lua_settop(L, 2); // keep only our original arguments on the stack |
1571 | if (strcmp( keystr, "status") == 0) | 1571 | if (strcmp( keystr, "status") == 0) |
1572 | { | 1572 | { |
1573 | lane->pushThreadStatus(L); // push the string representing the status | 1573 | lane->pushThreadStatus(L); // push the string representing the status |
1574 | return 1; | 1574 | return 1; |
1575 | } | 1575 | } |
1576 | // return UD.metatable[key] | 1576 | // return self.metatable[key] |
1577 | lua_getmetatable(L, UD); // UD KEY mt | 1577 | lua_getmetatable(L, kSelf); // self KEY mt |
1578 | lua_replace(L, -3); // mt KEY | 1578 | lua_replace(L, -3); // mt KEY |
1579 | lua_rawget(L, -2); // mt value | 1579 | lua_rawget(L, -2); // mt value |
1580 | // only "cancel" and "join" are registered as functions, any other string will raise an error | 1580 | // only "cancel" and "join" are registered as functions, any other string will raise an error |
1581 | if (lua_iscfunction(L, -1)) | 1581 | if (!lua_iscfunction(L, -1)) |
1582 | { | 1582 | { |
1583 | return 1; | 1583 | luaL_error(L, "can't index a lane with '%s'", keystr); // doesn't return |
1584 | } | 1584 | } |
1585 | return luaL_error(L, "can't index a lane with '%s'", keystr); | 1585 | return 1; |
1586 | } | 1586 | } |
1587 | // unknown key | 1587 | // unknown key |
1588 | lua_getmetatable(L, UD); | 1588 | lua_getmetatable(L, kSelf); |
1589 | lua_getfield(L, -1, "cached_error"); | 1589 | lua_getfield(L, -1, "cached_error"); |
1590 | lua_pushliteral(L, "Unknown key: "); | 1590 | lua_pushliteral(L, "Unknown key: "); |
1591 | lua_pushvalue(L, KEY); | 1591 | lua_pushvalue(L, kKey); |
1592 | lua_concat(L, 2); | 1592 | lua_concat(L, 2); |
1593 | lua_call(L, 1, 0); // error( "Unknown key: " .. key) -> doesn't return | 1593 | lua_call(L, 1, 0); // error( "Unknown key: " .. key) -> doesn't return |
1594 | return 0; | 1594 | return 0; |
@@ -1863,15 +1863,19 @@ LUAG_FUNC(configure) | |||
1863 | ); // settings M VERSION | 1863 | ); // settings M VERSION |
1864 | lua_setfield(L, -2, "version"); // settings M | 1864 | lua_setfield(L, -2, "version"); // settings M |
1865 | 1865 | ||
1866 | lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX | 1866 | lua_pushinteger(L, kThreadPrioMax); // settings M kThreadPrioMax |
1867 | lua_setfield(L, -2, "max_prio"); // settings M | 1867 | lua_setfield(L, -2, "max_prio"); // settings M |
1868 | 1868 | ||
1869 | CANCEL_ERROR.pushKey(L); // settings M CANCEL_ERROR | 1869 | kCancelError.pushKey(L); // settings M kCancelError |
1870 | lua_setfield(L, -2, "cancel_error"); // settings M | 1870 | lua_setfield(L, -2, "cancel_error"); // settings M |
1871 | 1871 | ||
1872 | /* to activate in a separate commit | ||
1873 | kNilSentinel.pushKey(L); // settings M kNilSentinel | ||
1874 | lua_setfield(L, -2, "null"); // settings M | ||
1875 | */ | ||
1872 | STACK_CHECK(L, 2); // reference stack contains only the function argument 'settings' | 1876 | STACK_CHECK(L, 2); // reference stack contains only the function argument 'settings' |
1873 | // we'll need this every time we transfer some C function from/to this state | 1877 | // we'll need this every time we transfer some C function from/to this state |
1874 | LOOKUP_REGKEY.setValue(L, [](lua_State* L) { lua_newtable(L); }); // settings M | 1878 | kLookupRegKey.setValue(L, [](lua_State* L) { lua_newtable(L); }); // settings M |
1875 | STACK_CHECK(L, 2); | 1879 | STACK_CHECK(L, 2); |
1876 | 1880 | ||
1877 | // register all native functions found in that module in the transferable functions database | 1881 | // register all native functions found in that module in the transferable functions database |
@@ -1893,8 +1897,8 @@ LUAG_FUNC(configure) | |||
1893 | } | 1897 | } |
1894 | lua_pop(L, 1); // settings | 1898 | lua_pop(L, 1); // settings |
1895 | 1899 | ||
1896 | // set _R[CONFIG_REGKEY] = settings | 1900 | // set _R[kConfigRegKey] = settings |
1897 | CONFIG_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); | 1901 | kConfigRegKey.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); |
1898 | STACK_CHECK(L, 1); | 1902 | STACK_CHECK(L, 1); |
1899 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); | 1903 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); |
1900 | // Return the settings table | 1904 | // Return the settings table |
@@ -1986,7 +1990,7 @@ LANES_API int luaopen_lanes_core( lua_State* L) | |||
1986 | lua_pushvalue(L, 1); // M "lanes.core" | 1990 | lua_pushvalue(L, 1); // M "lanes.core" |
1987 | lua_pushvalue(L, -2); // M "lanes.core" M | 1991 | lua_pushvalue(L, -2); // M "lanes.core" M |
1988 | lua_pushcclosure(L, LG_configure, 2); // M LG_configure() | 1992 | lua_pushcclosure(L, LG_configure, 2); // M LG_configure() |
1989 | CONFIG_REGKEY.pushValue(L); // M LG_configure() settings | 1993 | kConfigRegKey.pushValue(L); // M LG_configure() settings |
1990 | if (!lua_isnil(L, -1)) // this is not the first require "lanes.core": call configure() immediately | 1994 | if (!lua_isnil(L, -1)) // this is not the first require "lanes.core": call configure() immediately |
1991 | { | 1995 | { |
1992 | lua_pushvalue(L, -1); // M LG_configure() settings settings | 1996 | lua_pushvalue(L, -1); // M LG_configure() settings settings |