mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 18:03:04 +01:00
Added delay before unloading plugin module after last reference to that module outside plugin manager is gone
This commit is contained in:
parent
b77154b2b5
commit
c076b1d8c1
@ -211,7 +211,6 @@ public:
|
||||
{
|
||||
PluginManagerInterfacePtr pi;
|
||||
pi->unregisterModule(this);
|
||||
pi->moduleUnloaded();
|
||||
|
||||
flagOsUnload = false;
|
||||
}
|
||||
|
@ -172,7 +172,9 @@ public:
|
||||
// Pay attention - this should be called at plugin-regsiter time!
|
||||
// Only at this moment manager knows, which module sets his cleanup
|
||||
virtual void FB_CARG registerModule(IPluginModule* cleanup) = 0;
|
||||
// Remove registered before cleanup routine
|
||||
// Remove registered before cleanup routine.
|
||||
// This method must be called by module which detects that it's unloaded,
|
||||
// but not notified prior to it by PluginManager via IPluginModule.
|
||||
virtual void FB_CARG unregisterModule(IPluginModule* cleanup) = 0;
|
||||
// Main function called to access plugins registered in plugins manager
|
||||
// Has front-end in GetPlugins.h - template GetPlugins
|
||||
@ -189,9 +191,6 @@ public:
|
||||
// Plugins must be released using this function - use of plugin's release()
|
||||
// will cause resources leak
|
||||
virtual void FB_CARG releasePlugin(IPluginBase* plugin) = 0;
|
||||
// This method must be called by module which detects that it's unloaded,
|
||||
// but not notified prior to it by PluginManager via IPluginModule.
|
||||
virtual void FB_CARG moduleUnloaded() = 0;
|
||||
};
|
||||
|
||||
typedef void PluginEntrypoint(IMaster* masterInterface);
|
||||
|
@ -283,18 +283,10 @@ int JService::release()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static AtomicCounter shutdownCounter;
|
||||
|
||||
int JProvider::release()
|
||||
{
|
||||
if (--refCounter == 0)
|
||||
{
|
||||
if (--shutdownCounter == 0)
|
||||
{
|
||||
LocalStatus status;
|
||||
shutdown(&status, 5000, fb_shutrsn_no_connection);
|
||||
}
|
||||
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
@ -302,7 +294,23 @@ int JProvider::release()
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Firebird::UnloadDetector unloadDetector;
|
||||
static UnloadDetector unloadDetector;
|
||||
|
||||
|
||||
class ShutdownBeforeUnload
|
||||
{
|
||||
public:
|
||||
ShutdownBeforeUnload(Firebird::MemoryPool&)
|
||||
{ }
|
||||
~ShutdownBeforeUnload()
|
||||
{
|
||||
LocalStatus status;
|
||||
currentProvider()->shutdown(&status, 0, fb_shutrsn_exit_called);
|
||||
}
|
||||
};
|
||||
|
||||
static GlobalPtr<ShutdownBeforeUnload, InstanceControl::PRIORITY_DETECT_UNLOAD> shutdownBeforeUnload;
|
||||
|
||||
|
||||
class EngineFactory : public StackIface<IPluginFactory>
|
||||
{
|
||||
@ -315,7 +323,7 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
++shutdownCounter;
|
||||
//++shutdownCounter;
|
||||
IPluginBase* p = new JProvider(factoryParameter);
|
||||
p->addRef();
|
||||
return p;
|
||||
@ -3825,7 +3833,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
void JProvider::shutdown(IStatus* status, unsigned int timeout, const int /*reason*/)
|
||||
void JProvider::shutdown(IStatus* status, unsigned int timeout, const int reason)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -3857,6 +3865,15 @@ void JProvider::shutdown(IStatus* status, unsigned int timeout, const int /*reas
|
||||
attach_count, database_count, svc_count);
|
||||
}
|
||||
|
||||
if (reason == fb_shutrsn_exit_called)
|
||||
{
|
||||
// Starting threads may fail when task is going to close.
|
||||
// This happens at least with some microsoft C runtimes.
|
||||
// If people wish to have timeout, they should better call fb_shutdown() themselves.
|
||||
// Therefore:
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
Semaphore shutdown_semaphore;
|
||||
|
@ -484,6 +484,8 @@ public:
|
||||
if (stopThread)
|
||||
{
|
||||
// ignore an attempt to start timer - anyway thread to make it fire is down
|
||||
timer->addRef();
|
||||
timer->release();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ namespace
|
||||
file += newExt;
|
||||
}
|
||||
|
||||
// Holds a reference to plugins.conf file
|
||||
class StaticConfHolder
|
||||
{
|
||||
public:
|
||||
@ -236,7 +237,9 @@ namespace
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct RegisteredPlugin // This is POD object
|
||||
// Plugins registered when loading pluign module
|
||||
// This is POD object - no dtor, only simple data types inside
|
||||
struct RegisteredPlugin
|
||||
{
|
||||
RegisteredPlugin(IPluginFactory* f, const char* nm, unsigned int t)
|
||||
: factory(f), name(nm), type(t)
|
||||
@ -251,6 +254,7 @@ namespace
|
||||
unsigned int type;
|
||||
};
|
||||
|
||||
// Controls module, containing plugins
|
||||
class PluginModule : public Firebird::RefCounted, public GlobalStorage
|
||||
{
|
||||
public:
|
||||
@ -310,6 +314,10 @@ namespace
|
||||
if (cleanup == c)
|
||||
{
|
||||
cleanup = 0;
|
||||
// This is called only by unregister module
|
||||
// when current module is forced to go away by OS.
|
||||
// Do not unload it ourself in this case.
|
||||
addRef();
|
||||
}
|
||||
else if (next)
|
||||
{
|
||||
@ -377,6 +385,8 @@ namespace
|
||||
|
||||
PluginModule* builtin = NULL;
|
||||
|
||||
// Provides most of configuration services for plugins,
|
||||
// except per-database configuration in aliases.conf
|
||||
class ConfiguredPlugin : public RefCounted, public GlobalStorage
|
||||
{
|
||||
public:
|
||||
@ -442,6 +452,34 @@ namespace
|
||||
PathName plugName;
|
||||
};
|
||||
|
||||
// Delays destruction of ConfiguredPlugin instance
|
||||
class PluginDestroyTimer : public Firebird::StdIface<Firebird::ITimer, FB_I_TIMER_VERSION>
|
||||
{
|
||||
public:
|
||||
PluginDestroyTimer(ConfiguredPlugin* cp)
|
||||
: configuredPlugin(cp)
|
||||
{ }
|
||||
|
||||
// ITimer implementation
|
||||
void FB_CARG handler()
|
||||
{ }
|
||||
|
||||
int FB_CARG release()
|
||||
{
|
||||
if (--refCounter == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<ConfiguredPlugin> configuredPlugin;
|
||||
};
|
||||
|
||||
// Provides per-database configuration from aliases.conf
|
||||
class FactoryParameter : public StdIface<IPluginConfig, FB_FACTORY_PARAMETER_VERSION>
|
||||
{
|
||||
public:
|
||||
@ -484,6 +522,12 @@ namespace
|
||||
}
|
||||
|
||||
private:
|
||||
~FactoryParameter()
|
||||
{
|
||||
PluginDestroyTimer* timer = new PluginDestroyTimer(configuredPlugin);
|
||||
TimerInterfacePtr()->start(timer, 1000000); // 1 sec
|
||||
}
|
||||
|
||||
RefPtr<ConfiguredPlugin> configuredPlugin;
|
||||
RefPtr<IFirebirdConf> firebirdConf;
|
||||
};
|
||||
@ -586,6 +630,7 @@ namespace
|
||||
*prev = this;
|
||||
}
|
||||
|
||||
// Provides access to plugins of given type / name
|
||||
class PluginSet : public StdIface<IPluginSet, FB_PLUGIN_SET_VERSION>
|
||||
{
|
||||
public:
|
||||
@ -848,9 +893,16 @@ void FB_CARG PluginManager::registerModule(IPluginModule* cleanup)
|
||||
|
||||
void FB_CARG PluginManager::unregisterModule(IPluginModule* cleanup)
|
||||
{
|
||||
MutexLockGuard g(plugins->mutex);
|
||||
{ // guard scope
|
||||
MutexLockGuard g(plugins->mutex);
|
||||
modules->resetCleanup(cleanup);
|
||||
}
|
||||
|
||||
modules->resetCleanup(cleanup);
|
||||
// Module cleanup should be unregistered only if it's unoaded
|
||||
// and only if it's unoaded not by PluginManager, but by OS.
|
||||
// That means that task is closing unexpectedly - sooner of all
|
||||
// exit() is called by client of embedded server. Shutdown ourself.
|
||||
fb_shutdown(5000, fb_shutrsn_exit_called);
|
||||
}
|
||||
|
||||
IPluginSet* FB_CARG PluginManager::getPlugins(unsigned int interfaceType, const char* namesList,
|
||||
@ -934,9 +986,4 @@ void PluginManager::waitForType(unsigned int typeThatMustGoAway)
|
||||
}
|
||||
}
|
||||
|
||||
void FB_CARG PluginManager::moduleUnloaded()
|
||||
{
|
||||
fb_shutdown(5000, fb_shutrsn_exit_called);
|
||||
}
|
||||
|
||||
} // namespace Firebird
|
||||
|
@ -51,7 +51,6 @@ public:
|
||||
void FB_CARG releasePlugin(IPluginBase* plugin);
|
||||
void FB_CARG registerModule(IPluginModule* cleanup);
|
||||
void FB_CARG unregisterModule(IPluginModule* cleanup);
|
||||
void FB_CARG moduleUnloaded();
|
||||
|
||||
PluginManager();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user