Core/Scripting: Fix acquiring of references between script swaps
* Delay unloading of shared libraries to the next update tick to prevent crashes in the destructor of the last referenced script instance. * Closes #17557
This commit is contained in:
1 parent
a354feb48b
commit
efa3d00ebf
3 files changed
+55
-14
No files matched your search
@@ -987,7 +987,7 @@ void ScriptMgr::Initialize()
|
|||||||
FillSpellSummary();
|
FillSpellSummary();
|
||||||
|
|
||||||
// Load core scripts
|
// Load core scripts
|
||||||
SetScriptContext("___static___");
|
SetScriptContext(GetNameOfStaticContext());
|
||||||
|
|
||||||
// SmartAI
|
// SmartAI
|
||||||
AddSC_SmartScripts();
|
AddSC_SmartScripts();
|
||||||
@@ -1043,6 +1043,12 @@ void ScriptMgr::SwapScriptContext(bool initialize)
|
|||||||
_currentContext.clear();
|
_currentContext.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string const& ScriptMgr::GetNameOfStaticContext()
|
||||||
|
{
|
||||||
|
static std::string const name = "___static___";
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptMgr::ReleaseScriptContext(std::string const& context)
|
void ScriptMgr::ReleaseScriptContext(std::string const& context)
|
||||||
{
|
{
|
||||||
sScriptRegistryCompositum->ReleaseContext(context);
|
sScriptRegistryCompositum->ReleaseContext(context);
|
||||||
|
|||||||
@@ -879,6 +879,9 @@ class TC_GAME_API ScriptMgr
|
|||||||
/// calls for better performance (bulk changes).
|
/// calls for better performance (bulk changes).
|
||||||
void SwapScriptContext(bool initialize = false);
|
void SwapScriptContext(bool initialize = false);
|
||||||
|
|
||||||
|
/// Returns the context name of the static context provided by the worldserver
|
||||||
|
static std::string const& GetNameOfStaticContext();
|
||||||
|
|
||||||
/// Acquires a strong module reference to the module containing the given script name,
|
/// Acquires a strong module reference to the module containing the given script name,
|
||||||
/// which prevents the shared library which contains the script from unloading.
|
/// which prevents the shared library which contains the script from unloading.
|
||||||
/// The shared library is lazy unloaded as soon as all references to it are released.
|
/// The shared library is lazy unloaded as soon as all references to it are released.
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ public:
|
|||||||
static Optional<std::shared_ptr<ScriptModule>>
|
static Optional<std::shared_ptr<ScriptModule>>
|
||||||
CreateFromPath(fs::path const& path, Optional<fs::path> cache_path);
|
CreateFromPath(fs::path const& path, Optional<fs::path> cache_path);
|
||||||
|
|
||||||
|
static void ScheduleDelayedDelete(ScriptModule* module);
|
||||||
|
|
||||||
char const* GetScriptModuleRevisionHash() const override
|
char const* GetScriptModuleRevisionHash() const override
|
||||||
{
|
{
|
||||||
return _getScriptModuleRevisionHash();
|
return _getScriptModuleRevisionHash();
|
||||||
@@ -275,8 +277,13 @@ Optional<std::shared_ptr<ScriptModule>>
|
|||||||
GetFunctionFromSharedLibrary(handle, "AddScripts", addScripts) &&
|
GetFunctionFromSharedLibrary(handle, "AddScripts", addScripts) &&
|
||||||
GetFunctionFromSharedLibrary(handle, "GetScriptModule", getScriptModule) &&
|
GetFunctionFromSharedLibrary(handle, "GetScriptModule", getScriptModule) &&
|
||||||
GetFunctionFromSharedLibrary(handle, "GetBuildDirective", getBuildDirective))
|
GetFunctionFromSharedLibrary(handle, "GetBuildDirective", getBuildDirective))
|
||||||
return std::make_shared<ScriptModule>(std::move(holder), getScriptModuleRevisionHash,
|
{
|
||||||
|
auto module = new ScriptModule(std::move(holder), getScriptModuleRevisionHash,
|
||||||
addScripts, getScriptModule, getBuildDirective, path);
|
addScripts, getScriptModule, getBuildDirective, path);
|
||||||
|
|
||||||
|
// Unload the module at the next update tick as soon as all references are removed
|
||||||
|
return std::shared_ptr<ScriptModule>(module, ScheduleDelayedDelete);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TC_LOG_ERROR("scripts.hotswap", "Could not extract all required functions from the shared library \"%s\"!",
|
TC_LOG_ERROR("scripts.hotswap", "Could not extract all required functions from the shared library \"%s\"!",
|
||||||
@@ -918,13 +925,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sScriptMgr->SetScriptContext(module_name);
|
|
||||||
(*module)->AddScripts();
|
|
||||||
TC_LOG_TRACE("scripts.hotswap", ">> Registered all scripts of module %s.", module_name.c_str());
|
|
||||||
|
|
||||||
if (swap_context)
|
|
||||||
sScriptMgr->SwapScriptContext();
|
|
||||||
|
|
||||||
// Create the source listener
|
// Create the source listener
|
||||||
auto listener = Trinity::make_unique<SourceUpdateListener>(
|
auto listener = Trinity::make_unique<SourceUpdateListener>(
|
||||||
sScriptReloadMgr->GetSourceDirectory() / module_name,
|
sScriptReloadMgr->GetSourceDirectory() / module_name,
|
||||||
@@ -933,8 +933,16 @@ private:
|
|||||||
// Store the module
|
// Store the module
|
||||||
_known_modules_build_directives.insert(std::make_pair(module_name, (*module)->GetBuildDirective()));
|
_known_modules_build_directives.insert(std::make_pair(module_name, (*module)->GetBuildDirective()));
|
||||||
_running_script_modules.insert(std::make_pair(module_name,
|
_running_script_modules.insert(std::make_pair(module_name,
|
||||||
std::make_pair(std::move(*module), std::move(listener))));
|
std::make_pair(*module, std::move(listener))));
|
||||||
_running_script_module_names.insert(std::make_pair(path, module_name));
|
_running_script_module_names.insert(std::make_pair(path, module_name));
|
||||||
|
|
||||||
|
// Process the script loading after the module was registered correctly (#17557).
|
||||||
|
sScriptMgr->SetScriptContext(module_name);
|
||||||
|
(*module)->AddScripts();
|
||||||
|
TC_LOG_TRACE("scripts.hotswap", ">> Registered all scripts of module %s.", module_name.c_str());
|
||||||
|
|
||||||
|
if (swap_context)
|
||||||
|
sScriptMgr->SwapScriptContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessReloadScriptModule(fs::path const& path)
|
void ProcessReloadScriptModule(fs::path const& path)
|
||||||
@@ -1414,6 +1422,26 @@ private:
|
|||||||
fs::path temporary_cache_path_;
|
fs::path temporary_cache_path_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ScriptModuleDeleteMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ScriptModuleDeleteMessage(ScriptModule* module)
|
||||||
|
: module_(module) { }
|
||||||
|
|
||||||
|
void operator() (HotSwapScriptReloadMgr*)
|
||||||
|
{
|
||||||
|
module_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<ScriptModule> module_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ScriptModule::ScheduleDelayedDelete(ScriptModule* module)
|
||||||
|
{
|
||||||
|
sScriptReloadMgr->QueueMessage(ScriptModuleDeleteMessage(module));
|
||||||
|
}
|
||||||
|
|
||||||
/// Maps efsw actions to strings
|
/// Maps efsw actions to strings
|
||||||
static char const* ActionToString(efsw::Action action)
|
static char const* ActionToString(efsw::Action action)
|
||||||
{
|
{
|
||||||
@@ -1571,11 +1599,15 @@ void SourceUpdateListener::handleFileAction(efsw::WatchID watchid, std::string c
|
|||||||
std::shared_ptr<ModuleReference>
|
std::shared_ptr<ModuleReference>
|
||||||
ScriptReloadMgr::AcquireModuleReferenceOfContext(std::string const& context)
|
ScriptReloadMgr::AcquireModuleReferenceOfContext(std::string const& context)
|
||||||
{
|
{
|
||||||
auto const itr = sScriptReloadMgr->_running_script_modules.find(context);
|
// Return empty references for the static context exported by the worldserver
|
||||||
if (itr != sScriptReloadMgr->_running_script_modules.end())
|
if (context == ScriptMgr::GetNameOfStaticContext())
|
||||||
return itr->second.first;
|
|
||||||
else
|
|
||||||
return { };
|
return { };
|
||||||
|
|
||||||
|
auto const itr = sScriptReloadMgr->_running_script_modules.find(context);
|
||||||
|
ASSERT(itr != sScriptReloadMgr->_running_script_modules.end()
|
||||||
|
&& "Requested a reference to a non existent script context!");
|
||||||
|
|
||||||
|
return itr->second.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the full hot swap implemented ScriptReloadMgr
|
// Returns the full hot swap implemented ScriptReloadMgr
|
||||||
|
|||||||
Reference in new issue
Block a user