diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-17 10:17:20 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-17 10:17:20 +0200 |
commit | 3dd36a796c9258f552c893d225e0d9cc0f576a6d (patch) | |
tree | 2417885e168dfc490413d752f2e01e629ea61a83 /src | |
parent | be7e5a99aa926d1a823031701453f9aa5c438ef6 (diff) | |
download | lanes-3dd36a796c9258f552c893d225e0d9cc0f576a6d.tar.gz lanes-3dd36a796c9258f552c893d225e0d9cc0f576a6d.tar.bz2 lanes-3dd36a796c9258f552c893d225e0d9cc0f576a6d.zip |
Strong typed Lua thread status
Diffstat (limited to 'src')
-rw-r--r-- | src/compat.h | 28 | ||||
-rw-r--r-- | src/lane.cpp | 74 |
2 files changed, 64 insertions, 38 deletions
diff --git a/src/compat.h b/src/compat.h index bf22f10..0e95cde 100644 --- a/src/compat.h +++ b/src/compat.h | |||
@@ -24,6 +24,8 @@ extern "C" | |||
24 | #define LUA_JITLIBNAME "jit" | 24 | #define LUA_JITLIBNAME "jit" |
25 | #endif // LUA_JITLIBNAME | 25 | #endif // LUA_JITLIBNAME |
26 | 26 | ||
27 | #include <cassert> | ||
28 | |||
27 | // code is now preferring Lua 5.4 API | 29 | // code is now preferring Lua 5.4 API |
28 | 30 | ||
29 | // ################################################################################################# | 31 | // ################################################################################################# |
@@ -160,6 +162,8 @@ void* lua_newuserdatauv(lua_State* L_, size_t sz_, int nuvalue_); | |||
160 | int lua_getiuservalue(lua_State* L_, int idx_, int n_); | 162 | int lua_getiuservalue(lua_State* L_, int idx_, int n_); |
161 | int lua_setiuservalue(lua_State* L_, int idx_, int n_); | 163 | int lua_setiuservalue(lua_State* L_, int idx_, int n_); |
162 | 164 | ||
165 | #define LUA_GNAME "_G" | ||
166 | |||
163 | #endif // LUA_VERSION_NUM < 504 | 167 | #endif // LUA_VERSION_NUM < 504 |
164 | 168 | ||
165 | // ################################################################################################# | 169 | // ################################################################################################# |
@@ -197,7 +201,7 @@ inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_) | |||
197 | 201 | ||
198 | // ################################################################################################# | 202 | // ################################################################################################# |
199 | 203 | ||
200 | // a wrapper over lua types to see them easier in a debugger | 204 | // a strong-typed wrapper over lua types to see them easier in a debugger |
201 | enum class LuaType | 205 | enum class LuaType |
202 | { | 206 | { |
203 | NONE = LUA_TNONE, | 207 | NONE = LUA_TNONE, |
@@ -222,4 +226,26 @@ inline char const* lua_typename(lua_State* L_, LuaType t_) | |||
222 | return lua_typename(L_, static_cast<int>(t_)); | 226 | return lua_typename(L_, static_cast<int>(t_)); |
223 | } | 227 | } |
224 | 228 | ||
229 | // ################################################################################################# | ||
230 | |||
231 | // a strong-typed wrapper over lua error codes to see them easier in a debugger | ||
232 | enum class LuaError | ||
233 | { | ||
234 | OK = LUA_OK, | ||
235 | YIELD = LUA_YIELD, | ||
236 | ERRRUN = LUA_ERRRUN, | ||
237 | ERRSYNTAX = LUA_ERRSYNTAX, | ||
238 | ERRMEM = LUA_ERRMEM, | ||
239 | ERRGCMM = LUA_ERRGCMM, // pre-5.4 | ||
240 | ERRERR = LUA_ERRERR | ||
241 | }; | ||
242 | |||
243 | inline constexpr LuaError ToLuaError(int rc_) | ||
244 | { | ||
245 | assert(rc_ == LUA_OK || rc_ == LUA_YIELD || rc_ == LUA_ERRRUN || rc_ == LUA_ERRSYNTAX || rc_ == LUA_ERRMEM || rc_ == LUA_ERRGCMM || rc_ == LUA_ERRERR); | ||
246 | return static_cast<LuaError>(rc_); | ||
247 | } | ||
248 | |||
249 | // ################################################################################################# | ||
250 | |||
225 | LuaType luaG_getmodule(lua_State* L_, char const* name_); | 251 | LuaType luaG_getmodule(lua_State* L_, char const* name_); |
diff --git a/src/lane.cpp b/src/lane.cpp index 4c33afb..57e3454 100644 --- a/src/lane.cpp +++ b/src/lane.cpp | |||
@@ -346,20 +346,20 @@ LUAG_FUNC(thread_index) | |||
346 | // LUA_ERRERR doesn't have the same value | 346 | // LUA_ERRERR doesn't have the same value |
347 | struct errcode_name | 347 | struct errcode_name |
348 | { | 348 | { |
349 | int code; | 349 | LuaError code; |
350 | char const* name; | 350 | char const* name; |
351 | }; | 351 | }; |
352 | 352 | ||
353 | static struct errcode_name s_errcodes[] = { | 353 | static struct errcode_name s_errcodes[] = { |
354 | { LUA_OK, "LUA_OK" }, | 354 | { LuaError::OK, "LUA_OK" }, |
355 | { LUA_YIELD, "LUA_YIELD" }, | 355 | { LuaError::YIELD, "LUA_YIELD" }, |
356 | { LUA_ERRRUN, "LUA_ERRRUN" }, | 356 | { LuaError::ERRRUN, "LUA_ERRRUN" }, |
357 | { LUA_ERRSYNTAX, "LUA_ERRSYNTAX" }, | 357 | { LuaError::ERRSYNTAX, "LUA_ERRSYNTAX" }, |
358 | { LUA_ERRMEM, "LUA_ERRMEM" }, | 358 | { LuaError::ERRMEM, "LUA_ERRMEM" }, |
359 | { LUA_ERRGCMM, "LUA_ERRGCMM" }, | 359 | { LuaError::ERRGCMM, "LUA_ERRGCMM" }, |
360 | { LUA_ERRERR, "LUA_ERRERR" }, | 360 | { LuaError::ERRERR, "LUA_ERRERR" }, |
361 | }; | 361 | }; |
362 | static char const* get_errcode_name(int _code) | 362 | static char const* get_errcode_name(LuaError _code) |
363 | { | 363 | { |
364 | for (errcode_name const& _entry : s_errcodes) { | 364 | for (errcode_name const& _entry : s_errcodes) { |
365 | if (_entry.code == _code) { | 365 | if (_entry.code == _code) { |
@@ -464,14 +464,14 @@ static constexpr RegistryUniqueKey kStackTraceRegKey{ 0x3F327747CACAA904ull }; | |||
464 | // ########################################## Finalizer ############################################ | 464 | // ########################################## Finalizer ############################################ |
465 | // ################################################################################################# | 465 | // ################################################################################################# |
466 | 466 | ||
467 | static void push_stack_trace(lua_State* L_, int rc_, int stk_base_) | 467 | static void push_stack_trace(lua_State* L_, LuaError rc_, int stk_base_) |
468 | { | 468 | { |
469 | // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry | 469 | // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry |
470 | switch (rc_) { | 470 | switch (rc_) { |
471 | case LUA_OK: // no error, body return values are on the stack | 471 | case LuaError::OK: // no error, body return values are on the stack |
472 | break; | 472 | break; |
473 | 473 | ||
474 | case LUA_ERRRUN: // cancellation or a runtime error | 474 | case LuaError::ERRRUN: // cancellation or a runtime error |
475 | #if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler | 475 | #if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler |
476 | { | 476 | { |
477 | STACK_CHECK_START_REL(L_, 0); | 477 | STACK_CHECK_START_REL(L_, 0); |
@@ -491,8 +491,8 @@ static void push_stack_trace(lua_State* L_, int rc_, int stk_base_) | |||
491 | [[fallthrough]]; // fall through if not ERROR_FULL_STACK | 491 | [[fallthrough]]; // fall through if not ERROR_FULL_STACK |
492 | #endif // !ERROR_FULL_STACK | 492 | #endif // !ERROR_FULL_STACK |
493 | 493 | ||
494 | case LUA_ERRMEM: // memory allocation error (handler not called) | 494 | case LuaError::ERRMEM: // memory allocation error (handler not called) |
495 | case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) | 495 | case LuaError::ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) |
496 | default: | 496 | default: |
497 | // we should have a single value which is either a string (the error message) or kCancelError | 497 | // we should have a single value which is either a string (the error message) or kCancelError |
498 | LUA_ASSERT(L_, (lua_gettop(L_) == stk_base_) && ((lua_type(L_, stk_base_) == LUA_TSTRING) || kCancelError.equals(L_, stk_base_))); | 498 | LUA_ASSERT(L_, (lua_gettop(L_) == stk_base_) && ((lua_type(L_, stk_base_) == LUA_TSTRING) || kCancelError.equals(L_, stk_base_))); |
@@ -515,12 +515,12 @@ static void push_stack_trace(lua_State* L_, int rc_, int stk_base_) | |||
515 | // TBD: should we add stack trace on failing finalizer, wouldn't be hard.. | 515 | // TBD: should we add stack trace on failing finalizer, wouldn't be hard.. |
516 | // | 516 | // |
517 | 517 | ||
518 | [[nodiscard]] static int run_finalizers(lua_State* L_, int lua_rc_) | 518 | [[nodiscard]] static LuaError run_finalizers(lua_State* L_, LuaError lua_rc_) |
519 | { | 519 | { |
520 | kFinalizerRegKey.pushValue(L_); // L_: ... finalizers? | 520 | kFinalizerRegKey.pushValue(L_); // L_: ... finalizers? |
521 | if (lua_isnil(L_, -1)) { | 521 | if (lua_isnil(L_, -1)) { |
522 | lua_pop(L_, 1); | 522 | lua_pop(L_, 1); |
523 | return 0; // no finalizers | 523 | return LuaError::OK; // no finalizers |
524 | } | 524 | } |
525 | 525 | ||
526 | STACK_GROW(L_, 5); | 526 | STACK_GROW(L_, 5); |
@@ -528,13 +528,13 @@ static void push_stack_trace(lua_State* L_, int rc_, int stk_base_) | |||
528 | int const _finalizers_index{ lua_gettop(L_) }; | 528 | int const _finalizers_index{ lua_gettop(L_) }; |
529 | int const _err_handler_index{ ERROR_FULL_STACK ? (lua_pushcfunction(L_, lane_error), lua_gettop(L_)) : 0 }; | 529 | int const _err_handler_index{ ERROR_FULL_STACK ? (lua_pushcfunction(L_, lane_error), lua_gettop(L_)) : 0 }; |
530 | 530 | ||
531 | int rc{ LUA_OK }; | 531 | LuaError _rc{ LuaError::OK }; |
532 | for (int n = static_cast<int>(lua_rawlen(L_, _finalizers_index)); n > 0; --n) { | 532 | for (int _n = static_cast<int>(lua_rawlen(L_, _finalizers_index)); _n > 0; --_n) { |
533 | int args = 0; | 533 | int _args{ 0 }; |
534 | lua_pushinteger(L_, n); // L_: ... finalizers lane_error n | 534 | lua_pushinteger(L_, _n); // L_: ... finalizers lane_error n |
535 | lua_rawget(L_, _finalizers_index); // L_: ... finalizers lane_error finalizer | 535 | lua_rawget(L_, _finalizers_index); // L_: ... finalizers lane_error finalizer |
536 | LUA_ASSERT(L_, lua_isfunction(L_, -1)); | 536 | LUA_ASSERT(L_, lua_isfunction(L_, -1)); |
537 | if (lua_rc_ != LUA_OK) { // we have an error message and an optional stack trace at the bottom of the stack | 537 | if (lua_rc_ != LuaError::OK) { // we have an error message and an optional stack trace at the bottom of the stack |
538 | LUA_ASSERT(L_, _finalizers_index == 2 || _finalizers_index == 3); | 538 | LUA_ASSERT(L_, _finalizers_index == 2 || _finalizers_index == 3); |
539 | // char const* err_msg = lua_tostring(L_, 1); | 539 | // char const* err_msg = lua_tostring(L_, 1); |
540 | lua_pushvalue(L_, 1); // L_: ... finalizers lane_error finalizer err_msg | 540 | lua_pushvalue(L_, 1); // L_: ... finalizers lane_error finalizer err_msg |
@@ -542,13 +542,13 @@ static void push_stack_trace(lua_State* L_, int rc_, int stk_base_) | |||
542 | if (_finalizers_index == 3) { | 542 | if (_finalizers_index == 3) { |
543 | lua_pushvalue(L_, 2); // L_: ... finalizers lane_error finalizer err_msg stack_trace | 543 | lua_pushvalue(L_, 2); // L_: ... finalizers lane_error finalizer err_msg stack_trace |
544 | } | 544 | } |
545 | args = _finalizers_index - 1; | 545 | _args = _finalizers_index - 1; |
546 | } | 546 | } |
547 | 547 | ||
548 | // if no error from the main body, finalizer doesn't receive any argument, else it gets the error message and optional stack trace | 548 | // if no error from the main body, finalizer doesn't receive any argument, else it gets the error message and optional stack trace |
549 | rc = lua_pcall(L_, args, 0, _err_handler_index); // L_: ... finalizers lane_error err_msg2? | 549 | _rc = ToLuaError(lua_pcall(L_, _args, 0, _err_handler_index)); // L_: ... finalizers lane_error err_msg2? |
550 | if (rc != LUA_OK) { | 550 | if (_rc != LuaError::OK) { |
551 | push_stack_trace(L_, rc, lua_gettop(L_)); // L_: ... finalizers lane_error err_msg2? trace | 551 | push_stack_trace(L_, _rc, lua_gettop(L_)); // L_: ... finalizers lane_error err_msg2? trace |
552 | // If one finalizer fails, don't run the others. Return this | 552 | // If one finalizer fails, don't run the others. Return this |
553 | // as the 'real' error, replacing what we could have had (or not) | 553 | // as the 'real' error, replacing what we could have had (or not) |
554 | // from the actual code. | 554 | // from the actual code. |
@@ -557,20 +557,20 @@ static void push_stack_trace(lua_State* L_, int rc_, int stk_base_) | |||
557 | // no error, proceed to next finalizer // L_: ... finalizers lane_error | 557 | // no error, proceed to next finalizer // L_: ... finalizers lane_error |
558 | } | 558 | } |
559 | 559 | ||
560 | if (rc != LUA_OK) { | 560 | if (_rc != LuaError::OK) { |
561 | // ERROR_FULL_STACK accounts for the presence of lane_error on the stack | 561 | // ERROR_FULL_STACK accounts for the presence of lane_error on the stack |
562 | int const nb_err_slots{ lua_gettop(L_) - _finalizers_index - ERROR_FULL_STACK }; | 562 | int const _nb_err_slots{ lua_gettop(L_) - _finalizers_index - ERROR_FULL_STACK }; |
563 | // a finalizer generated an error, this is what we leave of the stack | 563 | // a finalizer generated an error, this is what we leave of the stack |
564 | for (int n = nb_err_slots; n > 0; --n) { | 564 | for (int _n = _nb_err_slots; _n > 0; --_n) { |
565 | lua_replace(L_, n); | 565 | lua_replace(L_, _n); |
566 | } | 566 | } |
567 | // leave on the stack only the error and optional stack trace produced by the error in the finalizer | 567 | // leave on the stack only the error and optional stack trace produced by the error in the finalizer |
568 | lua_settop(L_, nb_err_slots); // L_: ... lane_error trace | 568 | lua_settop(L_, _nb_err_slots); // L_: ... lane_error trace |
569 | } else { // no error from the finalizers, make sure only the original return values from the lane body remain on the stack | 569 | } else { // no error from the finalizers, make sure only the original return values from the lane body remain on the stack |
570 | lua_settop(L_, _finalizers_index - 1); | 570 | lua_settop(L_, _finalizers_index - 1); |
571 | } | 571 | } |
572 | 572 | ||
573 | return rc; | 573 | return _rc; |
574 | } | 574 | } |
575 | 575 | ||
576 | // ################################################################################################# | 576 | // ################################################################################################# |
@@ -627,7 +627,7 @@ static void lane_main(Lane* lane_) | |||
627 | lua_State* const _L{ lane_->L }; | 627 | lua_State* const _L{ lane_->L }; |
628 | // wait until the launching thread has finished preparing L | 628 | // wait until the launching thread has finished preparing L |
629 | lane_->ready.wait(); | 629 | lane_->ready.wait(); |
630 | int _rc{ LUA_ERRRUN }; | 630 | LuaError _rc{ LuaError::ERRRUN }; |
631 | if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work | 631 | if (lane_->status == Lane::Pending) { // nothing wrong happened during preparation, we can work |
632 | // At this point, the lane function and arguments are on the stack | 632 | // At this point, the lane function and arguments are on the stack |
633 | int const nargs{ lua_gettop(_L) - 1 }; | 633 | int const nargs{ lua_gettop(_L) - 1 }; |
@@ -662,7 +662,7 @@ static void lane_main(Lane* lane_) | |||
662 | lua_insert(_L, 1); // L: handler func args | 662 | lua_insert(_L, 1); // L: handler func args |
663 | #endif // L: ERROR_FULL_STACK | 663 | #endif // L: ERROR_FULL_STACK |
664 | 664 | ||
665 | _rc = lua_pcall(_L, nargs, LUA_MULTRET, ERROR_FULL_STACK); // L: retvals|err | 665 | _rc = ToLuaError(lua_pcall(_L, nargs, LUA_MULTRET, ERROR_FULL_STACK)); // L: retvals|err |
666 | 666 | ||
667 | #if ERROR_FULL_STACK | 667 | #if ERROR_FULL_STACK |
668 | lua_remove(_L, 1); // L: retvals|error | 668 | lua_remove(_L, 1); // L: retvals|error |
@@ -674,9 +674,9 @@ static void lane_main(Lane* lane_) | |||
674 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END(_U), _L, get_errcode_name(_rc), kCancelError.equals(_L, 1) ? "cancelled" : lua_typename(_L, lua_type(_L, 1)))); | 674 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END(_U), _L, get_errcode_name(_rc), kCancelError.equals(_L, 1) ? "cancelled" : lua_typename(_L, lua_type(_L, 1)))); |
675 | // Call finalizers, if the script has set them up. | 675 | // Call finalizers, if the script has set them up. |
676 | // | 676 | // |
677 | int _rc2{ run_finalizers(_L, _rc) }; | 677 | LuaError const _rc2{ run_finalizers(_L, _rc) }; |
678 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END(_U), _L, get_errcode_name(_rc2))); | 678 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END(_U), _L, get_errcode_name(_rc2))); |
679 | if (_rc2 != LUA_OK) { // Error within a finalizer! | 679 | if (_rc2 != LuaError::OK) { // Error within a finalizer! |
680 | // the finalizer generated an error, and left its own error message [and stack trace] on the stack | 680 | // the finalizer generated an error, and left its own error message [and stack trace] on the stack |
681 | _rc = _rc2; // we're overruling the earlier script error or normal return | 681 | _rc = _rc2; // we're overruling the earlier script error or normal return |
682 | } | 682 | } |
@@ -699,11 +699,11 @@ static void lane_main(Lane* lane_) | |||
699 | if (lane_) { | 699 | if (lane_) { |
700 | // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them | 700 | // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them |
701 | 701 | ||
702 | Lane::Status const _st = (_rc == LUA_OK) ? Lane::Done : kCancelError.equals(_L, 1) ? Lane::Cancelled : Lane::Error; | 702 | Lane::Status const _st{ (_rc == LuaError::OK) ? Lane::Done : kCancelError.equals(_L, 1) ? Lane::Cancelled : Lane::Error }; |
703 | 703 | ||
704 | { | 704 | { |
705 | // 'doneMutex' protects the -> Done|Error|Cancelled state change | 705 | // 'doneMutex' protects the -> Done|Error|Cancelled state change |
706 | std::lock_guard lock{ lane_->doneMutex }; | 706 | std::lock_guard _guard{ lane_->doneMutex }; |
707 | lane_->status = _st; | 707 | lane_->status = _st; |
708 | lane_->doneCondVar.notify_one(); // wake up master (while 'lane_->doneMutex' is on) | 708 | lane_->doneCondVar.notify_one(); // wake up master (while 'lane_->doneMutex' is on) |
709 | } | 709 | } |