]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modmanager_static.cpp
Fix MySQL crash on module unload with empty query queue
[user/henk/code/inspircd.git] / src / modmanager_static.cpp
1 #define MODNAME AllModule
2
3 #include "inspircd.h"
4 #include "exitcodes.h"
5
6 #ifdef PURE_STATIC
7
8 typedef std::map<std::string, AllModuleList*> modmap;
9 static std::vector<AllCommandList::fn>* cmdlist = NULL;
10 static modmap* modlist = NULL;
11
12 AllCommandList::AllCommandList(fn cmd)
13 {
14         if (!cmdlist)
15                 cmdlist = new std::vector<AllCommandList::fn>();
16         cmdlist->push_back(cmd);
17 }
18
19 AllModuleList::AllModuleList(AllModuleList::fn mod, const std::string& Name) : init(mod), name(Name)
20 {
21         if (!modlist)
22                 modlist = new modmap();
23         modlist->insert(std::make_pair(Name, this));
24 }
25
26 class AllModule : public Module
27 {
28         std::vector<Command*> cmds;
29  public:
30         AllModule()
31         {
32                 if (!cmdlist)
33                         return;
34                 try
35                 {
36                         cmds.reserve(cmdlist->size());
37                         for(std::vector<AllCommandList::fn>::iterator i = cmdlist->begin(); i != cmdlist->end(); ++i)
38                         {
39                                 Command* c = (*i)(this);
40                                 cmds.push_back(c);
41                                 ServerInstance->AddCommand(c);
42                         }
43                 }
44                 catch (...)
45                 {
46                         this->AllModule::~AllModule();
47                         throw;
48                 }
49         }
50
51         ~AllModule()
52         {
53                 for(std::vector<Command*>::iterator i = cmds.begin(); i != cmds.end(); ++i)
54                         delete *i;
55         }
56
57         Version GetVersion()
58         {
59                 return Version("All commands", VF_VENDOR|VF_CORE);
60         }
61 };
62
63 MODULE_INIT(AllModule)
64
65 bool ModuleManager::Load(const std::string& name, bool defer)
66 {
67         modmap::iterator it = modlist->find(name);
68         if (it == modlist->end())
69                 return false;
70         Module* mod = NULL;
71         try
72         {
73                 mod = (*it->second->init)();
74                 mod->ModuleSourceFile = name;
75                 mod->ModuleDLLManager = NULL;
76                 Modules[name] = mod;
77                 if (defer)
78                 {
79                         ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s", name.c_str());
80                         return true;
81                 }
82                 else
83                 {
84                         mod->init();
85                 }
86         }
87         catch (CoreException& modexcept)
88         {
89                 if (mod)
90                         DoSafeUnload(mod);
91                 ServerInstance->Logs->Log("MODULE", DEFAULT, "Unable to load " + name + ": " + modexcept.GetReason());
92                 return false;
93         }
94         FOREACH_MOD(I_OnLoadModule,OnLoadModule(mod));
95         /* We give every module a chance to re-prioritize when we introduce a new one,
96          * not just the one thats loading, as the new module could affect the preference
97          * of others
98          */
99         for(int tries = 0; tries < 20; tries++)
100         {
101                 prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
102                 for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
103                         n->second->Prioritize();
104
105                 if (prioritizationState == PRIO_STATE_LAST)
106                         break;
107                 if (tries == 19)
108                         ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + name);
109         }
110
111         ServerInstance->BuildISupport();
112         return true;
113 }
114
115 namespace {
116         struct UnloadAction : public HandlerBase0<void>
117         {
118                 Module* const mod;
119                 UnloadAction(Module* m) : mod(m) {}
120                 void Call()
121                 {
122                         ServerInstance->Modules->DoSafeUnload(mod);
123                         ServerInstance->GlobalCulls.Apply();
124                         ServerInstance->GlobalCulls.AddItem(this);
125                 }
126         };
127
128         struct ReloadAction : public HandlerBase0<void>
129         {
130                 Module* const mod;
131                 HandlerBase1<void, bool>* const callback;
132                 ReloadAction(Module* m, HandlerBase1<void, bool>* c)
133                         : mod(m), callback(c) {}
134                 void Call()
135                 {
136                         std::string name = mod->ModuleSourceFile;
137                         ServerInstance->Modules->DoSafeUnload(mod);
138                         ServerInstance->GlobalCulls.Apply();
139                         bool rv = ServerInstance->Modules->Load(name.c_str());
140                         callback->Call(rv);
141                         ServerInstance->GlobalCulls.AddItem(this);
142                 }
143         };
144 }
145
146 bool ModuleManager::Unload(Module* mod)
147 {
148         if (!CanUnload(mod))
149                 return false;
150         ServerInstance->AtomicActions.AddAction(new UnloadAction(mod));
151         return true;
152 }
153
154 void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback)
155 {
156         if (CanUnload(mod))
157                 ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback));
158         else
159                 callback->Call(false);
160 }
161
162 void ModuleManager::LoadAll()
163 {
164         Load("AllModule", true);
165
166         ConfigTagList tags = ServerInstance->Config->ConfTags("module");
167         for(ConfigIter i = tags.first; i != tags.second; ++i)
168         {
169                 ConfigTag* tag = i->second;
170                 std::string name = tag->getString("name");
171                 printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",name.c_str());
172
173                 if (!this->Load(name, true))
174                 {
175                         ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError());
176                         printf_c("\n[\033[1;31m*\033[0m] %s\n\n", this->LastError().c_str());
177                         ServerInstance->Exit(EXIT_STATUS_MODULE);
178                 }
179         }
180
181         for(std::map<std::string, Module*>::iterator i = Modules.begin(); i != Modules.end(); i++)
182         {
183                 Module* mod = i->second;
184                 try 
185                 {
186                         mod->init();
187                 }
188                 catch (CoreException& modexcept)
189                 {
190                         LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason();
191                         ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
192                         printf_c("\n[\033[1;31m*\033[0m] %s\n\n", LastModuleError.c_str());
193                         ServerInstance->Exit(EXIT_STATUS_MODULE);
194                 }
195         }
196
197         /* We give every module a chance to re-prioritize when we introduce a new one,
198          * not just the one thats loading, as the new module could affect the preference
199          * of others
200          */
201         for(int tries = 0; tries < 20; tries++)
202         {
203                 prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
204                 for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
205                         n->second->Prioritize();
206
207                 if (prioritizationState == PRIO_STATE_LAST)
208                         break;
209                 if (tries == 19)
210                 {
211                         ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected");
212                         ServerInstance->Exit(EXIT_STATUS_MODULE);
213                 }
214         }
215 }
216
217 #endif