aboutsummaryrefslogtreecommitdiff
path: root/src/universe.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/universe.cpp34
1 files changed, 19 insertions, 15 deletions
diff --git a/src/universe.cpp b/src/universe.cpp
index 1cb4fd0..5fda29a 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -147,8 +147,7 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo
147 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 147 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
148 lua_createtable(L_, 0, 1); // L_: settings universe {mt} 148 lua_createtable(L_, 0, 1); // L_: settings universe {mt}
149 std::ignore = luaG_getfield(L_, 1, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout 149 std::ignore = luaG_getfield(L_, 1, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout
150 std::ignore = luaG_getfield(L_, 1, "shutdown_mode"); // L_: settings universe {mt} shutdown_timeout shutdown_mode 150 lua_pushcclosure(L_, LG_universe_gc, 1); // L_: settings universe {mt} LG_universe_gc
151 lua_pushcclosure(L_, LG_universe_gc, 2); // L_: settings universe {mt} LG_universe_gc
152 lua_setfield(L_, -2, "__gc"); // L_: settings universe {mt} 151 lua_setfield(L_, -2, "__gc"); // L_: settings universe {mt}
153 lua_setmetatable(L_, -2); // L_: settings universe 152 lua_setmetatable(L_, -2); // L_: settings universe
154 lua_pop(L_, 1); // L_: settings 153 lua_pop(L_, 1); // L_: settings
@@ -352,7 +351,7 @@ lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std::
352 351
353// ################################################################################################# 352// #################################################################################################
354 353
355void Universe::terminateFreeRunningLanes(lua_State* const L_, lua_Duration const shutdownTimeout_, CancelOp const op_) 354bool Universe::terminateFreeRunningLanes(lua_Duration const shutdownTimeout_, CancelOp const op_)
356{ 355{
357 if (selfdestructFirst != SELFDESTRUCT_END) { 356 if (selfdestructFirst != SELFDESTRUCT_END) {
358 // Signal _all_ still running threads to exit (including the timer thread) 357 // Signal _all_ still running threads to exit (including the timer thread)
@@ -404,15 +403,8 @@ void Universe::terminateFreeRunningLanes(lua_State* const L_, lua_Duration const
404 } 403 }
405 } 404 }
406 405
407 // If after all this, we still have some free-running lanes, it's an external user error, they should have stopped appropriately 406 // are all lanes successfully terminated?
408 { 407 return selfdestructFirst == SELFDESTRUCT_END;
409 std::lock_guard<std::mutex> _guard{ selfdestructMutex };
410 Lane* _lane{ selfdestructFirst };
411 if (_lane != SELFDESTRUCT_END) {
412 // this causes a leak because we don't call U's destructor (which could be bad if the still running lanes are accessing it)
413 raise_luaL_error(L_, "Zombie thread '%s' refuses to die!", _lane->debugName.data());
414 }
415 }
416} 408}
417 409
418// ################################################################################################# 410// #################################################################################################
@@ -421,15 +413,21 @@ void Universe::terminateFreeRunningLanes(lua_State* const L_, lua_Duration const
421LUAG_FUNC(universe_gc) 413LUAG_FUNC(universe_gc)
422{ 414{
423 lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; 415 lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) };
424 std::string_view const _op_string{ luaG_tostring(L_, lua_upvalueindex(2)) };
425 STACK_CHECK_START_ABS(L_, 1); 416 STACK_CHECK_START_ABS(L_, 1);
426 Universe* const _U{ luaG_tofulluserdata<Universe>(L_, 1) }; // L_: U 417 Universe* const _U{ luaG_tofulluserdata<Universe>(L_, 1) }; // L_: U
427 _U->terminateFreeRunningLanes(L_, _shutdown_timeout, WhichCancelOp(_op_string)); 418
419 // attempt to terminate all lanes with increasingly stronger cancel methods
420 bool const _allLanesTerminated{
421 _U->terminateFreeRunningLanes(_shutdown_timeout, CancelOp::Soft)
422 || _U->terminateFreeRunningLanes(_shutdown_timeout, CancelOp::Hard)
423 || _U->terminateFreeRunningLanes(_shutdown_timeout, CancelOp::MaskAll)
424 };
428 425
429 // invoke the function installed by lanes.finally() 426 // invoke the function installed by lanes.finally()
430 kFinalizerRegKey.pushValue(L_); // L_: U finalizer|nil 427 kFinalizerRegKey.pushValue(L_); // L_: U finalizer|nil
431 if (!lua_isnil(L_, -1)) { 428 if (!lua_isnil(L_, -1)) {
432 lua_pcall(L_, 0, 0, 0); // L_: U 429 lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool
430 lua_pcall(L_, 1, 0, 0); // L_: U
433 // discard any error that might have occured 431 // discard any error that might have occured
434 lua_settop(L_, 1); 432 lua_settop(L_, 1);
435 } else { 433 } else {
@@ -438,6 +436,12 @@ LUAG_FUNC(universe_gc)
438 // in case of error, the message is pushed on the stack 436 // in case of error, the message is pushed on the stack
439 STACK_CHECK(L_, 1); 437 STACK_CHECK(L_, 1);
440 438
439 // if some lanes are still running here, we have no other choice than crashing and let the client figure out what's wrong
440 while (_U->selfdestructFirst != SELFDESTRUCT_END) {
441 throw std::logic_error{ "Some lanes are still running at shutdown" };
442 //std::this_thread::yield();
443 }
444
441 // no need to mutex-protect this as all threads in the universe are gone at that point 445 // no need to mutex-protect this as all threads in the universe are gone at that point
442 if (_U->timerLinda != nullptr) { // test in case some early internal error prevented Lanes from creating the deep timer 446 if (_U->timerLinda != nullptr) { // test in case some early internal error prevented Lanes from creating the deep timer
443 [[maybe_unused]] int const _prev_ref_count{ _U->timerLinda->refcount.fetch_sub(1, std::memory_order_relaxed) }; 447 [[maybe_unused]] int const _prev_ref_count{ _U->timerLinda->refcount.fetch_sub(1, std::memory_order_relaxed) };