Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / frontend_service / module_manager.cpp
blob82c2e4d71c23700e3eafff6129505a7676fd5be7
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
24 #include "nel/misc/debug.h"
25 #include "nel/misc/hierarchical_timer.h"
27 #include "module_manager.h"
29 using namespace NLMISC;
30 using namespace std;
33 * Static variables
36 uint CModuleManager::_MaxModules = 0;
38 NLMISC::CMutex *CModuleManager::_ModMutexes = NULL;
40 vector<CModuleManager*> CModuleManager::_RegisteredManagers;
43 // Constructor
44 CModuleManager::CModuleManager(const char *name, bool independent)
46 _Independent = independent;
47 _Thread = NULL;
48 _StopThread = false;
49 _ThreadStopped = false;
51 _StackName = (name != NULL) ? string(name) : "<unnamed>";
53 _Id = (uint)_RegisteredManagers.size();
54 _Cycle = 0;
55 _CompleteCycle = false;
56 _RegisteredManagers.push_back(this);
59 // Destructor
60 CModuleManager::~CModuleManager()
62 if (_Thread != NULL)
64 nlwarning("FEMMAN: [%s] Execution is not finished yet. Brutal thread killing", _StackName.c_str());
65 _Thread->terminate();
66 delete _Thread;
74 void CModuleManager::init(uint maxModules)
76 nlassert(_MaxModules == 0);
77 nlassert(_ModMutexes == NULL);
79 _MaxModules = maxModules;
80 _ModMutexes = new CMutex[maxModules];
85 void CModuleManager::release()
87 _MaxModules = 0;
88 delete [] _ModMutexes;
89 _ModMutexes = NULL;
94 void CModuleManager::startAll()
96 // first reset cycle
97 resetCycle();
99 uint i;
101 // and start all managers at once
102 for (i=0; i<_RegisteredManagers.size(); ++i)
103 if (_RegisteredManagers[i]->_Independent)
104 _RegisteredManagers[i]->start();
107 void CModuleManager::stopAll(TTime timeout)
109 uint i;
111 // send soft stop
112 for (i=0; i<_RegisteredManagers.size(); ++i)
113 _RegisteredManagers[i]->stop(false, 0);
115 // wait for all managers to stop or timeout
116 TTime before = CTime::getLocalTime();
117 while (!allStopped() && CTime::getLocalTime()-before < timeout)
118 nlSleep(10);
120 // and hard stop
121 for (i=0; i<_RegisteredManagers.size(); ++i)
122 _RegisteredManagers[i]->stop(true, 0);
125 void CModuleManager::resetCycle()
127 uint i;
129 // reset all managers cycle counter
130 for (i=0; i<_RegisteredManagers.size(); ++i)
131 _RegisteredManagers[i]->_Cycle = 0;
134 bool CModuleManager::allReady()
136 uint i;
138 // checks if all managers are at the same cycle
139 for (i=0; i<_RegisteredManagers.size()-1; ++i)
140 if (_RegisteredManagers[i]->_Cycle != _RegisteredManagers[i+1]->_Cycle)
141 return false;
143 return true;
146 bool CModuleManager::allComplete()
148 uint i;
150 // checks if all managers have set the stop flag
151 for (i=0; i<_RegisteredManagers.size()-1; ++i)
152 if (_RegisteredManagers[i]->_CompleteCycle != _RegisteredManagers[i+1]->_CompleteCycle)
153 return false;
155 return true;
158 bool CModuleManager::allStopped()
160 uint i;
162 // checks if all managers have set the stop flag
163 for (i=0; i<_RegisteredManagers.size(); ++i)
164 if (!_RegisteredManagers[i]->_ThreadStopped)
165 return false;
167 return true;
170 void CModuleManager::resetManagers()
172 // clear all registered managers
173 _RegisteredManagers.clear();
180 void CModuleManager::addModule(uint id, TModuleExecCallback cb)
182 nlassert(id < _MaxModules);
183 nlassert(cb != NULL);
184 nldebug("FEMMAN: [%s] Added module %d (Cb=%p) to stack", _StackName.c_str(), id, (void *)cb);
186 _ExecutionStack.push_back(CExecutionItem());
188 _ExecutionStack.back().Type = Module;
189 _ExecutionStack.back().Id = id;
190 _ExecutionStack.back().Cb = cb;
192 _ExecutedModules.push_back(id);
197 void CModuleManager::addWait(uint id)
199 nlassert(id < _MaxModules);
200 nldebug("FEMMAN: [%s] Added wait %d to stack", _StackName.c_str(), id);
202 _ExecutionStack.push_back(CExecutionItem());
204 _ExecutionStack.back().Type = Wait;
205 _ExecutionStack.back().Id = id;
206 _ExecutionStack.back().Cb = NULL;
211 void CModuleManager::start()
213 _Thread = IThread::create(this);
215 _StopThread = false;
216 _ThreadStopped = false;
218 _Thread->start();
219 //nlinfo("FEMMAN: [%s] Start", _StackName.c_str());
224 void CModuleManager::runOnce()
226 _StopThread = false;
227 _ThreadStopped = false;
229 //nlinfo("FEMMAN: [%s] Running one time", _StackName.c_str());
231 // step cycle
232 stepCycle();
234 // wait for all managers to sync on the same cycle before entering mutexes
235 waitAllReady();
237 // lock mutexes
238 enterMutexes();
240 completeCycle();
242 // and wait for all managers to finish entering mutexes
243 waitAllComplete();
245 //H_BEFORE(MMExecuteStack);
246 executeStack();
247 //H_AFTER(MMExecuteStack);
249 _ThreadStopped = true;
254 void CModuleManager::stop(bool blockingMode, TTime timeout)
256 // non independent modules (called by main thread) are always stopped at this point, no need to force stop
257 if (!_Independent)
259 _ThreadStopped = true;
260 return;
264 if (!blockingMode)
266 // if soft stop, just send stop message and leave
267 nlinfo("FEMMAN: [%s] soft stop", _StackName.c_str());
268 _StopThread = true;
269 return;
272 if (!_StopThread)
274 // if not yet called stop, send message stop
275 nlinfo("FEMMAN: [%s] hard stop", _StackName.c_str());
276 _StopThread = true;
278 // wait for stop or timeout
279 TTime before = CTime::getLocalTime();
280 while (!_ThreadStopped && CTime::getLocalTime()-before < timeout)
281 nlSleep(10);
284 if ( _Thread )
286 // if timeout, terminate thread
287 if (!_ThreadStopped)
289 nlwarning("FEMMAN: [%s] Can't stop. Brutal thread killing", _StackName.c_str());
290 _Thread->terminate();
293 delete _Thread;
294 _Thread = NULL;
301 void CModuleManager::run()
303 nldebug("FEMMAN: [%s] attached thread loop start", _StackName.c_str());
305 while (true)
307 // step cycle
308 stepCycle();
310 // wait for all managers to sync on the same cycle before entering mutexes
311 waitAllReady();
313 // lock mutexes
314 enterMutexes();
316 completeCycle();
318 // and wait for all managers to finish entering mutexes
319 waitAllComplete();
321 //H_BEFORE(MMExecuteStack);
322 executeStack();
323 //H_AFTER(MMExecuteStack);
325 // if stop sent, just leave
326 if (_StopThread)
327 break;
330 nldebug("FEMMAN: [%s] attached thread loop end", _StackName.c_str());
332 _ThreadStopped = true;
337 void CModuleManager::executeStack()
339 // for each item,
340 // if a module,
341 // calls associated callback
342 // leaves mutex
343 // else
344 // enters mutex
345 // leaves mutex
347 //nldebug("FEMMAN: [%s] execute stack", _StackName.c_str());
349 uint i;
351 for (i=0; i<_ExecutionStack.size(); ++i)
353 CExecutionItem &item = _ExecutionStack[i];
355 if (item.Type == Module)
357 //nldebug("FEMMAN: [%s] execute module %d at %p", _StackName.c_str(), item.Id, item.Cb);
358 //H_BEFORE(MMCall);
359 item.Cb();
360 //H_AFTER(MMCall);
361 _ModMutexes[item.Id].leave();
363 else if (item.Type == Wait)
365 //nldebug("FEMMAN: [%s] wait for module %d to finish", _StackName.c_str(), item.Id);
366 //H_BEFORE(MMWait);
367 //TTime t = CTime::getLocalTime();
368 _ModMutexes[item.Id].enter();
369 //nlinfo( "Waited %u ms", (uint32)(CTime::getLocalTime()-t) );
370 _ModMutexes[item.Id].leave();
371 //H_AFTER(MMWait);
373 else
375 nlwarning("FEMMAN: Unexpected ExecutionItem type (%d) at item %d of the execution stack %s", item.Type, i, _StackName.c_str());
376 uint j;
377 for (j=0; j<_ExecutionStack.size(); ++j)
378 nlwarning("FEMMAN: > %d [%s] Id=%d Cb=%p", j, (item.Type == Module) ? "MOD" : (item.Type == Wait) ? "WAIT" : "ERR", item.Id, (void *)item.Cb);
379 nlerror("FEMMAN: Error in execution stack %s", _StackName.c_str());
383 //nldebug("FEMMAN: [%s] stack executed", _StackName.c_str());
386 void CModuleManager::enterMutexes()
388 // enters all controlled mutexes
390 //nldebug("FEMMAN: [%s] Entering all controlled mutexes", _StackName.c_str());
392 uint i;
394 for (i=0; i<_ExecutedModules.size(); ++i)
396 //nldebug("FEMMAN: [%s] Entering mutex %d", _StackName.c_str(), _ExecutedModules[i]);
397 //TTime t = CTime::getLocalTime();
398 _ModMutexes[_ExecutedModules[i]].enter();
399 //nlinfo( "Waited %u ms", (uint32)(CTime::getLocalTime()-t) );
401 //nldebug("FEMMAN: [%s] All controlled mutexes successfully entered", _StackName.c_str());