aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/index.html7
-rw-r--r--src/universe.cpp24
2 files changed, 17 insertions, 14 deletions
diff --git a/docs/index.html b/docs/index.html
index 1cc007f..0cdf954 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -379,7 +379,7 @@
379 <td> 379 <td>
380 Sets the duration in seconds Lanes will wait for graceful termination of running lanes at application shutdown. Default is <tt>0.25</tt>.<br /> 380 Sets the duration in seconds Lanes will wait for graceful termination of running lanes at application shutdown. Default is <tt>0.25</tt>.<br />
381 Lanes signals all lanes for cancellation with <tt>"soft"</tt>, <tt>"hard"</tt>, and <tt>"all"</tt> modes, in that order. Each attempt has <tt>shutdown_timeout</tt> seconds to succeed before the next one.<br /> 381 Lanes signals all lanes for cancellation with <tt>"soft"</tt>, <tt>"hard"</tt>, and <tt>"all"</tt> modes, in that order. Each attempt has <tt>shutdown_timeout</tt> seconds to succeed before the next one.<br />
382 Then there is a last chance at cleanup with <a href="#finally"><tt>lanes.finally()</tt></a>. If some lanes are still running after that point, shutdown will freeze the application forever. It is YOUR responsibility to cleanup properly after yourself. 382 Then there is a last chance at cleanup with <a href="#finally"><tt>lanes.finally()</tt></a>. If some lanes are still running after that point, shutdown will either freeze or throw. It is YOUR responsibility to cleanup properly after yourself.
383 </td> 383 </td>
384 </tr> 384 </tr>
385 385
@@ -469,9 +469,10 @@
469<p> 469<p>
470 An error will be raised if you attempt to do this from inside a lane, or on bad arguments (non-function, or too many arguments).<br /> 470 An error will be raised if you attempt to do this from inside a lane, or on bad arguments (non-function, or too many arguments).<br />
471 Only the last registered finalizer is kept. It can be cleared by passing <tt>nil</tt> or nothing.<br /> 471 Only the last registered finalizer is kept. It can be cleared by passing <tt>nil</tt> or nothing.<br />
472 The installed function is called after all free-running lanes got a chance to terminate (see<a href="#shutdown_timeout"><tt>shutdown_timeout</tt></a>), but before lindas become unusable.<br /> 472 The finalizer is called unprotected from inside <tt>__gc</tt> metamethod of Lane's Universe. Therefore, if your finalizer raises an error, Lua rules regarding errors in finalizers apply normally.<br />
473 The installed function is called after all free-running lanes got a chance to terminate (see <a href="#shutdown_timeout"><tt>shutdown_timeout</tt></a>), but before lindas become unusable.<br />
473 The finalizer receives a single argument, a <tt>bool</tt> indicating whether some Lanes are still running or not at that point. It is possible to inspect them with <a href="#tracking">tracking</a>.<br /> 474 The finalizer receives a single argument, a <tt>bool</tt> indicating whether some Lanes are still running or not at that point. It is possible to inspect them with <a href="#tracking">tracking</a>.<br />
474 If an error occurs inside this finalizer, it is silently swallowed, since it happens only during state shutdown, and you can't do anything about it. 475 If there are still running lanes when the finalizer returns: Lanes will throw a C++ <tt>std::logic_error</tt> if the finalizer returned <tt>"throw"</tt>. Any other value will cause Lanes to freeze forever.
475</p> 476</p>
476 477
477<hr/> 478<hr/>
diff --git a/src/universe.cpp b/src/universe.cpp
index 5fda29a..04db10f 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -427,22 +427,24 @@ LUAG_FUNC(universe_gc)
427 kFinalizerRegKey.pushValue(L_); // L_: U finalizer|nil 427 kFinalizerRegKey.pushValue(L_); // L_: U finalizer|nil
428 if (!lua_isnil(L_, -1)) { 428 if (!lua_isnil(L_, -1)) {
429 lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool 429 lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool
430 lua_pcall(L_, 1, 0, 0); // L_: U 430 // no protection. Lua rules for errors in finalizers apply normally
431 // discard any error that might have occured 431 lua_call(L_, 1, 1); // L_: U ret|error
432 lua_settop(L_, 1);
433 } else {
434 lua_pop(L_, 1); // L_: U
435 } 432 }
436 // in case of error, the message is pushed on the stack 433 STACK_CHECK(L_, 2);
437 STACK_CHECK(L_, 1); 434
435 // 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
436 bool const _throw{ luaG_tostring(L_, -1) == "throw" };
437 lua_pop(L_, 1); // L_: U
438 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) { 439 while (_U->selfdestructFirst != SELFDESTRUCT_END) {
441 throw std::logic_error{ "Some lanes are still running at shutdown" }; 440 if (_throw) {
442 //std::this_thread::yield(); 441 throw std::logic_error{ "Some lanes are still running at shutdown" };
442 } else {
443 std::this_thread::yield();
444 }
443 } 445 }
444 446
445 // no need to mutex-protect this as all threads in the universe are gone at that point 447 // no need to mutex-protect this as all lanes in the universe are gone at that point
446 if (_U->timerLinda != nullptr) { // test in case some early internal error prevented Lanes from creating the deep timer 448 if (_U->timerLinda != nullptr) { // test in case some early internal error prevented Lanes from creating the deep timer
447 [[maybe_unused]] int const _prev_ref_count{ _U->timerLinda->refcount.fetch_sub(1, std::memory_order_relaxed) }; 449 [[maybe_unused]] int const _prev_ref_count{ _U->timerLinda->refcount.fetch_sub(1, std::memory_order_relaxed) };
448 LUA_ASSERT(L_, _prev_ref_count == 1); // this should be the last reference 450 LUA_ASSERT(L_, _prev_ref_count == 1); // this should be the last reference