cpu: Fix broken thread context handover
authorAndreas Sandberg <Andreas.Sandberg@ARM.com>
Mon, 7 Jan 2013 18:05:46 +0000 (13:05 -0500)
committerAndreas Sandberg <Andreas.Sandberg@ARM.com>
Mon, 7 Jan 2013 18:05:46 +0000 (13:05 -0500)
The thread context handover code used to break when multiple handovers
were performed during the same quiesce period. Previously, the thread
contexts would assign the TC pointer in the old quiesce event to the
new TC. This obviously broke in cases where multiple switches were
performed within the same quiesce period, in which case the TC pointer
in the quiesce event would point to an old CPU.

The new implementation deschedules pending quiesce events in the old
TC and schedules a new quiesce event in the new TC. The code has been
refactored to remove most of the code duplication.

src/cpu/inorder/thread_context.cc
src/cpu/o3/thread_context_impl.hh
src/cpu/simple_thread.cc
src/cpu/simple_thread.hh
src/cpu/thread_context.cc
src/cpu/thread_context.hh

index 2990430e1e36a18bd97379311cbdeabc93f1d703..aab8c226ae9aa166a625afd5114691a3c240639c 100644 (file)
@@ -93,18 +93,10 @@ InOrderThreadContext::profileSample()
 void
 InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
 {
-    // some things should already be set up
-    assert(getSystemPtr() == old_context->getSystemPtr());
-    assert(getProcessPtr() == old_context->getProcessPtr());
-
-    // copy over functional state
-    setStatus(old_context->status());
-    copyArchRegs(old_context);
+    ::takeOverFrom(*this, *old_context);
 
     thread->funcExeInst = old_context->readFuncExeInst();
 
-    old_context->setStatus(ThreadContext::Halted);
-
     thread->noSquashFromTC = false;
     thread->trapPending = false;
 }
index 0a8dfeb3e5e0652a9f9a702d7458a5c01966588c..6de5c573178c6c53674d0ade0b922fe5250d8ba6 100755 (executable)
@@ -66,34 +66,10 @@ template <class Impl>
 void
 O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
 {
-    // some things should already be set up
-    assert(getSystemPtr() == old_context->getSystemPtr());
-    assert(getProcessPtr() == old_context->getProcessPtr());
+    ::takeOverFrom(*this, *old_context);
 
-    // copy over functional state
-    setStatus(old_context->status());
-    copyArchRegs(old_context);
-    setContextId(old_context->contextId());
-    setThreadId(old_context->threadId());
-
-    if (FullSystem) {
-        EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
-        if (other_quiesce) {
-            // Point the quiesce event's TC at this TC so that it wakes up
-            // the proper CPU.
-            other_quiesce->tc = this;
-        }
-        if (thread->quiesceEvent) {
-            thread->quiesceEvent->tc = this;
-        }
-
-        // Transfer kernel stats from one CPU to the other.
-        thread->kernelStats = old_context->getKernelStats();
-    } else {
-        thread->funcExeInst = old_context->readFuncExeInst();
-    }
-
-    old_context->setStatus(ThreadContext::Halted);
+    thread->kernelStats = old_context->getKernelStats();
+    thread->funcExeInst = old_context->readFuncExeInst();
 
     thread->noSquashFromTC = false;
     thread->trapPending = false;
index 7876802244b7b29287ca6a5a21fb7ea31bc91390..9cf8da7b4c28b1a7074f69c00e8efb9bc80a87ce 100644 (file)
@@ -107,49 +107,11 @@ SimpleThread::~SimpleThread()
 void
 SimpleThread::takeOverFrom(ThreadContext *oldContext)
 {
-    // some things should already be set up
-    if (FullSystem)
-        assert(system == oldContext->getSystemPtr());
-    assert(process == oldContext->getProcessPtr());
-
-    copyState(oldContext);
-    if (FullSystem) {
-        EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
-        if (quiesce) {
-            // Point the quiesce event's TC at this TC so that it wakes up
-            // the proper CPU.
-            quiesce->tc = tc;
-        }
-        if (quiesceEvent) {
-            quiesceEvent->tc = tc;
-        }
-
-        TheISA::Kernel::Statistics *stats = oldContext->getKernelStats();
-        if (stats) {
-            kernelStats = stats;
-        }
-    }
+    ::takeOverFrom(*tc, *oldContext);
 
+    kernelStats = oldContext->getKernelStats();
+    funcExeInst = oldContext->readFuncExeInst();
     storeCondFailures = 0;
-
-    oldContext->setStatus(ThreadContext::Halted);
-}
-
-void
-SimpleThread::copyTC(ThreadContext *context)
-{
-    copyState(context);
-
-    if (FullSystem) {
-        EndQuiesceEvent *quiesce = context->getQuiesceEvent();
-        if (quiesce) {
-            quiesceEvent = quiesce;
-        }
-        TheISA::Kernel::Statistics *stats = context->getKernelStats();
-        if (stats) {
-            kernelStats = stats;
-        }
-    }
 }
 
 void
index ee54850aea07517bbf7e7b84f8e856161123136b..6f1173b7ff7fe4a4db141c8277f8e7e6e4b30303 100644 (file)
@@ -146,8 +146,6 @@ class SimpleThread : public ThreadState
 
     void regStats(const std::string &name);
 
-    void copyTC(ThreadContext *context);
-
     void copyState(ThreadContext *oldContext);
 
     void serialize(std::ostream &os);
index 4a4038297729ffa4de2f7044976d7e683b6771a6..a5a05a2648501dd6efb61a6e8d1cb5d5d23dc0e9 100644 (file)
 #include "base/misc.hh"
 #include "base/trace.hh"
 #include "config/the_isa.hh"
+#include "cpu/base.hh"
+#include "cpu/quiesce_event.hh"
 #include "cpu/thread_context.hh"
 #include "debug/Context.hh"
+#include "sim/full_system.hh"
 
 void
 ThreadContext::compare(ThreadContext *one, ThreadContext *two)
@@ -136,3 +139,37 @@ unserialize(ThreadContext &tc, Checkpoint *cp, const std::string &section)
 
     // thread_num and cpu_id are deterministic from the config
 }
+
+void
+takeOverFrom(ThreadContext &ntc, ThreadContext &otc)
+{
+    assert(ntc.getProcessPtr() == otc.getProcessPtr());
+
+    ntc.setStatus(otc.status());
+    ntc.copyArchRegs(&otc);
+    ntc.setContextId(otc.contextId());
+    ntc.setThreadId(otc.threadId());
+
+    if (FullSystem) {
+        assert(ntc.getSystemPtr() == otc.getSystemPtr());
+
+        BaseCPU *ncpu(ntc.getCpuPtr());
+        assert(ncpu);
+        EndQuiesceEvent *oqe(otc.getQuiesceEvent());
+        assert(oqe);
+        assert(oqe->tc == &otc);
+
+        BaseCPU *ocpu(otc.getCpuPtr());
+        assert(ocpu);
+        EndQuiesceEvent *nqe(ntc.getQuiesceEvent());
+        assert(nqe);
+        assert(nqe->tc == &ntc);
+
+        if (oqe->scheduled()) {
+            ncpu->schedule(nqe, oqe->when());
+            ocpu->deschedule(oqe);
+        }
+    }
+
+    otc.setStatus(ThreadContext::Halted);
+}
index c54076c8a77bae9e985911d14d03da0a08d9bc92..dbe3c0ce83e2bb3f9449b257d789e79f5bf0179c 100644 (file)
@@ -481,4 +481,17 @@ void unserialize(ThreadContext &tc, Checkpoint *cp, const std::string &section);
 
 /** @} */
 
+
+/**
+ * Copy state between thread contexts in preparation for CPU handover.
+ *
+ * @note This method modifies the old thread contexts as well as the
+ * new thread context. The old thread context will have its quiesce
+ * event descheduled if it is scheduled and its status set to halted.
+ *
+ * @param new_tc Destination ThreadContext.
+ * @param old_tc Source ThreadContext.
+ */
+void takeOverFrom(ThreadContext &new_tc, ThreadContext &old_tc);
+
 #endif