summaryrefslogtreecommitdiff
path: root/src/cpu/kvm/base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/kvm/base.cc')
-rw-r--r--src/cpu/kvm/base.cc62
1 files changed, 44 insertions, 18 deletions
diff --git a/src/cpu/kvm/base.cc b/src/cpu/kvm/base.cc
index d25e145a5..64c1a5e81 100644
--- a/src/cpu/kvm/base.cc
+++ b/src/cpu/kvm/base.cc
@@ -63,7 +63,7 @@
/* Used by some KVM macros */
#define PAGE_SIZE pageSize
-volatile bool timerOverflowed = false;
+static volatile __thread bool timerOverflowed = false;
BaseKvmCPU::BaseKvmCPU(BaseKvmCPUParams *params)
: BaseCPU(params),
@@ -92,18 +92,6 @@ BaseKvmCPU::BaseKvmCPU(BaseKvmCPUParams *params)
thread->setStatus(ThreadContext::Halted);
tc = thread->getTC();
threadContexts.push_back(tc);
-
- setupCounters();
-
- if (params->usePerfOverflow)
- runTimer.reset(new PerfKvmTimer(hwCycles,
- KVM_TIMER_SIGNAL,
- params->hostFactor,
- params->hostFreq));
- else
- runTimer.reset(new PosixKvmTimer(KVM_TIMER_SIGNAL, CLOCK_MONOTONIC,
- params->hostFactor,
- params->hostFreq));
}
BaseKvmCPU::~BaseKvmCPU()
@@ -177,6 +165,35 @@ BaseKvmCPU::startup()
}
thread->startup();
+
+ Event *startupEvent(
+ new EventWrapper<BaseKvmCPU,
+ &BaseKvmCPU::startupThread>(this, true));
+ schedule(startupEvent, curTick());
+}
+
+void
+BaseKvmCPU::startupThread()
+{
+ // Do thread-specific initialization. We need to setup signal
+ // delivery for counters and timers from within the thread that
+ // will execute the event queue to ensure that signals are
+ // delivered to the right threads.
+ const BaseKvmCPUParams * const p(
+ dynamic_cast<const BaseKvmCPUParams *>(params()));
+
+ setupCounters();
+
+ if (p->usePerfOverflow)
+ runTimer.reset(new PerfKvmTimer(hwCycles,
+ KVM_TIMER_SIGNAL,
+ p->hostFactor,
+ p->hostFreq));
+ else
+ runTimer.reset(new PosixKvmTimer(KVM_TIMER_SIGNAL, CLOCK_MONOTONIC,
+ p->hostFactor,
+ p->hostFreq));
+
}
void
@@ -1044,6 +1061,13 @@ BaseKvmCPU::flushCoalescedMMIO()
/**
* Cycle timer overflow when running in KVM. Forces the KVM syscall to
* exit with EINTR and allows us to run the event queue.
+ *
+ * @warn This function might not be called since some kernels don't
+ * seem to deliver signals when the signal is only unmasked when
+ * running in KVM. This doesn't matter though since we are only
+ * interested in getting KVM to exit, which happens as expected. See
+ * setupSignalHandler() and kvmRun() for details about KVM signal
+ * handling.
*/
static void
onTimerOverflow(int signo, siginfo_t *si, void *data)
@@ -1079,20 +1103,22 @@ BaseKvmCPU::setupSignalHandler()
panic("KVM: Failed to setup vCPU instruction signal handler\n");
sigset_t sigset;
- if (sigprocmask(SIG_BLOCK, NULL, &sigset) == -1)
+ if (pthread_sigmask(SIG_BLOCK, NULL, &sigset) == -1)
panic("KVM: Failed get signal mask\n");
// Request KVM to setup the same signal mask as we're currently
- // running with. We'll sometimes need to mask the KVM_TIMER_SIGNAL
- // to cause immediate exits from KVM after servicing IO
- // requests. See kvmRun().
+ // running with except for the KVM control signals. We'll
+ // sometimes need to raise the KVM_TIMER_SIGNAL to cause immediate
+ // exits from KVM after servicing IO requests. See kvmRun().
+ sigdelset(&sigset, KVM_TIMER_SIGNAL);
+ sigdelset(&sigset, KVM_INST_SIGNAL);
setSignalMask(&sigset);
// Mask our control signals so they aren't delivered unless we're
// actually executing inside KVM.
sigaddset(&sigset, KVM_TIMER_SIGNAL);
sigaddset(&sigset, KVM_INST_SIGNAL);
- if (sigprocmask(SIG_SETMASK, &sigset, NULL) == -1)
+ if (pthread_sigmask(SIG_SETMASK, &sigset, NULL) == -1)
panic("KVM: Failed mask the KVM control signals\n");
}