summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-03-28 12:43:07 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-03-28 12:43:07 -0400
commitb165191a1488201c35170d0c5ba4fcd8c5342bf2 (patch)
treec8af5940b2112de56d3cc4b47706d0627bea8482
parent29eee8bd6e92b94a52e8489b98cb81a396d230ed (diff)
parent53ce38b106a086a4e3bc1ed0663bb47b0f0d967c (diff)
Merge branch 'lua-hangfix' into lua-startup.
-rw-r--r--indra/llcommon/llevents.h14
-rw-r--r--indra/llcommon/lua_function.cpp3
-rw-r--r--indra/llcommon/lua_function.h3
-rw-r--r--indra/llcommon/lualistener.cpp29
-rw-r--r--indra/llcommon/lualistener.h2
-rw-r--r--indra/newview/llluamanager.cpp42
-rw-r--r--indra/newview/tests/llluamanager_test.cpp20
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