summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorMaxim Nikolenko <maximnproductengine@lindenlab.com>2024-04-16 21:17:46 +0300
committerGitHub <noreply@github.com>2024-04-16 21:17:46 +0300
commit6c2a278c3dbd9d0660be5e9f6ec1c756af7cb992 (patch)
tree9d39fb278553c99d3f8638c7be129000793a2809 /indra/newview
parent3a1a3bb9248939bfec431dc10814eb598591f78a (diff)
parent44e3b1859a925c3d5c9a9caa841669fad9d322b4 (diff)
Merge pull request #1247 from secondlife/lua-interrupts
Call suspend() periodically to avoid viewer freeze
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llfloaterluadebug.cpp6
-rw-r--r--indra/newview/llluamanager.cpp35
2 files changed, 39 insertions, 2 deletions
diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp
index f247528231..6fd11dd1c7 100644
--- a/indra/newview/llfloaterluadebug.cpp
+++ b/indra/newview/llfloaterluadebug.cpp
@@ -123,8 +123,10 @@ void LLFloaterLUADebug::completion(int count, const LLSD& result)
if (count < 0)
{
// error: show error message
- mResultOutput->insertText("*** ");
- mResultOutput->pasteTextWithLinebreaks(result.asString());
+ LLStyle::Params params;
+ params.readonly_color = LLUIColorTable::instance().getColor("LtRed");
+ mResultOutput->appendText(result.asString(), false, params);
+ mResultOutput->endOfDoc();
return;
}
if (count == 1)
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp
index 853ed5a634..dfa27ebc37 100644
--- a/indra/newview/llluamanager.cpp
+++ b/indra/newview/llluamanager.cpp
@@ -51,11 +51,22 @@
std::map<std::string, std::string> LLLUAmanager::sScriptNames;
std::set<std::string> LLLUAmanager::sTerminationList;
+const S32 INTERRUPTS_MAX_LIMIT = 20000;
+const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
+
+void set_interrupts_counter(lua_State *L, S32 counter)
+{
+ lua_pushstring(L, "_INTERRUPTS");
+ lua_pushinteger(L, counter);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+}
+
lua_function(sleep, "sleep(seconds): pause the running coroutine")
{
F32 seconds = lua_tonumber(L, -1);
lua_pop(L, 1);
llcoro::suspendUntilTimeout(seconds);
+ set_interrupts_counter(L, 0);
return 0;
};
@@ -98,6 +109,8 @@ std::string lua_print_msg(lua_State* L, const std::string_view& level)
std::string msg{ out.str() };
// put message out there for any interested party (*koff* LLFloaterLUADebug *koff*)
LLEventPumps::instance().obtain("lua output").post(stringize(level, ": ", msg));
+
+ llcoro::suspend();
return msg;
}
@@ -155,6 +168,7 @@ lua_function(get_event_next,
const auto& [pump, data]{ listener->getNext() };
lua_pushstdstring(L, pump);
lua_pushllsd(L, data);
+ set_interrupts_counter(L, 0);
return 2;
}
@@ -175,6 +189,25 @@ std::pair<int, LLSD> LLLUAmanager::waitScriptFile(const std::string& filename)
return startScriptFile(filename).get();
}
+void check_interrupts_counter(lua_State* L)
+{
+ lua_pushstring(L, "_INTERRUPTS");
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ S32 counter = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ counter++;
+ if (counter > INTERRUPTS_MAX_LIMIT)
+ {
+ lluau::error(L, "Possible infinite loop, terminated.");
+ }
+ else if (counter % INTERRUPTS_SUSPEND_LIMIT == 0)
+ {
+ llcoro::suspend();
+ }
+ set_interrupts_counter(L, counter);
+}
+
void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn result_cb, script_finished_fn finished_cb)
{
// A script_result_fn will be called when LuaState::expr() completes.
@@ -189,6 +222,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r
// A script_finished_fn is used to initialize the LuaState.
// It will be called when the LuaState is destroyed.
LuaState L(finished_cb);
+ set_interrupts_counter(L, 0);
lua_callbacks(L)->interrupt = [](lua_State *L, int gc)
{
@@ -202,6 +236,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r
sTerminationList.erase(it);
lluau::error(L, "Script was terminated");
}
+ check_interrupts_counter(L);
};
std::string text{std::istreambuf_iterator<char>(in_file), {}};
auto [count, result] = L.expr(filename, text);