aboutsummaryrefslogtreecommitdiff
path: root/block-raw-posix.c
diff options
context:
space:
mode:
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2008-09-10 15:45:19 +0000
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2008-09-10 15:45:19 +0000
commitbaf35cb90204d75404892aa4e52628ae7a00669b (patch)
tree44d96418e4d0e90c5841692a29743022fbc107c1 /block-raw-posix.c
parent279826619dfb36bac39d8549526a76eabb9d311e (diff)
Use signalfd() to work around signal/select race
This patch introduces signalfd() to work around the signal/select race in checking for AIO completions. For platforms that don't support signalfd(), we emulate it with threads. There was a long discussion about this approach. I don't believe there are any fundamental problems with this approach and I believe eliminating the use of signals is a good thing. I've tested Windows and Linux using Windows and Linux guests. I've also checked for disk IO performance regressions. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5187 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'block-raw-posix.c')
-rw-r--r--block-raw-posix.c129
1 files changed, 48 insertions, 81 deletions
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 96edab4fb7..f6dc72ae54 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -25,8 +25,10 @@
#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
#include "qemu-timer.h"
#include "exec-all.h"
+#include "qemu-char.h"
#endif
#include "block_int.h"
+#include "compatfd.h"
#include <assert.h>
#ifdef CONFIG_AIO
#include <aio.h>
@@ -438,52 +440,12 @@ typedef struct RawAIOCB {
int ret;
} RawAIOCB;
+static int aio_sig_fd = -1;
static int aio_sig_num = SIGUSR2;
static RawAIOCB *first_aio; /* AIO issued */
static int aio_initialized = 0;
-static void aio_signal_handler(int signum)
-{
-#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
- CPUState *env = cpu_single_env;
- if (env) {
- /* stop the currently executing cpu because a timer occured */
- cpu_interrupt(env, CPU_INTERRUPT_EXIT);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
- }
-#endif
-}
-
-void qemu_aio_init(void)
-{
- struct sigaction act;
-
- aio_initialized = 1;
-
- sigfillset(&act.sa_mask);
- act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
- act.sa_handler = aio_signal_handler;
- sigaction(aio_sig_num, &act, NULL);
-
-#if defined(__GLIBC__) && defined(__linux__)
- {
- /* XXX: aio thread exit seems to hang on RedHat 9 and this init
- seems to fix the problem. */
- struct aioinit ai;
- memset(&ai, 0, sizeof(ai));
- ai.aio_threads = 1;
- ai.aio_num = 1;
- ai.aio_idle_time = 365 * 100000;
- aio_init(&ai);
- }
-#endif
-}
-
-void qemu_aio_poll(void)
+static void qemu_aio_poll(void *opaque)
{
RawAIOCB *acb, **pacb;
int ret;
@@ -524,49 +486,66 @@ void qemu_aio_poll(void)
the_end: ;
}
+void qemu_aio_init(void)
+{
+ sigset_t mask;
+
+ aio_initialized = 1;
+
+ /* Make sure to block AIO signal */
+ sigemptyset(&mask);
+ sigaddset(&mask, aio_sig_num);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ aio_sig_fd = qemu_signalfd(&mask);
+#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
+ qemu_set_fd_handler2(aio_sig_fd, NULL, qemu_aio_poll, NULL, NULL);
+#endif
+
+#if defined(__GLIBC__) && defined(__linux__)
+ {
+ /* XXX: aio thread exit seems to hang on RedHat 9 and this init
+ seems to fix the problem. */
+ struct aioinit ai;
+ memset(&ai, 0, sizeof(ai));
+ ai.aio_threads = 1;
+ ai.aio_num = 1;
+ ai.aio_idle_time = 365 * 100000;
+ aio_init(&ai);
+ }
+#endif
+}
+
/* Wait for all IO requests to complete. */
void qemu_aio_flush(void)
{
- qemu_aio_wait_start();
- qemu_aio_poll();
+ qemu_aio_poll(NULL);
while (first_aio) {
qemu_aio_wait();
}
- qemu_aio_wait_end();
-}
-
-/* wait until at least one AIO was handled */
-static sigset_t wait_oset;
-
-void qemu_aio_wait_start(void)
-{
- sigset_t set;
-
- if (!aio_initialized)
- qemu_aio_init();
- sigemptyset(&set);
- sigaddset(&set, aio_sig_num);
- sigprocmask(SIG_BLOCK, &set, &wait_oset);
}
void qemu_aio_wait(void)
{
- sigset_t set;
- int nb_sigs;
+ int ret;
#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
if (qemu_bh_poll())
return;
#endif
- sigemptyset(&set);
- sigaddset(&set, aio_sig_num);
- sigwait(&set, &nb_sigs);
- qemu_aio_poll();
-}
-void qemu_aio_wait_end(void)
-{
- sigprocmask(SIG_SETMASK, &wait_oset, NULL);
+ do {
+ fd_set rdfds;
+
+ FD_ZERO(&rdfds);
+ FD_SET(aio_sig_fd, &rdfds);
+
+ ret = select(aio_sig_fd + 1, &rdfds, NULL, NULL, NULL);
+ if (ret == -1 && errno == EINTR)
+ continue;
+ } while (ret == 0);
+
+ qemu_aio_poll(NULL);
}
static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
@@ -704,18 +683,10 @@ void qemu_aio_init(void)
{
}
-void qemu_aio_poll(void)
-{
-}
-
void qemu_aio_flush(void)
{
}
-void qemu_aio_wait_start(void)
-{
-}
-
void qemu_aio_wait(void)
{
#if !defined(QEMU_IMG) && !defined(QEMU_NBD)
@@ -723,10 +694,6 @@ void qemu_aio_wait(void)
#endif
}
-void qemu_aio_wait_end(void)
-{
-}
-
#endif /* CONFIG_AIO */
static void raw_close(BlockDriverState *bs)