]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules.cpp
Fix MySQL crash on module unload with empty query queue
[user/henk/code/inspircd.git] / src / modules.cpp
index 9e5c84bfff3d8e32412b9db1773c21bcc27ac2f3..f2ce6d372221c5ba6500f71dc9fdf61fc9dd84cb 100644 (file)
        #include <dirent.h>
 #endif
 
+static std::vector<dynamic_reference_base*>* dynrefs = NULL;
+
+void dynamic_reference_base::reset_all()
+{
+       if (!dynrefs)
+               return;
+       for(unsigned int i = 0; i < dynrefs->size(); i++)
+               (*dynrefs)[i]->ClearCache();
+}
 
 // Version is a simple class for holding a modules version number
 template<>
@@ -162,7 +171,7 @@ void                Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) {
 ModResult      Module::OnNumeric(User*, unsigned int, const std::string&) { return MOD_RES_PASSTHRU; }
 void           Module::OnHookIO(StreamSocket*, ListenSocket*) { }
 ModResult   Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { return MOD_RES_PASSTHRU; }
-void           Module::OnSendWhoLine(User*, const std::vector<std::string>&, User*, Channel*, std::string&) { }
+void           Module::OnSendWhoLine(User*, const std::vector<std::string>&, User*, std::string&) { }
 
 ModuleManager::ModuleManager() : ModCount(0)
 {
@@ -368,8 +377,8 @@ void ModuleManager::DoSafeUnload(Module* mod)
                if (curr->second->creator == mod)
                        DataProviders.erase(curr);
        }
-       for(unsigned int i = 0; i < ServerInstance->Modules->ActiveDynrefs.size(); i++)
-               ServerInstance->Modules->ActiveDynrefs[i]->ClearCache();
+
+       dynamic_reference_base::reset_all();
 
        /* Tidy up any dangling resolvers */
        ServerInstance->Res->CleanResolvers(mod);
@@ -386,6 +395,29 @@ void ModuleManager::DoSafeUnload(Module* mod)
        ServerInstance->BuildISupport();
 }
 
+void ModuleManager::UnloadAll()
+{
+       /* We do this more than once, so that any service providers get a
+        * chance to be unhooked by the modules using them, but then get
+        * a chance to be removed themsleves.
+        *
+        * Note: this deliberately does NOT delete the DLLManager objects
+        */
+       for (int tries = 0; tries < 4; tries++)
+       {
+               std::map<std::string, Module*>::iterator i = Modules.begin();
+               while (i != Modules.end())
+               {
+                       std::map<std::string, Module*>::iterator me = i++;
+                       if (CanUnload(me->second))
+                       {
+                               DoSafeUnload(me->second);
+                       }
+               }
+               ServerInstance->GlobalCulls.Apply();
+       }
+}
+
 std::string& ModuleManager::LastError()
 {
        return LastModuleError;
@@ -454,8 +486,7 @@ void ModuleManager::DelService(ServiceProvider& item)
                                if (curr->second == &item)
                                        DataProviders.erase(curr);
                        }
-                       for(unsigned int i = 0; i < ServerInstance->Modules->ActiveDynrefs.size(); i++)
-                               ServerInstance->Modules->ActiveDynrefs[i]->ClearCache();
+                       dynamic_reference_base::reset_all();
                        return;
                }
                default:
@@ -484,19 +515,26 @@ ServiceProvider* ModuleManager::FindService(ServiceType type, const std::string&
 dynamic_reference_base::dynamic_reference_base(Module* Creator, const std::string& Name)
        : name(Name), value(NULL), creator(Creator)
 {
-       ServerInstance->Modules->ActiveDynrefs.push_back(this);
+       if (!dynrefs)
+               dynrefs = new std::vector<dynamic_reference_base*>;
+       dynrefs->push_back(this);
 }
 
 dynamic_reference_base::~dynamic_reference_base()
 {
-       for(unsigned int i = 0; i < ServerInstance->Modules->ActiveDynrefs.size(); i++)
+       for(unsigned int i = 0; i < dynrefs->size(); i++)
        {
-               if (ServerInstance->Modules->ActiveDynrefs[i] == this)
+               if (dynrefs->at(i) == this)
                {
-                       unsigned int last = ServerInstance->Modules->ActiveDynrefs.size() - 1;
+                       unsigned int last = dynrefs->size() - 1;
                        if (i != last)
-                               ServerInstance->Modules->ActiveDynrefs[i] = ServerInstance->Modules->ActiveDynrefs[last];
-                       ServerInstance->Modules->ActiveDynrefs.erase(ServerInstance->Modules->ActiveDynrefs.begin() + last);
+                               dynrefs->at(i) = dynrefs->at(last);
+                       dynrefs->erase(dynrefs->begin() + last);
+                       if (dynrefs->empty())
+                       {
+                               delete dynrefs;
+                               dynrefs = NULL;
+                       }
                        return;
                }
        }