diff options
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/llfloaterluascripts.cpp | 3 | ||||
-rw-r--r-- | indra/newview/llluamanager.cpp | 50 | ||||
-rw-r--r-- | indra/newview/llluamanager.h | 3 | ||||
-rw-r--r-- | indra/newview/tests/llluamanager_test.cpp | 35 |
4 files changed, 34 insertions, 57 deletions
diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp index 30353a7210..39d5816b0d 100644 --- a/indra/newview/llfloaterluascripts.cpp +++ b/indra/newview/llfloaterluascripts.cpp @@ -54,8 +54,7 @@ LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key) if (mScriptList->hasSelectedItem()) { std::string coro_name = mScriptList->getSelectedValue(); - LLEventPumps::instance().obtain("LLLua").post(llsd::map("status", "close", "coro", coro_name)); - LLLUAmanager::terminateScript(coro_name); + LLCoros::instance().killreq(coro_name); } }); } diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index dfa27ebc37..97779a12ad 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -49,24 +49,13 @@ #include <vector> 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); + lluau::set_interrupts_counter(L, 0); return 0; }; @@ -168,7 +157,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); + lluau::set_interrupts_counter(L, 0); return 2; } @@ -189,25 +178,6 @@ 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. @@ -222,22 +192,6 @@ 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) - { - // skip if we're interrupting only for garbage collection - if (gc >= 0) - return; - - auto it = sTerminationList.find(LLCoros::getName()); - if (it != sTerminationList.end()) - { - 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); if (result_cb) diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h index d671719bc4..af9dcf70c2 100644 --- a/indra/newview/llluamanager.h +++ b/indra/newview/llluamanager.h @@ -85,12 +85,9 @@ public: static void runScriptOnLogin(); static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; } - static std::set<std::string> getTerminationList() { return sTerminationList; } - static void terminateScript(std::string& coro_name) { sTerminationList.insert(coro_name); } private: static std::map<std::string, std::string> sScriptNames; - static std::set<std::string> sTerminationList; }; class LLRequireResolver diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index b907ac6619..cf1bf25b5c 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -400,9 +400,16 @@ namespace tut auto future = LLLUAmanager::startScriptLine(L, lua); auto replyname{ L.obtainListener()->getReplyName() }; auto& replypump{ LLEventPumps::instance().obtain(replyname) }; - // By the time leap.process() calls get_event_next() and wakes us up, - // we expect that both requester() coroutines have posted and are - // waiting for a reply. + // LuaState::expr() periodically interrupts a running chunk to ensure + // the rest of our coroutines get cycles. Nonetheless, for this test + // we have to wait until both requester() coroutines have posted and + // are waiting for a reply. + for (unsigned count=0; count < 100; ++count) + { + if (requests.size() == 2) + break; + llcoro::suspend(); + } ensure_equals("didn't get both requests", requests.size(), 2); // moreover, we expect they arrived in the order they were created ensure_equals("a wasn't first", requests[0]["name"].asString(), "a"); @@ -413,7 +420,7 @@ namespace tut replypump.post(llsd::map("name", "not special")); // now respond to requester(a) replypump.post(requests[0]); - // tell leap.process() we're done + // tell leap we're done replypump.post(LLSD()); auto [count, result] = future.get(); ensure_equals("leap.lua: " + result.asString(), count, 0); @@ -438,4 +445,24 @@ namespace tut ensure_equals("unexpected killed Lua script error", result.asString(), "viewer is stopping"); } + + template<> template<> + void object::test<8>() + { + set_test_name("stop looping Lua script"); + const std::string desc("looping Lua script should terminate"); + const std::string lua( + "-- " + desc + "\n" + "\n" + "while true do\n" + " x = 1\n" + "end\n" + ); + LuaState L; + auto [count, result] = LLLUAmanager::waitScriptLine(L, lua); + // We expect the above erroneous script has been forcibly terminated + // because it ran too long without doing any actual work. + ensure_equals(desc + " count: " + result.asString(), count, -1); + ensure_contains(desc + " result", result.asString(), "terminated"); + } } // namespace tut |