Slightly better handling of plugin reloading.

This commit is contained in:
Fyren 2016-06-02 00:03:52 +00:00
parent b9f7f20046
commit 4e654704dc
2 changed files with 53 additions and 20 deletions

View File

@ -1192,10 +1192,11 @@ void CPlugin::SetRegistered()
m_state = PluginState::Registered; m_state = PluginState::Registered;
} }
void CPlugin::SetWaitingToUnload() void CPlugin::SetWaitingToUnload(bool andReload)
{ {
assert(m_state == PluginState::Registered); assert(m_state == PluginState::Registered ||
m_state = PluginState::WaitingToUnload; (m_state == PluginState::WaitingToUnload && andReload));
m_state = andReload ? PluginState::WaitingToUnloadAndReload : PluginState::WaitingToUnload;
} }
void CPluginManager::LoadExtensions(CPlugin *pPlugin) void CPluginManager::LoadExtensions(CPlugin *pPlugin)
@ -1440,8 +1441,11 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin)
assert(m_plugins.contains(pPlugin)); assert(m_plugins.contains(pPlugin));
// If we're already in the unload queue, just wait. // If we're already in the unload queue, just wait.
if (pPlugin->State() == PluginState::WaitingToUnload) if (pPlugin->State() == PluginState::WaitingToUnload ||
pPlugin->State() == PluginState::WaitingToUnloadAndReload)
{
return false; return false;
}
// It is not safe to unload any plugin while another is on the callstack. // It is not safe to unload any plugin while another is on the callstack.
bool any_active = false; bool any_active = false;
@ -2015,13 +2019,22 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
else else
strcpy(name, pl->GetFilename()); strcpy(name, pl->GetFilename());
if (ReloadPlugin(pl)) if (ReloadPlugin(pl, true))
{ {
rootmenu->ConsolePrint("[SM] Plugin %s reloaded successfully.", name); rootmenu->ConsolePrint("[SM] Plugin %s reloaded successfully.", name);
} }
else else
{ {
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name); switch (pl->State())
{
//the unload/reload attempt next frame will print a message
case PluginState::WaitingToUnload:
case PluginState::WaitingToUnloadAndReload:
return;
default:
rootmenu->ConsolePrint("[SM] Failed to reload plugin %s.", name);
}
} }
return; return;
@ -2041,15 +2054,14 @@ void CPluginManager::OnRootConsoleCommand(const char *cmdname, const ICommandArg
rootmenu->DrawGenericOption("unload_all", "Unloads all plugins"); rootmenu->DrawGenericOption("unload_all", "Unloads all plugins");
} }
bool CPluginManager::ReloadPlugin(CPlugin *pl) bool CPluginManager::ReloadPlugin(CPlugin *pl, bool print)
{ {
char filename[PLATFORM_MAX_PATH]; PluginState state = pl->State();
bool wasloaded; if (state == PluginState::WaitingToUnloadAndReload)
PluginType ptype; return false;
IPlugin *newpl;
strcpy(filename, pl->GetFilename()); ke::AString filename(pl->GetFilename());
ptype = pl->GetType(); PluginType ptype = pl->GetType();
int id = 1; int id = 1;
for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) { for (PluginIter iter(m_plugins); !iter.done(); iter.next(), id++) {
@ -2059,13 +2071,34 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl)
if (!UnloadPlugin(pl)) if (!UnloadPlugin(pl))
{ {
if (pl->State() == PluginState::WaitingToUnload)
{
pl->SetWaitingToUnload(true);
ScheduleTaskForNextFrame([this, id, filename, ptype, print]() -> void {
ReloadPluginImpl(id, filename.chars(), ptype, print);
});
}
return false; return false;
} }
if (!(newpl=LoadPlugin(filename, true, ptype, NULL, 0, &wasloaded)))
ReloadPluginImpl(id, filename.chars(), ptype, false);
return true;
}
void CPluginManager::ReloadPluginImpl(int id, const char filename[], PluginType ptype, bool print)
{
char error[128];
bool wasloaded;
IPlugin *newpl = LoadPlugin(filename, true, ptype, error, sizeof(error), &wasloaded);
if (!newpl)
{ {
return false; rootmenu->ConsolePrint("[SM] Plugin %s failed to reload: %s.", filename, error);
return;
} }
if (print)
rootmenu->ConsolePrint("[SM] Plugin %s reloaded successfully.", filename);
m_plugins.remove(static_cast<CPlugin *>(newpl)); m_plugins.remove(static_cast<CPlugin *>(newpl));
PluginIter iter(m_plugins); PluginIter iter(m_plugins);
@ -2073,8 +2106,6 @@ bool CPluginManager::ReloadPlugin(CPlugin *pl)
// Empty loop. // Empty loop.
} }
m_plugins.insertBefore(iter, static_cast<CPlugin *>(newpl)); m_plugins.insertBefore(iter, static_cast<CPlugin *>(newpl));
return true;
} }
void CPluginManager::RefreshAll() void CPluginManager::RefreshAll()

View File

@ -88,7 +88,8 @@ enum class PluginState
Evicted, Evicted,
// The plugin is waiting to be unloaded. // The plugin is waiting to be unloaded.
WaitingToUnload WaitingToUnload,
WaitingToUnloadAndReload,
}; };
class CPlugin : class CPlugin :
@ -176,7 +177,7 @@ public:
return m_state; return m_state;
} }
void SetRegistered(); void SetRegistered();
void SetWaitingToUnload(); void SetWaitingToUnload(bool andReload=false);
PluginStatus GetDisplayStatus() const { PluginStatus GetDisplayStatus() const {
return m_status; return m_status;
@ -426,7 +427,7 @@ public:
bool LibraryExists(const char *lib); bool LibraryExists(const char *lib);
bool ReloadPlugin(CPlugin *pl); bool ReloadPlugin(CPlugin *pl, bool print=false);
void UnloadAll(); void UnloadAll();
@ -463,6 +464,7 @@ private:
bool FindOrRequirePluginDeps(CPlugin *pPlugin); bool FindOrRequirePluginDeps(CPlugin *pPlugin);
void UnloadPluginImpl(CPlugin *plugin); void UnloadPluginImpl(CPlugin *plugin);
void ReloadPluginImpl(int id, const char filename[], PluginType ptype, bool print);
void Purge(CPlugin *plugin); void Purge(CPlugin *plugin);
public: public: