diff options
Diffstat (limited to '')
-rw-r--r-- | src/universe.cpp | 34 |
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 | ||
355 | void Universe::terminateFreeRunningLanes(lua_State* const L_, lua_Duration const shutdownTimeout_, CancelOp const op_) | 354 | bool 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 | |||
421 | LUAG_FUNC(universe_gc) | 413 | LUAG_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) }; |