summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Sandberg <Andreas.Sandberg@ARM.com>2013-01-07 13:05:46 -0500
committerAndreas Sandberg <Andreas.Sandberg@ARM.com>2013-01-07 13:05:46 -0500
commit52ff37caa3dc434baa0468f13ac609430f078982 (patch)
treec5d1ff3172fa4ba3069741d1110aa043bafa1b91
parentfca4fea769c09add919099e5ede694145c5c5f77 (diff)
downloadgem5-52ff37caa3dc434baa0468f13ac609430f078982.tar.xz
cpu: Fix broken thread context handover
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.
-rw-r--r--src/cpu/inorder/thread_context.cc10
-rwxr-xr-xsrc/cpu/o3/thread_context_impl.hh30
-rw-r--r--src/cpu/simple_thread.cc44
-rw-r--r--src/cpu/simple_thread.hh2
-rw-r--r--src/cpu/thread_context.cc37
-rw-r--r--src/cpu/thread_context.hh13
6 files changed, 57 insertions, 79 deletions
diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc
index 2990430e1..aab8c226a 100644
--- a/src/cpu/inorder/thread_context.cc
+++ b/src/cpu/inorder/thread_context.cc
@@ -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;
}
diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh
index 0a8dfeb3e..6de5c5731 100755
--- a/src/cpu/o3/thread_context_impl.hh
+++ b/src/cpu/o3/thread_context_impl.hh
@@ -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;
diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc
index 787680224..9cf8da7b4 100644
--- a/src/cpu/simple_thread.cc
+++ b/src/cpu/simple_thread.cc
@@ -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
diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh
index ee54850ae..6f1173b7f 100644
--- a/src/cpu/simple_thread.hh
+++ b/src/cpu/simple_thread.hh
@@ -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);
diff --git a/src/cpu/thread_context.cc b/src/cpu/thread_context.cc
index 4a4038297..a5a05a264 100644
--- a/src/cpu/thread_context.cc
+++ b/src/cpu/thread_context.cc
@@ -43,8 +43,11 @@
#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);
+}
diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh
index c54076c8a..dbe3c0ce8 100644
--- a/src/cpu/thread_context.hh
+++ b/src/cpu/thread_context.hh
@@ -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