From 15255a36e495d231bd3ff82b0a11c42c4f674e7c Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Wed, 24 Jul 2024 22:25:29 -0500 Subject: [PATCH] AP_Scripting: reference function to run separately Some bits of the code in the require machinery use the `lua_ref` to access the script environment. However, this can change after the script is rescheduled and it returns an arbitrary function to run next. Resolve this by introducing `run_ref` which is specifically a reference to the function to run next. `lua_ref` is preserved for the script lifetime. --- libraries/AP_Scripting/lua_scripts.cpp | 12 ++++++++---- libraries/AP_Scripting/lua_scripts.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/AP_Scripting/lua_scripts.cpp b/libraries/AP_Scripting/lua_scripts.cpp index d0fe11a993..f9800d76b6 100644 --- a/libraries/AP_Scripting/lua_scripts.cpp +++ b/libraries/AP_Scripting/lua_scripts.cpp @@ -199,7 +199,9 @@ lua_scripts::script_info *lua_scripts::load_script(lua_State *L, char *filename) update_stats(filename, loadEnd-loadStart, endMem, loadMem); new_script->name = filename; - new_script->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX); // cache the reference + lua_pushvalue(L, -1); + new_script->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX); // store reference to object for environment purposes + new_script->run_ref = luaL_ref(L, LUA_REGISTRYINDEX); // store reference to function to run new_script->next_run_ms = AP_HAL::millis64() - 1; // force the script to be stale // Get checksum of file @@ -325,7 +327,8 @@ void lua_scripts::run_next_script(lua_State *L) { int stack_top = lua_gettop(L); // pop the function to the top of the stack - lua_rawgeti(L, LUA_REGISTRYINDEX, script->lua_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, script->run_ref); + // set object for environment purposes AP::scripting()->set_current_ref(script->lua_ref); if(lua_pcall(L, 0, LUA_MULTRET, 0)) { @@ -364,8 +367,8 @@ void lua_scripts::run_next_script(lua_State *L) { // types match the expectations, go ahead and reschedule script->next_run_ms = start_time_ms + (uint64_t)luaL_checknumber(L, -1); lua_pop(L, 1); - int old_ref = script->lua_ref; - script->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX); + int old_ref = script->run_ref; + script->run_ref = luaL_ref(L, LUA_REGISTRYINDEX); luaL_unref(L, LUA_REGISTRYINDEX, old_ref); reschedule_script(script); break; @@ -410,6 +413,7 @@ void lua_scripts::remove_script(lua_State *L, script_info *script) { if (L != nullptr) { // state could be null if we are force killing all scripts luaL_unref(L, LUA_REGISTRYINDEX, script->lua_ref); + luaL_unref(L, LUA_REGISTRYINDEX, script->run_ref); } _heap.deallocate(script->name); _heap.deallocate(script); diff --git a/libraries/AP_Scripting/lua_scripts.h b/libraries/AP_Scripting/lua_scripts.h index 3f7129172e..0f7e6dc7fd 100644 --- a/libraries/AP_Scripting/lua_scripts.h +++ b/libraries/AP_Scripting/lua_scripts.h @@ -63,6 +63,7 @@ private: typedef struct script_info { int lua_ref; // reference to the loaded script object + int run_ref; // reference to the function to run uint64_t next_run_ms; // time (in milliseconds) the script should next be run at uint32_t crc; // crc32 checksum char *name; // filename for the script // FIXME: This information should be available from Lua