summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2010-02-24 16:01:21 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2010-02-24 16:01:21 -0300
commit9e49066b3dd6b659fc04eb4375e016dcb9492dce (patch)
tree279e4179ea95e1bfd3765c370699fe2120c1985a
parent6249f61a891b6b003531ca4e459c3a553faa82bc (diff)
parentcc84de9570ffe01a9c3c169bd62ab9586a9a080c (diff)
Merge commit 'cc84de9570ffe01a9c3c169bd62ab9586a9a080c' into upstream-merge
* commit 'cc84de9570ffe01a9c3c169bd62ab9586a9a080c': kvm: consume internal signal with sigtimedwait kvm specific wait_io_event block SIGCHLD in vcpu thread(s) kvm: Kill CR3_CACHE feature references kvm: Fix eflags corruption in kvm mode Conflicts: kvm-all.c Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--cpu-exec.c12
-rw-r--r--kvm-all.c20
-rw-r--r--kvm.h1
-rw-r--r--qemu-kvm.c17
-rw-r--r--qemu-kvm.h15
-rw-r--r--vl.c114
6 files changed, 125 insertions, 54 deletions
diff --git a/cpu-exec.c b/cpu-exec.c
index 3da7730b3..fe1176ddb 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -234,11 +234,13 @@ int cpu_exec(CPUState *env1)
env = env1;
#if defined(TARGET_I386)
- /* put eflags in CPU temporary format */
- CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
- DF = 1 - (2 * ((env->eflags >> 10) & 1));
- CC_OP = CC_OP_EFLAGS;
- env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ if (!kvm_enabled()) {
+ /* put eflags in CPU temporary format */
+ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((env->eflags >> 10) & 1));
+ CC_OP = CC_OP_EFLAGS;
+ env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ }
#elif defined(TARGET_SPARC)
#elif defined(TARGET_M68K)
env->cc_op = CC_OP_FLAGS;
diff --git a/kvm-all.c b/kvm-all.c
index bed562fb6..d1542e3d3 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -789,6 +789,7 @@ int kvm_cpu_exec(CPUState *env)
kvm_arch_post_run(env, run);
if (ret == -EINTR || ret == -EAGAIN) {
+ cpu_exit(env);
dprintf("io window exit\n");
ret = 0;
break;
@@ -1137,5 +1138,24 @@ void kvm_remove_all_breakpoints(CPUState *current_env)
}
#endif /* !KVM_CAP_SET_GUEST_DEBUG */
+int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
+{
+ struct kvm_signal_mask *sigmask;
+ int r;
+
+ if (!sigset)
+ return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
+
+ sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset));
+
+ sigmask->len = 8;
+ memcpy(sigmask->sigset, sigset, sizeof(*sigset));
+ r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask);
+ free(sigmask);
+
+ return r;
+}
+
#undef PAGE_SIZE
#include "qemu-kvm.c"
+
diff --git a/kvm.h b/kvm.h
index a78a27fb5..1b498d7c4 100644
--- a/kvm.h
+++ b/kvm.h
@@ -60,6 +60,7 @@ int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
target_ulong len, int type);
void kvm_remove_all_breakpoints(CPUState *current_env);
int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap);
+int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset);
int kvm_pit_in_kernel(void);
int kvm_irqchip_in_kernel(void);
diff --git a/qemu-kvm.c b/qemu-kvm.c
index 979038925..29365a9cf 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -1026,23 +1026,6 @@ int kvm_inject_irq(CPUState *env, unsigned irq)
return kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr);
}
-int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
-{
- struct kvm_signal_mask *sigmask;
- int r;
-
- if (!sigset) {
- return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
- }
- sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset));
-
- sigmask->len = 8;
- memcpy(sigmask->sigset, sigset, sizeof(*sigset));
- r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask);
- free(sigmask);
- return r;
-}
-
int kvm_inject_nmi(CPUState *env)
{
#ifdef KVM_CAP_USER_NMI
diff --git a/qemu-kvm.h b/qemu-kvm.h
index 93b144ff7..ecb52c1f6 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -373,21 +373,6 @@ int kvm_get_shadow_pages(kvm_context_t kvm, unsigned int *nrshadow_pages);
#endif
/*!
- * \brief Set a vcpu's signal mask for guest mode
- *
- * A vcpu can have different signals blocked in guest mode and user mode.
- * This allows guest execution to be interrupted on a signal, without requiring
- * that the signal be delivered to a signal handler (the signal can be
- * dequeued using sigwait(2).
- *
- * \param kvm Pointer to the current kvm_context
- * \param vcpu Which virtual CPU should be initialized
- * \param sigset signal mask for guest mode
- * \return 0 on success, or -errno on error
- */
-int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset);
-
-/*!
* \brief Dump VCPU registers
*
* This dumps some of the information that KVM has about a virtual CPU, namely:
diff --git a/vl.c b/vl.c
index 665bb6150..9babbfb53 100644
--- a/vl.c
+++ b/vl.c
@@ -283,6 +283,12 @@ uint8_t qemu_uuid[16];
static QEMUBootSetHandler *boot_set_handler;
static void *boot_set_opaque;
+#ifdef SIGRTMIN
+#define SIG_IPI (SIGRTMIN+4)
+#else
+#define SIG_IPI SIGUSR1
+#endif
+
static int default_serial = 1;
static int default_parallel = 1;
static int default_virtcon = 1;
@@ -3388,9 +3394,11 @@ static QemuCond qemu_cpu_cond;
static QemuCond qemu_system_cond;
static QemuCond qemu_pause_cond;
-static void block_io_signals(void);
+static void tcg_block_io_signals(void);
+static void kvm_block_io_signals(CPUState *env);
static void unblock_io_signals(void);
static int tcg_has_work(void);
+static int cpu_has_work(CPUState *env);
static int qemu_init_main_loop(void)
{
@@ -3411,6 +3419,15 @@ static int qemu_init_main_loop(void)
return 0;
}
+static void qemu_wait_io_event_common(CPUState *env)
+{
+ if (env->stop) {
+ env->stop = 0;
+ env->stopped = 1;
+ qemu_cond_signal(&qemu_pause_cond);
+ }
+}
+
static void qemu_wait_io_event(CPUState *env)
{
while (!tcg_has_work())
@@ -3427,24 +3444,54 @@ static void qemu_wait_io_event(CPUState *env)
qemu_mutex_unlock(&qemu_fair_mutex);
qemu_mutex_lock(&qemu_global_mutex);
- if (env->stop) {
- env->stop = 0;
- env->stopped = 1;
- qemu_cond_signal(&qemu_pause_cond);
+ qemu_wait_io_event_common(env);
+}
+
+static void qemu_kvm_eat_signal(CPUState *env, int timeout)
+{
+ struct timespec ts;
+ int r, e;
+ siginfo_t siginfo;
+ sigset_t waitset;
+
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+
+ sigemptyset(&waitset);
+ sigaddset(&waitset, SIG_IPI);
+
+ qemu_mutex_unlock(&qemu_global_mutex);
+ r = sigtimedwait(&waitset, &siginfo, &ts);
+ e = errno;
+ qemu_mutex_lock(&qemu_global_mutex);
+
+ if (r == -1 && !(e == EAGAIN || e == EINTR)) {
+ fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+ exit(1);
}
}
+static void qemu_kvm_wait_io_event(CPUState *env)
+{
+ while (!cpu_has_work(env))
+ qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
+
+ qemu_kvm_eat_signal(env, 0);
+ qemu_wait_io_event_common(env);
+}
+
static int qemu_cpu_exec(CPUState *env);
static void *kvm_cpu_thread_fn(void *arg)
{
CPUState *env = arg;
- block_io_signals();
qemu_thread_self(env->thread);
if (kvm_enabled())
kvm_init_vcpu(env);
+ kvm_block_io_signals(env);
+
/* signal CPU creation */
qemu_mutex_lock(&qemu_global_mutex);
env->created = 1;
@@ -3457,7 +3504,7 @@ static void *kvm_cpu_thread_fn(void *arg)
while (1) {
if (cpu_can_run(env))
qemu_cpu_exec(env);
- qemu_wait_io_event(env);
+ qemu_kvm_wait_io_event(env);
}
return NULL;
@@ -3469,7 +3516,7 @@ static void *tcg_cpu_thread_fn(void *arg)
{
CPUState *env = arg;
- block_io_signals();
+ tcg_block_io_signals();
qemu_thread_self(env->thread);
/* signal CPU creation */
@@ -3495,7 +3542,7 @@ void qemu_cpu_kick(void *_env)
CPUState *env = _env;
qemu_cond_broadcast(env->halt_cond);
if (kvm_enabled())
- qemu_thread_signal(env->thread, SIGUSR1);
+ qemu_thread_signal(env->thread, SIG_IPI);
}
int qemu_cpu_self(void *_env)
@@ -3514,7 +3561,7 @@ static void cpu_signal(int sig)
cpu_exit(cpu_single_env);
}
-static void block_io_signals(void)
+static void tcg_block_io_signals(void)
{
sigset_t set;
struct sigaction sigact;
@@ -3523,15 +3570,48 @@ static void block_io_signals(void)
sigaddset(&set, SIGUSR2);
sigaddset(&set, SIGIO);
sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGCHLD);
pthread_sigmask(SIG_BLOCK, &set, NULL);
sigemptyset(&set);
- sigaddset(&set, SIGUSR1);
+ sigaddset(&set, SIG_IPI);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = cpu_signal;
- sigaction(SIGUSR1, &sigact, NULL);
+ sigaction(SIG_IPI, &sigact, NULL);
+}
+
+static void dummy_signal(int sig)
+{
+}
+
+static void kvm_block_io_signals(CPUState *env)
+{
+ int r;
+ sigset_t set;
+ struct sigaction sigact;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR2);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGCHLD);
+ sigaddset(&set, SIG_IPI);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ pthread_sigmask(SIG_BLOCK, NULL, &set);
+ sigdelset(&set, SIG_IPI);
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = dummy_signal;
+ sigaction(SIG_IPI, &sigact, NULL);
+
+ r = kvm_set_signal_mask(env, &set);
+ if (r) {
+ fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
+ exit(1);
+ }
}
static void unblock_io_signals(void)
@@ -3545,7 +3625,7 @@ static void unblock_io_signals(void)
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
sigemptyset(&set);
- sigaddset(&set, SIGUSR1);
+ sigaddset(&set, SIG_IPI);
pthread_sigmask(SIG_BLOCK, &set, NULL);
}
@@ -3554,7 +3634,7 @@ static void qemu_signal_lock(unsigned int msecs)
qemu_mutex_lock(&qemu_fair_mutex);
while (qemu_mutex_trylock(&qemu_global_mutex)) {
- qemu_thread_signal(tcg_cpu_thread, SIGUSR1);
+ qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
break;
}
@@ -3595,7 +3675,7 @@ static void pause_all_vcpus(void)
while (penv) {
penv->stop = 1;
- qemu_thread_signal(penv->thread, SIGUSR1);
+ qemu_thread_signal(penv->thread, SIG_IPI);
qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
}
@@ -3604,7 +3684,7 @@ static void pause_all_vcpus(void)
qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
penv = first_cpu;
while (penv) {
- qemu_thread_signal(penv->thread, SIGUSR1);
+ qemu_thread_signal(penv->thread, SIG_IPI);
penv = (CPUState *)penv->next_cpu;
}
}
@@ -3617,7 +3697,7 @@ static void resume_all_vcpus(void)
while (penv) {
penv->stop = 0;
penv->stopped = 0;
- qemu_thread_signal(penv->thread, SIGUSR1);
+ qemu_thread_signal(penv->thread, SIG_IPI);
qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
}