aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpus.c74
1 files changed, 69 insertions, 5 deletions
diff --git a/cpus.c b/cpus.c
index b09f5e3b50..38756572d9 100644
--- a/cpus.c
+++ b/cpus.c
@@ -33,6 +33,7 @@
#include "exec-all.h"
#include "cpus.h"
+#include "compatfd.h"
#ifdef SIGRTMIN
#define SIG_IPI (SIGRTMIN+4)
@@ -329,14 +330,75 @@ static QemuCond qemu_work_cond;
static void tcg_init_ipi(void);
static void kvm_init_ipi(CPUState *env);
-static void unblock_io_signals(void);
+static sigset_t block_io_signals(void);
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them. We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+static void sigfd_handler(void *opaque)
+{
+ int fd = (unsigned long) opaque;
+ struct qemu_signalfd_siginfo info;
+ struct sigaction action;
+ ssize_t len;
+
+ while (1) {
+ do {
+ len = read(fd, &info, sizeof(info));
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1 && errno == EAGAIN) {
+ break;
+ }
+
+ if (len != sizeof(info)) {
+ printf("read from sigfd returned %zd: %m\n", len);
+ return;
+ }
+
+ sigaction(info.ssi_signo, NULL, &action);
+ if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
+ action.sa_sigaction(info.ssi_signo,
+ (siginfo_t *)&info, NULL);
+ } else if (action.sa_handler) {
+ action.sa_handler(info.ssi_signo);
+ }
+ }
+}
+
+static int qemu_signalfd_init(sigset_t mask)
+{
+ int sigfd;
+
+ sigfd = qemu_signalfd(&mask);
+ if (sigfd == -1) {
+ fprintf(stderr, "failed to create signalfd\n");
+ return -errno;
+ }
+
+ fcntl_setfl(sigfd, O_NONBLOCK);
+
+ qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+ (void *)(unsigned long) sigfd);
+
+ return 0;
+}
int qemu_init_main_loop(void)
{
int ret;
+ sigset_t blocked_signals;
cpu_set_debug_excp_handler(cpu_debug_handler);
+ blocked_signals = block_io_signals();
+
+ ret = qemu_signalfd_init(blocked_signals);
+ if (ret)
+ return ret;
+
+ /* Note eventfd must be drained before signalfd handlers run */
ret = qemu_event_init();
if (ret)
return ret;
@@ -347,7 +409,6 @@ int qemu_init_main_loop(void)
qemu_mutex_init(&qemu_global_mutex);
qemu_mutex_lock(&qemu_global_mutex);
- unblock_io_signals();
qemu_thread_self(&io_thread);
return 0;
@@ -586,19 +647,22 @@ static void kvm_init_ipi(CPUState *env)
}
}
-static void unblock_io_signals(void)
+static sigset_t block_io_signals(void)
{
sigset_t set;
+ /* SIGUSR2 used by posix-aio-compat.c */
sigemptyset(&set);
sigaddset(&set, SIGUSR2);
- sigaddset(&set, SIGIO);
- sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
sigemptyset(&set);
+ sigaddset(&set, SIGIO);
+ sigaddset(&set, SIGALRM);
sigaddset(&set, SIG_IPI);
pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ return set;
}
void qemu_mutex_lock_iothread(void)