Merge branch 'lua_state' into 'master'

Use unique_ptr to handle lua state lifetime

See merge request OpenMW/openmw!4636
This commit is contained in:
Evil Eye 2025-04-23 18:54:40 +00:00
commit b4d5013679
5 changed files with 48 additions and 42 deletions

View file

@ -59,7 +59,7 @@ list(APPEND COMPONENT_FILES "${OpenMW_BINARY_DIR}/${OSG_PLUGIN_CHECKER_CPP_FILE}
add_component_dir (lua add_component_dir (lua
luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage utf8 luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage utf8
shapes/box inputactions yamlloader scripttracker shapes/box inputactions yamlloader scripttracker luastateptr
) )
add_component_dir (l10n add_component_dir (l10n

View file

@ -1,8 +1,9 @@
#include "luascripts.hpp" #include "luascripts.hpp"
#include "components/esm3/esmreader.hpp" #include <components/esm3/esmreader.hpp>
#include "components/esm3/esmwriter.hpp" #include <components/esm3/esmwriter.hpp>
#include <components/lua/luastateptr.hpp>
#include <components/lua/serialization.hpp> #include <components/lua/serialization.hpp>
// List of all records, that are related to Lua. // List of all records, that are related to Lua.
@ -102,13 +103,16 @@ void ESM::LuaScriptsCfg::adjustRefNums(const ESMReader& esm)
throw std::runtime_error("Incorrect contentFile index"); throw std::runtime_error("Incorrect contentFile index");
}; };
lua_State* L = luaL_newstate(); LuaUtil::LuaStatePtr state(luaL_newstate());
if (state == nullptr)
throw std::runtime_error("Failed to create Lua runtime");
LuaUtil::BasicSerializer serializer(adjustRefNumFn); LuaUtil::BasicSerializer serializer(adjustRefNumFn);
auto adjustLuaData = [&](std::string& data) { auto adjustLuaData = [&](std::string& data) {
if (data.empty()) if (data.empty())
return; return;
sol::object luaData = LuaUtil::deserialize(L, data, &serializer); sol::object luaData = LuaUtil::deserialize(state.get(), data, &serializer);
data = LuaUtil::serialize(luaData, &serializer); data = LuaUtil::serialize(luaData, &serializer);
}; };
@ -123,7 +127,6 @@ void ESM::LuaScriptsCfg::adjustRefNums(const ESMReader& esm)
refCfg.mRefnumContentFile = adjustRefNumFn(refCfg.mRefnumContentFile); refCfg.mRefnumContentFile = adjustRefNumFn(refCfg.mRefnumContentFile);
} }
} }
lua_close(L);
} }
void ESM::LuaScriptsCfg::save(ESMWriter& esm) const void ESM::LuaScriptsCfg::save(ESMWriter& esm) const

View file

@ -11,6 +11,7 @@
#include <components/files/conversion.hpp> #include <components/files/conversion.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include "luastateptr.hpp"
#include "scriptscontainer.hpp" #include "scriptscontainer.hpp"
#include "utf8.hpp" #include "utf8.hpp"
@ -151,37 +152,37 @@ namespace LuaUtil
return newPtr; return newPtr;
} }
lua_State* LuaState::createLuaRuntime(LuaState* luaState) LuaStatePtr LuaState::createLuaRuntime(LuaState* luaState)
{ {
if (sProfilerEnabled) if (sProfilerEnabled)
{ {
Log(Debug::Info) << "Initializing LuaUtil::LuaState with profiler"; Log(Debug::Info) << "Initializing LuaUtil::LuaState with profiler";
lua_State* L = lua_newstate(&trackingAllocator, luaState); LuaStatePtr state(lua_newstate(&trackingAllocator, luaState));
if (L) if (state != nullptr)
return L; return state;
else sProfilerEnabled = false;
{ Log(Debug::Error) << "Failed to initialize LuaUtil::LuaState with custom allocator; disabling Lua profiler";
sProfilerEnabled = false;
Log(Debug::Error)
<< "Failed to initialize LuaUtil::LuaState with custom allocator; disabling Lua profiler";
}
} }
Log(Debug::Info) << "Initializing LuaUtil::LuaState without profiler"; Log(Debug::Info) << "Initializing LuaUtil::LuaState without profiler";
lua_State* L = luaL_newstate(); LuaStatePtr state(luaL_newstate());
if (!L) if (state == nullptr)
throw std::runtime_error("Can't create Lua runtime"); throw std::runtime_error("Failed to create Lua runtime");
return L; return state;
} }
LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf, const LuaStateSettings& settings) LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf, const LuaStateSettings& settings)
: mSettings(settings) : mSettings(settings)
, mLuaHolder(createLuaRuntime(this)) , mLuaState([&] {
, mSol(mLuaHolder.get()) LuaStatePtr state = createLuaRuntime(this);
sol::set_default_state(state.get());
return state;
}())
, mSol(mLuaState.get())
, mConf(conf) , mConf(conf)
, mVFS(vfs) , mVFS(vfs)
{ {
if (sProfilerEnabled) if (sProfilerEnabled)
lua_sethook(mLuaHolder.get(), &countHook, LUA_MASKCOUNT, countHookStep); lua_sethook(mLuaState.get(), &countHook, LUA_MASKCOUNT, countHookStep);
protectedCall([&](LuaView& view) { protectedCall([&](LuaView& view) {
auto& sol = view.sol(); auto& sol = view.sol();

View file

@ -10,6 +10,7 @@
#include <components/vfs/pathutil.hpp> #include <components/vfs/pathutil.hpp>
#include "configuration.hpp" #include "configuration.hpp"
#include "luastateptr.hpp"
namespace VFS namespace VFS
{ {
@ -188,7 +189,7 @@ namespace LuaUtil
static void countHook(lua_State* L, lua_Debug* ar); static void countHook(lua_State* L, lua_Debug* ar);
static void* trackingAllocator(void* ud, void* ptr, size_t osize, size_t nsize); static void* trackingAllocator(void* ud, void* ptr, size_t osize, size_t nsize);
lua_State* createLuaRuntime(LuaState* luaState); static LuaStatePtr createLuaRuntime(LuaState* luaState);
struct AllocOwner struct AllocOwner
{ {
@ -206,25 +207,8 @@ namespace LuaUtil
uint64_t mSmallAllocMemoryUsage = 0; uint64_t mSmallAllocMemoryUsage = 0;
std::vector<int64_t> mMemoryUsage; std::vector<int64_t> mMemoryUsage;
class LuaStateHolder
{
public:
LuaStateHolder(lua_State* L)
: L(L)
{
sol::set_default_state(L);
}
~LuaStateHolder() { lua_close(L); }
LuaStateHolder(const LuaStateHolder&) = delete;
LuaStateHolder(LuaStateHolder&&) = delete;
lua_State* get() { return L; }
private:
lua_State* L;
};
// Must be declared before mSol and all sol-related objects. Then on exit it will be destructed the last. // Must be declared before mSol and all sol-related objects. Then on exit it will be destructed the last.
LuaStateHolder mLuaHolder; LuaStatePtr mLuaState;
sol::state_view mSol; sol::state_view mSol;
const ScriptsConfiguration* mConf; const ScriptsConfiguration* mConf;

View file

@ -0,0 +1,18 @@
#ifndef OPENMW_COMPONENTS_LUA_LUASTATEPTR_H
#define OPENMW_COMPONENTS_LUA_LUASTATEPTR_H
#include <sol/state.hpp>
#include <memory>
namespace LuaUtil
{
struct CloseLuaState
{
void operator()(lua_State* state) noexcept { lua_close(state); }
};
using LuaStatePtr = std::unique_ptr<lua_State, CloseLuaState>;
}
#endif