summaryrefslogtreecommitdiffstats
path: root/source/DeadlockDetect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/DeadlockDetect.cpp')
-rw-r--r--source/DeadlockDetect.cpp155
1 files changed, 155 insertions, 0 deletions
diff --git a/source/DeadlockDetect.cpp b/source/DeadlockDetect.cpp
new file mode 100644
index 000000000..960038f81
--- /dev/null
+++ b/source/DeadlockDetect.cpp
@@ -0,0 +1,155 @@
+
+// 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"
+
+
+
+
+
+/// Number of milliseconds per cycle
+const int CYCLE_MILLISECONDS = 500;
+
+/// When the number of cycles for the same world age hits this value, it is considered a deadlock
+const int NUM_CYCLES_LIMIT = 40; // 40 = twenty seconds
+
+
+
+
+
+cDeadlockDetect::cDeadlockDetect(void) :
+ super("DeadlockDetect")
+{
+}
+
+
+
+
+
+bool cDeadlockDetect::Start(void)
+{
+ // 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::Stop(void)
+{
+ m_EvtTerminate.Set();
+ super::Stop();
+}
+
+
+
+
+
+void cDeadlockDetect::Execute(void)
+{
+ // Loop until the event is signalled
+ while (m_EvtTerminate.Wait(CYCLE_MILLISECONDS) == cEvent::wrTimeout)
+ {
+ // 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);
+ } // 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())
+ {
+ ASSERT(!"Unknown world in cDeadlockDetect");
+ return;
+ }
+ if (itr->second.m_Age == a_Age)
+ {
+ itr->second.m_NumCyclesSame += 1;
+ if (itr->second.m_NumCyclesSame > NUM_CYCLES_LIMIT)
+ {
+ DeadlockDetected();
+ return;
+ }
+ }
+ else
+ {
+ itr->second.m_Age = a_Age;
+ itr->second.m_NumCyclesSame = 0;
+ }
+}
+
+
+
+
+
+void cDeadlockDetect::DeadlockDetected(void)
+{
+ ASSERT(!"Deadlock detected");
+
+ // TODO: Make a crashdump / coredump
+
+ // Crash the server intentionally:
+ *((int *)0) = 0;
+}
+
+
+
+