diff options
author | Avi Kivity <avi@qumranet.com> | 2007-07-15 15:08:23 +0300 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-19 15:18:57 +0300 |
commit | f186f01d8f7b21d1e98a81d0c5ca6f6d18d2d46d (patch) | |
tree | 8e99defb6be3d46b5d6161dd3ac94c06e9bc6f97 | |
parent | 82ddea8dee3d6290ac7dc771e0dbc60af7bddfd5 (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.c | 52 |
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) { |