8
0
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:
alexpeshkoff 2011-04-29 16:24:27 +00:00
parent b77154b2b5
commit c076b1d8c1
6 changed files with 88 additions and 25 deletions

View File

@ -211,7 +211,6 @@ public:
{
PluginManagerInterfacePtr pi;
pi->unregisterModule(this);
pi->moduleUnloaded();
flagOsUnload = false;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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();