148 lines
2.4 KiB
C++
148 lines
2.4 KiB
C++
|
|
// DeadlockDetect.cpp
|
|
|
|
// Declares the cDeadlockDetect class that tries to detect deadlocks and aborts the server when it detects one
|
|
|
|
#include "Globals.h"
|
|
#include "DeadlockDetect.h"
|
|
#include "Root.h"
|
|
#include "World.h"
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
|
|
|
|
/** Number of milliseconds per cycle */
|
|
const int CYCLE_MILLISECONDS = 100;
|
|
|
|
|
|
|
|
|
|
|
|
cDeadlockDetect::cDeadlockDetect(void) :
|
|
super("DeadlockDetect"),
|
|
m_IntervalSec(1000)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool cDeadlockDetect::Start(int a_IntervalSec)
|
|
{
|
|
m_IntervalSec = a_IntervalSec;
|
|
|
|
// Read the initial world data:
|
|
class cFillIn :
|
|
public cWorldListCallback
|
|
{
|
|
public:
|
|
cFillIn(cDeadlockDetect * a_Detect) :
|
|
m_Detect(a_Detect)
|
|
{
|
|
}
|
|
|
|
virtual bool Item(cWorld * a_World) override
|
|
{
|
|
m_Detect->SetWorldAge(a_World->GetName(), a_World->GetWorldAge());
|
|
return false;
|
|
}
|
|
|
|
protected:
|
|
cDeadlockDetect * m_Detect;
|
|
} FillIn(this);
|
|
cRoot::Get()->ForEachWorld(FillIn);
|
|
return super::Start();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cDeadlockDetect::Execute(void)
|
|
{
|
|
// Loop until the signal to terminate:
|
|
while (!m_ShouldTerminate)
|
|
{
|
|
// Check the world ages:
|
|
class cChecker :
|
|
public cWorldListCallback
|
|
{
|
|
public:
|
|
cChecker(cDeadlockDetect * a_Detect) :
|
|
m_Detect(a_Detect)
|
|
{
|
|
}
|
|
|
|
protected:
|
|
cDeadlockDetect * m_Detect;
|
|
|
|
virtual bool Item(cWorld * a_World) override
|
|
{
|
|
m_Detect->CheckWorldAge(a_World->GetName(), a_World->GetWorldAge());
|
|
return false;
|
|
}
|
|
} Checker(this);
|
|
cRoot::Get()->ForEachWorld(Checker);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(CYCLE_MILLISECONDS));
|
|
} // while (should run)
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cDeadlockDetect::SetWorldAge(const AString & a_WorldName, Int64 a_Age)
|
|
{
|
|
m_WorldAges[a_WorldName].m_Age = a_Age;
|
|
m_WorldAges[a_WorldName].m_NumCyclesSame = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
|
|
{
|
|
WorldAges::iterator itr = m_WorldAges.find(a_WorldName);
|
|
if (itr == m_WorldAges.end())
|
|
{
|
|
SetWorldAge(a_WorldName, a_Age);
|
|
return;
|
|
}
|
|
|
|
cDeadlockDetect::sWorldAge & WorldAge = itr->second;
|
|
|
|
if (WorldAge.m_Age == a_Age)
|
|
{
|
|
WorldAge.m_NumCyclesSame += 1;
|
|
if (WorldAge.m_NumCyclesSame > (m_IntervalSec * 1000) / CYCLE_MILLISECONDS)
|
|
{
|
|
DeadlockDetected();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WorldAge.m_Age = a_Age;
|
|
WorldAge.m_NumCyclesSame = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void cDeadlockDetect::DeadlockDetected(void)
|
|
{
|
|
LOGERROR("Deadlock detected, aborting the server");
|
|
ASSERT(!"Deadlock detected");
|
|
abort();
|
|
}
|
|
|
|
|
|
|
|
|