diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b6734e6fc6..7659de0ffd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -59,7 +59,7 @@ list(APPEND COMPONENT_FILES "${OpenMW_BINARY_DIR}/${OSG_PLUGIN_CHECKER_CPP_FILE} add_component_dir (lua luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage utf8 - shapes/box inputactions yamlloader scripttracker + shapes/box inputactions yamlloader scripttracker luastateptr ) add_component_dir (l10n diff --git a/components/esm/luascripts.cpp b/components/esm/luascripts.cpp index 81cc867aff..f724331548 100644 --- a/components/esm/luascripts.cpp +++ b/components/esm/luascripts.cpp @@ -1,8 +1,9 @@ #include "luascripts.hpp" -#include "components/esm3/esmreader.hpp" -#include "components/esm3/esmwriter.hpp" +#include +#include +#include #include // 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"); }; - 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); auto adjustLuaData = [&](std::string& data) { if (data.empty()) return; - sol::object luaData = LuaUtil::deserialize(L, data, &serializer); + sol::object luaData = LuaUtil::deserialize(state.get(), data, &serializer); data = LuaUtil::serialize(luaData, &serializer); }; @@ -123,7 +127,6 @@ void ESM::LuaScriptsCfg::adjustRefNums(const ESMReader& esm) refCfg.mRefnumContentFile = adjustRefNumFn(refCfg.mRefnumContentFile); } } - lua_close(L); } void ESM::LuaScriptsCfg::save(ESMWriter& esm) const diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp index de876f2c5c..f959263153 100644 --- a/components/lua/luastate.cpp +++ b/components/lua/luastate.cpp @@ -11,6 +11,7 @@ #include #include +#include "luastateptr.hpp" #include "scriptscontainer.hpp" #include "utf8.hpp" @@ -151,37 +152,37 @@ namespace LuaUtil return newPtr; } - lua_State* LuaState::createLuaRuntime(LuaState* luaState) + LuaStatePtr LuaState::createLuaRuntime(LuaState* luaState) { if (sProfilerEnabled) { Log(Debug::Info) << "Initializing LuaUtil::LuaState with profiler"; - lua_State* L = lua_newstate(&trackingAllocator, luaState); - if (L) - return L; - else - { - sProfilerEnabled = false; - Log(Debug::Error) - << "Failed to initialize LuaUtil::LuaState with custom allocator; disabling Lua profiler"; - } + LuaStatePtr state(lua_newstate(&trackingAllocator, luaState)); + if (state != nullptr) + return state; + sProfilerEnabled = false; + Log(Debug::Error) << "Failed to initialize LuaUtil::LuaState with custom allocator; disabling Lua profiler"; } Log(Debug::Info) << "Initializing LuaUtil::LuaState without profiler"; - lua_State* L = luaL_newstate(); - if (!L) - throw std::runtime_error("Can't create Lua runtime"); - return L; + LuaStatePtr state(luaL_newstate()); + if (state == nullptr) + throw std::runtime_error("Failed to create Lua runtime"); + return state; } LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf, const LuaStateSettings& settings) : mSettings(settings) - , mLuaHolder(createLuaRuntime(this)) - , mSol(mLuaHolder.get()) + , mLuaState([&] { + LuaStatePtr state = createLuaRuntime(this); + sol::set_default_state(state.get()); + return state; + }()) + , mSol(mLuaState.get()) , mConf(conf) , mVFS(vfs) { if (sProfilerEnabled) - lua_sethook(mLuaHolder.get(), &countHook, LUA_MASKCOUNT, countHookStep); + lua_sethook(mLuaState.get(), &countHook, LUA_MASKCOUNT, countHookStep); protectedCall([&](LuaView& view) { auto& sol = view.sol(); diff --git a/components/lua/luastate.hpp b/components/lua/luastate.hpp index cf8e62690a..d842478cb1 100644 --- a/components/lua/luastate.hpp +++ b/components/lua/luastate.hpp @@ -10,6 +10,7 @@ #include #include "configuration.hpp" +#include "luastateptr.hpp" namespace VFS { @@ -188,7 +189,7 @@ namespace LuaUtil static void countHook(lua_State* L, lua_Debug* ar); 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 { @@ -206,25 +207,8 @@ namespace LuaUtil uint64_t mSmallAllocMemoryUsage = 0; std::vector 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. - LuaStateHolder mLuaHolder; + LuaStatePtr mLuaState; sol::state_view mSol; const ScriptsConfiguration* mConf; diff --git a/components/lua/luastateptr.hpp b/components/lua/luastateptr.hpp new file mode 100644 index 0000000000..09733b0754 --- /dev/null +++ b/components/lua/luastateptr.hpp @@ -0,0 +1,18 @@ +#ifndef OPENMW_COMPONENTS_LUA_LUASTATEPTR_H +#define OPENMW_COMPONENTS_LUA_LUASTATEPTR_H + +#include + +#include + +namespace LuaUtil +{ + struct CloseLuaState + { + void operator()(lua_State* state) noexcept { lua_close(state); } + }; + + using LuaStatePtr = std::unique_ptr; +} + +#endif