From ef9633e1290d055543136e136b6b7f59d863a601 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 30 Jul 2008 12:06:29 +0100 Subject: [PATCH] Use fd signal trick to break us out of select; do not sigwait * The sigwait approach to detecting aio does not work because some versions of glibc forget to block signals on the private aio thread. This means that blocking SIGUSR2 is ineffective; the signals can be lost and the program can block in sigwait (!) * Use of SIGUSR2 to interrupt select() does not work because signals which arrive just before entry to select() do not interrupt it. So instead we use the time-honoured self-pipe trick: in the signal handler we write to a pipe, which we select on when we want to wait for the signal, and which we read from (to empty out) just before actually doing the `top half' processing which deals with the condition to which the signal relates. --- block-raw-posix.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/block-raw-posix.c b/block-raw-posix.c index 23311e87..c9f01255 100644 --- a/block-raw-posix.c +++ b/block-raw-posix.c @@ -22,6 +22,8 @@ * THE SOFTWARE. */ #include "qemu-common.h" +#include "qemu-char.h" +#include "qemu_socket.h" #ifndef QEMU_IMG #include "qemu-timer.h" #include "exec-all.h" @@ -242,9 +244,13 @@ typedef struct RawAIOCB { static int aio_sig_num = SIGUSR2; static RawAIOCB *first_aio; /* AIO issued */ static int aio_initialized = 0; +static int aio_sig_pipe[2]; static void aio_signal_handler(int signum) { + int e; + e = errno; + write(aio_sig_pipe[1],"",1); /* ignore errors as they should be EAGAIN */ #ifndef QEMU_IMG CPUState *env = cpu_single_env; if (env) { @@ -257,11 +263,31 @@ static void aio_signal_handler(int signum) #endif } #endif + errno = e; +} + +static void qemu_aio_sig_pipe_read(void *opaque_ignored) { + qemu_aio_poll(); } void qemu_aio_init(void) { struct sigaction act; + int ret; + + ret = pipe(aio_sig_pipe); + if (ret) { perror("qemu_aio_init pipe failed"); exit(-1); } + fcntl(aio_sig_pipe[0], F_SETFL, O_NONBLOCK); + fcntl(aio_sig_pipe[1], F_SETFL, O_NONBLOCK); + +#ifndef QEMU_IMG + ret = qemu_set_fd_handler2(aio_sig_pipe[0], NULL, + qemu_aio_sig_pipe_read, NULL, NULL); + if (ret) { + fputs("qemu_aio_init set_fd_handler failed\n",stderr); + exit(-1); + } +#endif aio_initialized = 1; @@ -289,6 +315,12 @@ void qemu_aio_poll(void) RawAIOCB *acb, **pacb; int ret; + /* eat any pending signal notifications */ + { + char dummy_buf[16]; + read(aio_sig_pipe[0],dummy_buf,sizeof(dummy_buf)); + } + for(;;) { pacb = &first_aio; for(;;) { @@ -345,29 +377,24 @@ void qemu_aio_wait_start(void) 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; + fd_set check; #ifndef QEMU_IMG if (qemu_bh_poll()) return; #endif - sigemptyset(&set); - sigaddset(&set, aio_sig_num); - sigwait(&set, &nb_sigs); + FD_ZERO(&check); + FD_SET(aio_sig_pipe[0], &check); + select(aio_sig_pipe[0]+1, &check,0,&check, 0); qemu_aio_poll(); } void qemu_aio_wait_end(void) { - sigprocmask(SIG_SETMASK, &wait_oset, NULL); } static RawAIOCB *raw_aio_setup(BlockDriverState *bs, -- 2.39.5