diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2025-03-17 12:34:08 +0100 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2025-03-17 12:34:08 +0100 |
commit | a57690123ae3ce5bdd7e970690f1380e88e4eaf6 (patch) | |
tree | d526e8f545cef2b1c23978cb9ee5c94dbc9cda2c /src/universe.cpp | |
parent | d93de7ca51edea911eeecb7c8edcffe77298ed07 (diff) | |
download | lanes-a57690123ae3ce5bdd7e970690f1380e88e4eaf6.tar.gz lanes-a57690123ae3ce5bdd7e970690f1380e88e4eaf6.tar.bz2 lanes-a57690123ae3ce5bdd7e970690f1380e88e4eaf6.zip |
Raise a regular Lua error instead of throwing a C++ std::logic_error exception in Universe::UniverseGC
Diffstat (limited to 'src/universe.cpp')
-rw-r--r-- | src/universe.cpp | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/src/universe.cpp b/src/universe.cpp index 3da0801..dd7bc4b 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
@@ -209,6 +209,17 @@ static int luaG_provide_protected_allocator(lua_State* const L_) | |||
209 | 209 | ||
210 | // ################################################################################################# | 210 | // ################################################################################################# |
211 | 211 | ||
212 | void Universe::flagDanglingLanes() const | ||
213 | { | ||
214 | std::lock_guard<std::mutex> _guard{ selfdestructMutex }; | ||
215 | Lane* _lane{ selfdestructFirst }; | ||
216 | while (_lane != SELFDESTRUCT_END) { | ||
217 | _lane->flaggedAfterUniverseGC.store(true, std::memory_order_relaxed); | ||
218 | _lane = _lane->selfdestruct_next; | ||
219 | } | ||
220 | } | ||
221 | // ################################################################################################# | ||
222 | |||
212 | // called once at the creation of the universe (therefore L_ is the master Lua state everything originates from) | 223 | // called once at the creation of the universe (therefore L_ is the master Lua state everything originates from) |
213 | // Do I need to disable this when compiling for LuaJIT to prevent issues? | 224 | // Do I need to disable this when compiling for LuaJIT to prevent issues? |
214 | void Universe::initializeAllocatorFunction(lua_State* const L_) | 225 | void Universe::initializeAllocatorFunction(lua_State* const L_) |
@@ -399,6 +410,7 @@ bool Universe::terminateFreeRunningLanes(lua_Duration const shutdownTimeout_, Ca | |||
399 | // ################################################################################################# | 410 | // ################################################################################################# |
400 | 411 | ||
401 | // process end: cancel any still free-running threads | 412 | // process end: cancel any still free-running threads |
413 | // as far as I can tell, this can only by called only from lua_close() | ||
402 | int Universe::UniverseGC(lua_State* const L_) | 414 | int Universe::UniverseGC(lua_State* const L_) |
403 | { | 415 | { |
404 | lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; | 416 | lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; |
@@ -416,23 +428,37 @@ int Universe::UniverseGC(lua_State* const L_) | |||
416 | kFinalizerRegKey.pushValue(L_); // L_: U finalizer|nil | 428 | kFinalizerRegKey.pushValue(L_); // L_: U finalizer|nil |
417 | if (!lua_isnil(L_, -1)) { | 429 | if (!lua_isnil(L_, -1)) { |
418 | lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool | 430 | lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool |
419 | // no protection. Lua rules for errors in finalizers apply normally | 431 | // no protection. Lua rules for errors in finalizers apply normally: |
420 | lua_call(L_, 1, 1); // L_: U ret|error | 432 | // Lua 5.4: error is propagated in the warn system |
433 | // older: error is swallowed | ||
434 | lua_call(L_, 1, 1); // L_: U msg? | ||
435 | // phew, no error in finalizer, since we reached that point | ||
421 | } | 436 | } |
422 | STACK_CHECK(L_, 2); | ||
423 | 437 | ||
424 | // if some lanes are still running here, we have no other choice than crashing or freezing and let the client figure out what's wrong | 438 | if (lua_isnil(L_, kIdxTop)) { |
425 | bool const _throw{ luaG_tostring(L_, kIdxTop) == "throw" }; | 439 | lua_pop(L_, 1); // L_: U |
426 | lua_pop(L_, 1); // L_: U | 440 | // no finalizer, or it returned no value: push some default message on the stack, in case it is necessary |
441 | luaG_pushstring(L_, "uncooperative lanes detected at shutdown"); // L_: U "msg" | ||
442 | } | ||
443 | STACK_CHECK(L_, 2); | ||
427 | 444 | ||
428 | while (_U->selfdestructFirst != SELFDESTRUCT_END) { | 445 | // now, all remaining lanes are flagged. if they crash because we remove keepers and the Universe from under them, it is their fault |
429 | if (_throw) { | 446 | bool const _detectedUncooperativeLanes{ _U->selfdestructFirst != SELFDESTRUCT_END }; |
430 | throw std::logic_error{ "Some lanes are still running at shutdown" }; | 447 | if (_detectedUncooperativeLanes) { |
448 | _U->flagDanglingLanes(); | ||
449 | if (luaG_tostring(L_, kIdxTop) == "freeze") { | ||
450 | std::this_thread::sleep_until(std::chrono::time_point<std::chrono::steady_clock>::max()); | ||
431 | } else { | 451 | } else { |
432 | std::this_thread::yield(); | 452 | // take the value returned by the finalizer (or our default message) and throw it as an error |
453 | // since we are inside Lua's GCTM, it will be propagated through the warning system (Lua 5.4) or swallowed silently | ||
454 | raise_lua_error(L_); | ||
433 | } | 455 | } |
434 | } | 456 | } |
435 | 457 | ||
458 | // --------------------------------------------------------- | ||
459 | // we don't reach that point if some lanes are still running | ||
460 | // --------------------------------------------------------- | ||
461 | |||
436 | // no need to mutex-protect this as all lanes in the universe are gone at that point | 462 | // no need to mutex-protect this as all lanes in the universe are gone at that point |
437 | Linda::DeleteTimerLinda(L_, std::exchange(_U->timerLinda, nullptr), PK); | 463 | Linda::DeleteTimerLinda(L_, std::exchange(_U->timerLinda, nullptr), PK); |
438 | 464 | ||