1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
24 #include "nel/misc/debug.h"
25 #include "nel/misc/hierarchical_timer.h"
27 #include "module_manager.h"
29 using namespace NLMISC
;
36 uint
CModuleManager::_MaxModules
= 0;
38 NLMISC::CMutex
*CModuleManager::_ModMutexes
= NULL
;
40 vector
<CModuleManager
*> CModuleManager::_RegisteredManagers
;
44 CModuleManager::CModuleManager(const char *name
, bool independent
)
46 _Independent
= independent
;
49 _ThreadStopped
= false;
51 _StackName
= (name
!= NULL
) ? string(name
) : "<unnamed>";
53 _Id
= (uint
)_RegisteredManagers
.size();
55 _CompleteCycle
= false;
56 _RegisteredManagers
.push_back(this);
60 CModuleManager::~CModuleManager()
64 nlwarning("FEMMAN: [%s] Execution is not finished yet. Brutal thread killing", _StackName
.c_str());
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()
88 delete [] _ModMutexes
;
94 void CModuleManager::startAll()
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
)
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
)
121 for (i
=0; i
<_RegisteredManagers
.size(); ++i
)
122 _RegisteredManagers
[i
]->stop(true, 0);
125 void CModuleManager::resetCycle()
129 // reset all managers cycle counter
130 for (i
=0; i
<_RegisteredManagers
.size(); ++i
)
131 _RegisteredManagers
[i
]->_Cycle
= 0;
134 bool CModuleManager::allReady()
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
)
146 bool CModuleManager::allComplete()
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
)
158 bool CModuleManager::allStopped()
162 // checks if all managers have set the stop flag
163 for (i
=0; i
<_RegisteredManagers
.size(); ++i
)
164 if (!_RegisteredManagers
[i
]->_ThreadStopped
)
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);
216 _ThreadStopped
= false;
219 //nlinfo("FEMMAN: [%s] Start", _StackName.c_str());
224 void CModuleManager::runOnce()
227 _ThreadStopped
= false;
229 //nlinfo("FEMMAN: [%s] Running one time", _StackName.c_str());
234 // wait for all managers to sync on the same cycle before entering mutexes
242 // and wait for all managers to finish entering mutexes
245 //H_BEFORE(MMExecuteStack);
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
259 _ThreadStopped
= true;
266 // if soft stop, just send stop message and leave
267 nlinfo("FEMMAN: [%s] soft stop", _StackName
.c_str());
274 // if not yet called stop, send message stop
275 nlinfo("FEMMAN: [%s] hard stop", _StackName
.c_str());
278 // wait for stop or timeout
279 TTime before
= CTime::getLocalTime();
280 while (!_ThreadStopped
&& CTime::getLocalTime()-before
< timeout
)
286 // if timeout, terminate thread
289 nlwarning("FEMMAN: [%s] Can't stop. Brutal thread killing", _StackName
.c_str());
290 _Thread
->terminate();
301 void CModuleManager::run()
303 nldebug("FEMMAN: [%s] attached thread loop start", _StackName
.c_str());
310 // wait for all managers to sync on the same cycle before entering mutexes
318 // and wait for all managers to finish entering mutexes
321 //H_BEFORE(MMExecuteStack);
323 //H_AFTER(MMExecuteStack);
325 // if stop sent, just leave
330 nldebug("FEMMAN: [%s] attached thread loop end", _StackName
.c_str());
332 _ThreadStopped
= true;
337 void CModuleManager::executeStack()
341 // calls associated callback
347 //nldebug("FEMMAN: [%s] execute stack", _StackName.c_str());
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);
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);
367 //TTime t = CTime::getLocalTime();
368 _ModMutexes
[item
.Id
].enter();
369 //nlinfo( "Waited %u ms", (uint32)(CTime::getLocalTime()-t) );
370 _ModMutexes
[item
.Id
].leave();
375 nlwarning("FEMMAN: Unexpected ExecutionItem type (%d) at item %d of the execution stack %s", item
.Type
, i
, _StackName
.c_str());
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());
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());