diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-02-22 20:42:08 -0500 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-02-22 20:42:08 -0500 |
commit | 85ef003ed7836cb351ee62ed44a4837a305e9dbd (patch) | |
tree | 6d747a2961291e46c5eadd23f8b9e30ce8101d7f /indra/newview | |
parent | 484b91dd65c8029ad5a52a6b4684d9046df709ac (diff) |
Lua listen_events(), await_event() => get_event_{pumps,next}().
Don't set up a Lua callback to receive incoming events, a la listen_events().
Don't listen on an arbitrary event pump, a la await_event().
Instead, the new get_event_pumps() entry point simply delivers the reply pump
and command pump names (as listen_events() did) without storing a Lua
callback.
Make LuaListener capture incoming events on the reply pump in a queue. This
avoids the problem of multiple events arriving too quickly for the Lua script
to retrieve. If the queue gets too big, discard the excess instead of blocking
the caller of post().
Then the new get_event_next() entry point retrieves the next (pump, data) pair
from the queue, blocking the Lua script until a suitable event arrives. This
is closer to the use of stdin for a LEAP plugin. It also addresses the
question: what should the Lua script's C++ coroutine do while waiting for an
incoming reply pump event?
Recast llluamanager_test.cpp for this new, more straightforward API.
Move LLLeap's and LuaListener's reply LLEventPump into LLLeapListener, which
they both use. This simplifies LLLeapListener's API, which was a little
convoluted: the caller supplied a connect callback to allow LLLeapListener to
connect some listener to the caller's reply pump. Now, instead, the caller
simply passes a bool(pumpname, data) callback to receive events incoming on
LLLeapListener's own reply pump.
Fix a latent bug in LLLeapListener: if a plugin called listen() more than once
with the same listener name, the new connection would not have been saved.
While at it, replace some older Boost features in LLLeapListener and LLLeap.
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/llluamanager.cpp | 63 | ||||
-rw-r--r-- | indra/newview/tests/llluamanager_test.cpp | 35 |
2 files changed, 35 insertions, 63 deletions
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp index c6a900aa81..33b996ab50 100644 --- a/indra/newview/llluamanager.cpp +++ b/indra/newview/llluamanager.cpp @@ -166,55 +166,34 @@ lua_function(post_on, "post_on(pumpname, data): post specified data to specified return 0; } -lua_function(listen_events, - "listen_events(callback): call callback(pumpname, data) with events received\n" - "on this Lua chunk's replypump.\n" - "Returns replypump, commandpump: names of LLEventPumps specific to this chunk.") +lua_function(get_event_pumps, + "get_event_pumps():\n" + "Returns replypump, commandpump: names of LLEventPumps specific to this chunk.\n" + "Events posted to replypump are queued for get_event_next().\n" + "post_on(commandpump, ...) to engage LLEventAPI operations (see helpleap()).") { - if (! lua_isfunction(L, 1)) - { - luaL_typeerror(L, 1, "function"); - return 0; - } luaL_checkstack(L, 2, nullptr); - -/*==========================================================================*| - // Get the lua_State* for the main thread of this state, in case we were - // called from a coroutine thread. We're going to make callbacks into Lua - // code, and we want to do it on the main thread rather than a (possibly - // suspended) coroutine thread. - // Registry table is at pseudo-index LUA_REGISTRYINDEX - // Main thread is at registry key LUA_RIDX_MAINTHREAD - auto regtype {lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD)}; - // Not finding the main thread at the documented place isn't a user error, - // it's a Problem - llassert_always(regtype == LUA_TTHREAD); - lua_State* mainthread{ lua_tothread(L, -1) }; - // pop the main thread - lua_pop(L, 1); -|*==========================================================================*/ - // Luau is based on Lua 5.1, and Lua 5.1 apparently provides no way to get - // back to the main thread from a coroutine thread? - lua_State* mainthread{ L }; - - auto listener{ LuaState::obtainListener(mainthread) }; - - // Now that we've found or created our LuaListener, store the passed Lua - // function as the callback. Beware: our caller passed the function on L's - // stack, but we want to store it on the mainthread registry. - if (L != mainthread) - { - // push 1 value (the Lua function) from L's stack to mainthread's - lua_xmove(L, mainthread, 1); - } - lua_setfield(mainthread, LUA_REGISTRYINDEX, "event.function"); - + auto listener{ LuaState::obtainListener(L) }; // return the reply pump name and the command pump name on caller's lua_State lua_pushstdstring(L, listener->getReplyName()); lua_pushstdstring(L, listener->getCommandName()); return 2; } +lua_function(get_event_next, + "get_event_next():\n" + "Returns the next (pumpname, data) pair from the replypump whose name\n" + "is returned by get_event_pumps(). Blocks the calling chunk until an\n" + "event becomes available.") +{ + luaL_checkstack(L, 2, nullptr); + auto listener{ LuaState::obtainListener(L) }; + const auto& [pump, data]{ listener->getNext() }; + lua_pushstdstring(L, pump); + lua_pushllsd(L, data); + return 2; +} + lua_function(await_event, "await_event(pumpname [, timeout [, value to return if timeout (default nil)]]):\n" "pause the running Lua chunk until the next event on the named LLEventPump") @@ -343,7 +322,7 @@ void LLLUAmanager::runScriptLine(LuaState& L, const std::string& chunk, script_r if (shortchunk.length() > shortlen) shortchunk = stringize(shortchunk.substr(0, shortlen), "..."); - std::string desc{ stringize("runScriptLine('", shortchunk, "')") }; + std::string desc{ stringize("lua: ", shortchunk) }; LLCoros::instance().launch(desc, [&L, desc, chunk, cb]() { auto [count, result] = L.expr(desc, chunk); diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp index 1f25fd5f3b..81ec186cf4 100644 --- a/indra/newview/tests/llluamanager_test.cpp +++ b/indra/newview/tests/llluamanager_test.cpp @@ -108,7 +108,6 @@ namespace tut replypump.listen("llluamanager_test", listener([&fromlua](const LLSD& data){ fromlua = data; }))); const std::string lua(stringize( - "-- test LLSD synthesized by Lua\n", "data = ", construct, "\n" "post_on('testpump', data)\n" )); @@ -134,7 +133,7 @@ namespace tut template<> template<> void object::test<3>() { - set_test_name("test post_on(), listen_events(), await_event()"); + set_test_name("test post_on(), get_event_pumps(), get_event_next()"); StringVec posts; LLEventStream replypump("testpump"); LLTempBoundListener conn( @@ -142,17 +141,14 @@ namespace tut listener([&posts](const LLSD& data) { posts.push_back(data.asString()); }))); const std::string lua( - "-- test post_on,listen_events,await_event\n" + "-- test post_on,get_event_pumps,get_event_next\n" "post_on('testpump', 'entry')\n" - "callback = function(pump, data)\n" - " -- just echo the data we received\n" - " post_on('testpump', data)\n" - "end\n" - "post_on('testpump', 'listen_events()')\n" - "replypump, cmdpump = listen_events(callback)\n" + "post_on('testpump', 'get_event_pumps()')\n" + "replypump, cmdpump = get_event_pumps()\n" "post_on('testpump', replypump)\n" - "post_on('testpump', 'await_event()')\n" - "await_event(replypump)\n" + "post_on('testpump', 'get_event_next()')\n" + "pump, data = get_event_next()\n" + "post_on('testpump', data)\n" "post_on('testpump', 'exit')\n" ); LuaState L; @@ -162,9 +158,9 @@ namespace tut auto future = LLLUAmanager::startScriptLine(L, lua); StringVec expected{ "entry", - "listen_events()", + "get_event_pumps()", "", - "await_event()", + "get_event_next()", "message", "exit" }; @@ -188,18 +184,15 @@ namespace tut listener([&reply](const LLSD& post){ reply = post; }))); const std::string lua( "-- test LLSD round trip\n" - "callback = function(pump, data)\n" - " -- just echo the data we received\n" - " post_on('testpump', data)\n" - "end\n" - "replypump, cmdpump = listen_events(callback)\n" + "replypump, cmdpump = get_event_pumps()\n" "post_on('testpump', replypump)\n" - "await_event(replypump)\n" + "pump, data = get_event_next()\n" + "return data\n" ); LuaState L; auto future = LLLUAmanager::startScriptLine(L, lua); // We woke up again ourselves because the coroutine running Lua has - // reached the await_event() call, which suspends the calling C++ + // reached the get_event_next() call, which suspends the calling C++ // coroutine (including the Lua code running on it) until we post // something to that reply pump. auto luapump{ reply.asString() }; @@ -208,7 +201,7 @@ namespace tut // The C++ coroutine running the Lua script is now ready to run. Run // it so it will echo the LLSD back to us. auto [count, result] = future.get(); - ensure_equals(desc, reply, expect); + ensure_equals(desc, result, expect); } // Define an RTItem to be used for round-trip LLSD testing: what it is, |