summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2006-12-10 22:17:51 +0000
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2006-12-10 22:17:51 +0000
commit540fee57bf71abccaba38c0297b80f8001780c1d (patch)
tree0a02c41f92100925e5f6a3db709372322389517e
parent5c0c0ec057e1f1bc9dd837c1654927b5b534e5c0 (diff)
Add InspIRCd::UseInterface and InspIRCd::DoneWithInterface, and also InspIRCd::GetInterfaceUseCount().
These can be used for one module to lock other modules in memory that it depends on, this way they can enforce an unload order so that you cant (for example) unload m_ssl_gnutls.so whilst m_spanningtree.so is using it for ssl server to server sessions (in this case, youd have to unload spanningtree first, THEN ssl_gnutls, to satisfy the dependencies and unload orders) git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@5924 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r--include/inspircd.h25
-rw-r--r--include/modules.h2
-rw-r--r--src/inspircd.cpp11
-rw-r--r--src/modules.cpp42
-rw-r--r--src/modules/m_cloaking.cpp5
-rw-r--r--src/modules/m_oper_hash.cpp3
-rw-r--r--src/modules/m_spanningtree.cpp4
7 files changed, 84 insertions, 8 deletions
diff --git a/include/inspircd.h b/include/inspircd.h
index 74678b206..8cce5513a 100644
--- a/include/inspircd.h
+++ b/include/inspircd.h
@@ -727,6 +727,31 @@ class InspIRCd : public classbase
*/
bool PublishInterface(const std::string &InterfaceName, Module* Mod);
+ /** Return a pair saying how many other modules are currently using the
+ * interfaces provided by module m.
+ * @param m The module to count usage for
+ * @return A pair, where the first value is the number of uses of the interface,
+ * and the second value is the interface name being used.
+ */
+ std::pair<int,std::string> GetInterfaceInstanceCount(Module* m);
+
+ /** Mark your module as using an interface.
+ * If you mark your module as using an interface, then that interface
+ * module may not unload until your module has unloaded first.
+ * This can be used to prevent crashes by ensuring code you depend on
+ * is always in memory while your module is active.
+ * @param InterfaceName The interface to use
+ */
+ void UseInterface(const std::string &InterfaceName);
+
+ /** Mark your module as finished with an interface.
+ * If you used UseInterface() above, you should use this method when
+ * your module is finished with the interface (usually in its destructor)
+ * to allow the modules which implement the given interface to be unloaded.
+ * @param InterfaceName The interface you are finished with using.
+ */
+ void DoneWithInterface(const std::string &InterfaceName);
+
/** Unpublish a 'feature'.
* When your module exits, it must call this method for every feature it
* is providing so that the feature table is cleaned up.
diff --git a/include/modules.h b/include/modules.h
index 9ace806b7..df8c03e3b 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -107,7 +107,7 @@ typedef std::deque<Module*> modulelist;
/** Holds a list of all modules which implement interfaces, by interface name
*/
-typedef std::map<std::string, modulelist> interfacelist;
+typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
/**
* This #define allows us to call a method in all
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 12134f3f6..e7801f1d5 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -505,6 +505,17 @@ bool InspIRCd::UnloadModule(const char* filename)
snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)");
return false;
}
+ std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modules[j]);
+ if (intercount.first > 0)
+ {
+ this->Log(DEFAULT,"Failed to unload module %s, being used by %d other(s) via interface '%s'",filename, intercount.first, intercount.second.c_str());
+ snprintf(MODERR,MAXBUF,"Module not unloadable (Still in use by %d other module%s which %s using its interface '%s') -- unload dependent modules first!",
+ intercount.first,
+ intercount.first > 1 ? "s" : "",
+ intercount.first > 1 ? "are" : "is",
+ intercount.second.c_str());
+ return false;
+ }
/* Give the module a chance to tidy out all its metadata */
for (chan_hash::iterator c = this->chanlist.begin(); c != this->chanlist.end(); c++)
{
diff --git a/src/modules.cpp b/src/modules.cpp
index 4ae033c8b..b670291ec 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -258,12 +258,12 @@ bool InspIRCd::PublishInterface(const std::string &InterfaceName, Module* Mod)
{
modulelist ml;
ml.push_back(Mod);
- Interfaces[InterfaceName] = ml;
+ Interfaces[InterfaceName] = std::make_pair(0, ml);
return true;
}
else
{
- iter->second.push_back(Mod);
+ iter->second.second.push_back(Mod);
return true;
}
return false;
@@ -276,12 +276,12 @@ bool InspIRCd::UnpublishInterface(const std::string &InterfaceName, Module* Mod)
if (iter == Interfaces.end())
return false;
- for (modulelist::iterator x = iter->second.begin(); x != iter->second.end(); x++)
+ for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
{
if (*x == Mod)
{
- iter->second.erase(x);
- if (iter->second.empty())
+ iter->second.second.erase(x);
+ if (iter->second.second.empty())
Interfaces.erase(InterfaceName);
return true;
}
@@ -295,7 +295,37 @@ modulelist* InspIRCd::FindInterface(const std::string &InterfaceName)
if (iter == Interfaces.end())
return NULL;
else
- return &(iter->second);
+ return &(iter->second.second);
+}
+
+void InspIRCd::UseInterface(const std::string &InterfaceName)
+{
+ interfacelist::iterator iter = Interfaces.find(InterfaceName);
+ if (iter != Interfaces.end())
+ iter->second.first++;
+
+}
+
+void InspIRCd::DoneWithInterface(const std::string &InterfaceName)
+{
+ interfacelist::iterator iter = Interfaces.find(InterfaceName);
+ if (iter != Interfaces.end())
+ iter->second.first--;
+}
+
+std::pair<int,std::string> InspIRCd::GetInterfaceInstanceCount(Module* m)
+{
+ for (interfacelist::iterator iter = Interfaces.begin(); iter != Interfaces.end(); iter++)
+ {
+ for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
+ {
+ if (*x == m)
+ {
+ return std::make_pair(iter->second.first, iter->first);
+ }
+ }
+ }
+ return std::make_pair(0, "");
}
const std::string& InspIRCd::GetModuleName(Module* m)
diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp
index ffa189007..a32f7348d 100644
--- a/src/modules/m_cloaking.cpp
+++ b/src/modules/m_cloaking.cpp
@@ -230,7 +230,9 @@ class ModuleCloaking : public Module
ModuleCloaking(InspIRCd* Me)
: Module::Module(Me)
{
- /* Attempt to locate the Hash service provider, bail if we can't find it */
+ ServerInstance->UseInterface("HashRequest");
+
+ /* Attempt to locate the md5 service provider, bail if we can't find it */
HashModule = ServerInstance->FindModule("m_md5.so");
if (!HashModule)
throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
@@ -248,6 +250,7 @@ class ModuleCloaking : public Module
{
ServerInstance->Modes->DelMode(cu);
DELETE(cu);
+ ServerInstance->DoneWithInterface("HashRequest");
}
virtual Version GetVersion()
diff --git a/src/modules/m_oper_hash.cpp b/src/modules/m_oper_hash.cpp
index b9e246c2b..61a43b1e1 100644
--- a/src/modules/m_oper_hash.cpp
+++ b/src/modules/m_oper_hash.cpp
@@ -91,6 +91,8 @@ class ModuleOperHash : public Module
Conf = NULL;
OnRehash("");
+ ServerInstance->UseInterface("HashRequest");
+
/* Find all modules which implement the interface 'HashRequest' */
modulelist* ml = ServerInstance->FindInterface("HashRequest");
@@ -121,6 +123,7 @@ class ModuleOperHash : public Module
virtual ~ModuleOperHash()
{
+ ServerInstance->DoneWithInterface("HashRequest");
}
void Implements(char* List)
diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp
index c0d2d7428..ef7e17820 100644
--- a/src/modules/m_spanningtree.cpp
+++ b/src/modules/m_spanningtree.cpp
@@ -4188,6 +4188,8 @@ class ModuleSpanningTree : public Module
ModuleSpanningTree(InspIRCd* Me)
: Module::Module(Me), max_local(0), max_global(0)
{
+ ServerInstance->UseInterface("InspSocketHook");
+
Utils = new SpanningTreeUtilities(Me, this);
command_rconnect = new cmd_rconnect(ServerInstance, this, Utils);
@@ -5402,6 +5404,8 @@ class ModuleSpanningTree : public Module
delete Utils;
if (SyncTimer)
ServerInstance->Timers->DelTimer(SyncTimer);
+
+ ServerInstance->DoneWithInterface("InspSocketHook");
}
virtual Version GetVersion()