diff options
-rw-r--r-- | docs/index.html | 7 | ||||
-rw-r--r-- | src/universe.cpp | 24 |
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 |