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.
This commit is contained in:
Thomas Watson 2024-07-24 22:25:29 -05:00 committed by Andrew Tridgell
parent c797baa37b
commit 15255a36e4
2 changed files with 9 additions and 4 deletions

View File

@ -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);

View File

@ -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