diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-03-28 12:43:07 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-03-28 12:43:07 -0400 |
commit | b165191a1488201c35170d0c5ba4fcd8c5342bf2 (patch) | |
tree | c8af5940b2112de56d3cc4b47706d0627bea8482 | |
parent | 29eee8bd6e92b94a52e8489b98cb81a396d230ed (diff) | |
parent | 53ce38b106a086a4e3bc1ed0663bb47b0f0d967c (diff) |
Merge branch 'lua-hangfix' into lua-startup.
-rw-r--r-- | indra/llcommon/llevents.h | 14 | ||||
-rw-r--r-- | indra/llcommon/lua_function.cpp | 3 | ||||
-rw-r--r-- | indra/llcommon/lua_function.h | 3 | ||||
-rw-r--r-- | indra/llcommon/lualistener.cpp | 29 | ||||
-rw-r--r-- | indra/llcommon/lualistener.h | 2 | ||||
-rw-r--r-- | indra/newview/llluamanager.cpp | 42 | ||||
-rw-r--r-- | indra/newview/tests/llluamanager_test.cpp | 20 |
7 files changed, 53 insertions, 60 deletions
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 77a405871d..c1b752a143 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -48,27 +48,13 @@ #pragma warning (pop) #endif -#include <boost/bind.hpp> -#include <boost/utility.hpp> // noncopyable #include <boost/optional/optional.hpp> -#include <boost/visit_each.hpp> -#include <boost/ref.hpp> // reference_wrapper -#include <boost/type_traits/is_pointer.hpp> -#include <boost/static_assert.hpp> #include "llsd.h" #include "llsingleton.h" #include "lldependencies.h" -#include "llstl.h" #include "llexception.h" #include "llhandle.h" -/*==========================================================================*| -// override this to allow binding free functions with more parameters -#ifndef LLEVENTS_LISTENER_ARITY -#define LLEVENTS_LISTENER_ARITY 10 -#endif -|*==========================================================================*/ - // hack for testing #ifndef testable #define testable private diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp index 9f0abd5674..e731408c7d 100644 --- a/indra/llcommon/lua_function.cpp +++ b/indra/llcommon/lua_function.cpp @@ -31,6 +31,9 @@ #include "lualistener.h" #include "stringize.h" +#define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n))) +#define lua_rawlen lua_objlen + /***************************************************************************** * luau namespace *****************************************************************************/ diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h index 07848e38af..868c13c3f1 100644 --- a/indra/llcommon/lua_function.h +++ b/indra/llcommon/lua_function.h @@ -23,9 +23,6 @@ class LuaListener; -#define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n))) -#define lua_rawlen lua_objlen - namespace lluau { // luau defines luaL_error() as void, but we want to use the Lua idiom of diff --git a/indra/llcommon/lualistener.cpp b/indra/llcommon/lualistener.cpp index ed34133924..018a31d5a8 100644 --- a/indra/llcommon/lualistener.cpp +++ b/indra/llcommon/lualistener.cpp @@ -36,7 +36,22 @@ LuaListener::LuaListener(lua_State* L): mListener(new LLLeapListener( "LuaListener", [this](const std::string& pump, const LLSD& data) - { return queueEvent(pump, data); })) + { return queueEvent(pump, data); })), + // Listen for shutdown events on the "LLApp" LLEventPump. + mShutdownConnection( + LLEventPumps::instance().obtain("LLApp").listen( + LLEventPump::inventName("LuaState"), + [this](const LLSD& status) + { + const auto& statsd = status["status"]; + if (statsd.asString() != "running") + { + // If a Lua script is still blocked in getNext() during + // viewer shutdown, close the queue to wake up getNext(). + mQueue.close(); + } + return false; + })) {} LuaListener::~LuaListener() @@ -87,5 +102,15 @@ bool LuaListener::queueEvent(const std::string& pump, const LLSD& data) LuaListener::PumpData LuaListener::getNext() { - return mQueue.pop(); + try + { + return mQueue.pop(); + } + catch (const LLThreadSafeQueueInterrupt&) + { + // mQueue has been closed. The only way that happens is when we detect + // viewer shutdown. Terminate the calling coroutine. + LLCoros::checkStop(); + return {}; + } } diff --git a/indra/llcommon/lualistener.h b/indra/llcommon/lualistener.h index c13b7bbd5f..40ccfba8fe 100644 --- a/indra/llcommon/lualistener.h +++ b/indra/llcommon/lualistener.h @@ -12,6 +12,7 @@ #if ! defined(LL_LUALISTENER_H) #define LL_LUALISTENER_H +#include "llevents.h" #include "llinstancetracker.h" #include "llsd.h" #include "llthreadsafequeue.h" @@ -73,6 +74,7 @@ private: LLThreadSafeQueue<PumpData> mQueue; std::unique_ptr<LLLeapListener> mListener; + LLTempBoundListener mShutdownConnection; }; #endif /* ! defined(LL_LUALISTENER_H) */ diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index aed6aee239..be9aa3c1ed 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -31,20 +31,11 @@ #include "llcoros.h" #include "llerror.h" #include "lleventcoro.h" +#include "llviewercontrol.h" #include "lua_function.h" #include "lualistener.h" #include "stringize.h" -// skip all these link dependencies for integration testing -#ifndef LL_TEST -#include "lluilistener.h" -#include "llviewercontrol.h" - -// FIXME extremely hacky way to get to the UI Listener framework. There's -// a cleaner way. -extern LLUIListener sUIListener; -#endif // ! LL_TEST - #include <boost/algorithm/string/replace.hpp> #include <filesystem> @@ -126,37 +117,6 @@ lua_function(print_warning, "print_warning(args...): WARNING level logging") return 0; } -#ifndef LL_TEST - -lua_function(run_ui_command, - "run_ui_command(name [, parameter]): " - "call specified UI command with specified parameter") -{ - int top = lua_gettop(L); - std::string func_name; - if (top >= 1) - { - func_name = lua_tostring(L,1); - } - std::string parameter; - if (top >= 2) - { - parameter = lua_tostring(L,2); - } - LL_WARNS("LUA") << "running ui func " << func_name << " parameter " << parameter << LL_ENDL; - LLSD event; - event["function"] = func_name; - if (!parameter.empty()) - { - event["parameter"] = parameter; - } - sUIListener.call(event); - - lua_settop(L, 0); - return 0; -} -#endif // ! LL_TEST - lua_function(post_on, "post_on(pumpname, data): post specified data to specified LLEventPump") { std::string pumpname{ lua_tostdstring(L, 1) }; diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index e10dedcf53..b907ac6619 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -418,4 +418,24 @@ namespace tut auto [count, result] = future.get(); ensure_equals("leap.lua: " + result.asString(), count, 0); } + + template<> template<> + void object::test<7>() + { + set_test_name("stop hanging Lua script"); + const std::string lua( + "-- hanging Lua script should terminate\n" + "\n" + "LL.get_event_next()\n" + ); + LuaState L; + auto future = LLLUAmanager::startScriptLine(L, lua); + // Poke LLTestApp to send its preliminary shutdown message. + mApp.setQuitting(); + // but now we have to give the startScriptLine() coroutine a chance to run + auto [count, result] = future.get(); + ensure_equals("killed Lua script terminated normally", count, -1); + ensure_equals("unexpected killed Lua script error", + result.asString(), "viewer is stopping"); + } } // namespace tut |