summaryrefslogtreecommitdiff
path: root/indra/newview/llluamanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llluamanager.cpp')
-rw-r--r--indra/newview/llluamanager.cpp35
1 files changed, 35 insertions, 0 deletions
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);