This avoids a wakeup being lost, in case the iothread handles the signal before select(). Copied and possibly damaged from kvm-userspace. Index: qemu/vl.c =================================================================== --- qemu.orig/vl.c +++ qemu/vl.c @@ -155,8 +155,6 @@ //#define DEBUG_NET //#define DEBUG_SLIRP -#define SIG_IPI (SIGRTMIN+4) - #ifdef DEBUG_IOPORT # define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__) #else @@ -273,6 +271,8 @@ QemuThread cpus_thread; QemuCond qemu_pause_cond; +static int io_thread_fd = -1; + static void pause_all_vcpus(void); static void resume_all_vcpus(void); @@ -3723,7 +3723,6 @@ static void block_io_signals(void) sigaddset(&set, SIGUSR2); sigaddset(&set, SIGIO); sigaddset(&set, SIGALRM); - sigaddset(&set, SIG_IPI); pthread_sigmask(SIG_BLOCK, &set, NULL); sigemptyset(&set); @@ -3735,30 +3734,19 @@ static void block_io_signals(void) sigaction(SIGUSR1, &sigact, NULL); } -/* used to wake up the io thread */ -static void sig_ipi_handler(int sig) -{ -} - static void unblock_io_signals(void) { sigset_t set; - struct sigaction sigact; sigemptyset(&set); sigaddset(&set, SIGUSR2); sigaddset(&set, SIGIO); sigaddset(&set, SIGALRM); - sigaddset(&set, SIG_IPI); pthread_sigmask(SIG_UNBLOCK, &set, NULL); sigemptyset(&set); sigaddset(&set, SIGUSR1); pthread_sigmask(SIG_BLOCK, &set, NULL); - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = sig_ipi_handler; - sigaction(SIG_IPI, &sigact, NULL); } int qemu_notify_event(void *cpu_env) @@ -3774,11 +3762,51 @@ int qemu_notify_event(void *cpu_env) void main_loop_break(void) { - QemuThread me; - qemu_thread_self(&me); - if (qemu_thread_equal(&io_thread, &me)) + uint64_t value = 1; + char buffer[8]; + size_t offset = 0; + + if (io_thread_fd == -1) return; - qemu_thread_signal(&io_thread, SIG_IPI); + + memcpy(buffer, &value, sizeof(value)); + + while (offset < 8) { + ssize_t len; + + len = write(io_thread_fd, buffer + offset, 8 - offset); + if (len == -1 && errno == EINTR) + continue; + + if (len <= 0) + break; + + offset += len; + } + + if (offset != 8) + fprintf(stderr, "failed to notify io thread\n"); +} + +/* Used to break IO thread out of select */ +static void io_thread_wakeup(void *opaque) +{ + int fd = (unsigned long)opaque; + char buffer[8]; + size_t offset = 0; + + while (offset < 8) { + ssize_t len; + + len = read(fd, buffer + offset, 8 - offset); + if (len == -1 && errno == EINTR) + continue; + + if (len <= 0) + break; + + offset += len; + } } static void qemu_signal_lock(unsigned int msecs) @@ -4086,6 +4114,20 @@ static void resume_all_vcpus(void) } } +static void setup_iothread_fd(void) +{ + int fds[2]; + + if (pipe(fds) == -1) { + fprintf(stderr, "failed to create iothread pipe"); + exit(0); + } + + qemu_set_fd_handler2(fds[0], NULL, io_thread_wakeup, NULL, + (void *)(unsigned long)fds[0]); + io_thread_fd = fds[1]; +} + static void main_loop(void) { int r; @@ -4096,6 +4138,7 @@ static void main_loop(void) qemu_cond_init(&qemu_pause_cond); qemu_thread_self(&io_thread); + setup_iothread_fd(); unblock_io_signals(); --