aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-07-15 15:08:23 +0300
committerAvi Kivity <avi@qumranet.com>2007-07-19 15:18:57 +0300
commitf186f01d8f7b21d1e98a81d0c5ca6f6d18d2d46d (patch)
tree8e99defb6be3d46b5d6161dd3ac94c06e9bc6f97
parent82ddea8dee3d6290ac7dc771e0dbc60af7bddfd5 (diff)
Synchronous signal handling
in order to ensure that signals are handled with the global lock held, we block them, and dequeue them with sigtimedwait(). we can then call the handlers directly. this ensures that the device model and internal qemu data structures are not corrupted by cpu 0 thread handling a signal while cpu 1 is servicing a pio or mmio request.
-rw-r--r--qemu-kvm.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/qemu-kvm.c b/qemu-kvm.c
index 68881291e..89d168f57 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -32,6 +32,8 @@ extern int smp_cpus;
pthread_mutex_t qemu_mutex = PTHREAD_MUTEX_INITIALIZER;
static __thread CPUState *vcpu_env;
+static sigset_t io_sigset, io_negsigset;
+
static int wait_hack;
#define SIG_IPI (SIGRTMIN+4)
@@ -551,13 +553,44 @@ static int has_work(CPUState *env)
return 0;
}
+static void kvm_eat_signals(CPUState *env, int timeout)
+{
+ struct timespec ts;
+ int r, e;
+ siginfo_t siginfo;
+ struct sigaction sa;
+
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+ r = sigtimedwait(&io_sigset, &siginfo, &ts);
+ if (r == -1 && (errno == EAGAIN || errno == EINTR) && !timeout)
+ return;
+ e = errno;
+ pthread_mutex_lock(&qemu_mutex);
+ cpu_single_env = vcpu_env;
+ if (r == -1 && !(errno == EAGAIN || errno == EINTR)) {
+ printf("sigtimedwait: %s\n", strerror(e));
+ exit(1);
+ }
+ if (r != -1) {
+ sigaction(siginfo.si_signo, NULL, &sa);
+ sa.sa_handler(siginfo.si_signo);
+ }
+ /*
+ * we call select() even if no signal was received, to account for
+ * for which there is no signal handler installed.
+ */
+ main_loop_wait(0);
+ pthread_mutex_unlock(&qemu_mutex);
+}
+
static void kvm_main_loop_wait(CPUState *env, int timeout)
{
if (vcpu_info[env->cpu_index].signalled && timeout)
goto shortcut;
pthread_mutex_unlock(&qemu_mutex);
if (env->cpu_index == 0)
- main_loop_wait(timeout);
+ kvm_eat_signals(env, timeout);
else
if (timeout) {
sigset_t set;
@@ -597,6 +630,9 @@ static void setup_kernel_sigmask(CPUState *env)
sigprocmask(SIG_BLOCK, NULL, &set);
sigdelset(&set, SIG_IPI);
+ if (env->cpu_index == 0)
+ sigandset(&set, &set, &io_negsigset);
+
kvm_set_signal_mask(kvm_context, env->cpu_index, &set);
}
@@ -647,11 +683,25 @@ static void *ap_main_loop(void *_env)
return NULL;
}
+static void kvm_add_signal(int signum)
+{
+ sigaddset(&io_sigset, signum);
+ sigdelset(&io_negsigset, signum);
+ sigprocmask(SIG_BLOCK, &io_sigset, NULL);
+}
+
int kvm_main_loop(void)
{
CPUState *env = first_cpu->next_cpu;
int i;
+ sigemptyset(&io_sigset);
+ sigfillset(&io_negsigset);
+ kvm_add_signal(SIGIO);
+ kvm_add_signal(SIGALRM);
+ kvm_add_signal(SIGUSR2);
+ kvm_add_signal(SIG_IPI);
+
vcpu_env = first_cpu;
signal(SIG_IPI, sig_ipi_handler);
for (i = 1; i < smp_cpus; ++i) {