aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-05-17 10:17:20 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-05-17 10:17:20 +0200
commit3dd36a796c9258f552c893d225e0d9cc0f576a6d (patch)
tree2417885e168dfc490413d752f2e01e629ea61a83 /src
parentbe7e5a99aa926d1a823031701453f9aa5c438ef6 (diff)
downloadlanes-3dd36a796c9258f552c893d225e0d9cc0f576a6d.tar.gz
lanes-3dd36a796c9258f552c893d225e0d9cc0f576a6d.tar.bz2
lanes-3dd36a796c9258f552c893d225e0d9cc0f576a6d.zip
Strong typed Lua thread status
Diffstat (limited to 'src')
-rw-r--r--src/compat.h28
-rw-r--r--src/lane.cpp74
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_);
160int lua_getiuservalue(lua_State* L_, int idx_, int n_); 162int lua_getiuservalue(lua_State* L_, int idx_, int n_);
161int lua_setiuservalue(lua_State* L_, int idx_, int n_); 163int 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
201enum class LuaType 205enum 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
232enum 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
243inline 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
225LuaType luaG_getmodule(lua_State* L_, char const* name_); 251LuaType 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
347struct errcode_name 347struct errcode_name
348{ 348{
349 int code; 349 LuaError code;
350 char const* name; 350 char const* name;
351}; 351};
352 352
353static struct errcode_name s_errcodes[] = { 353static 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};
362static char const* get_errcode_name(int _code) 362static 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
467static void push_stack_trace(lua_State* L_, int rc_, int stk_base_) 467static 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 }