This patch adds compatibility code so that we can use signalfd() within QEMU. signalfd() provides a mechanism to receive signal notification through a file descriptor. This is very useful in eliminating the signal/select race condition.
If signalfd() isn't available, we spawn a thread that uses sigwaitinfo() to emulate it. Signed-off-by: Anthony Liguori <[EMAIL PROTECTED]> diff --git a/qemu/kvm-compatfd.c b/qemu/kvm-compatfd.c index 1b030ba..b1311e2 100644 --- a/qemu/kvm-compatfd.c +++ b/qemu/kvm-compatfd.c @@ -15,6 +15,97 @@ #include "qemu-kvm.h" #include <sys/syscall.h> +#include <pthread.h> + +struct sigfd_compat_info +{ + sigset_t mask; + int fd; +}; + +static void *sigwait_compat(void *opaque) +{ + struct sigfd_compat_info *info = opaque; + int err; + + sigprocmask(SIG_BLOCK, &info->mask, NULL); + + do { + siginfo_t siginfo; + + err = sigwaitinfo(&info->mask, &siginfo); + if (err == -1 && errno == EINTR) + continue; + + if (err > 0) { + char buffer[128]; + size_t offset = 0; + + memcpy(buffer, &err, sizeof(err)); + while (offset < sizeof(buffer)) { + ssize_t len; + + len = write(info->fd, buffer + offset, + sizeof(buffer) - offset); + if (len == -1 && errno == EINTR) + continue; + + if (len <= 0) { + err = -1; + break; + } + + offset += len; + } + } + } while (err >= 0); + + return NULL; +} + +static int kvm_signalfd_compat(const sigset_t *mask) +{ + pthread_attr_t attr; + pthread_t tid; + struct sigfd_compat_info *info; + int fds[2]; + + info = malloc(sizeof(*info)); + if (info == NULL) { + errno = ENOMEM; + return -1; + } + + if (pipe(fds) == -1) { + free(info); + return -1; + } + + memcpy(&info->mask, mask, sizeof(*mask)); + info->fd = fds[1]; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + pthread_create(&tid, &attr, sigwait_compat, info); + + pthread_attr_destroy(&attr); + + return fds[0]; +} + +int kvm_signalfd(const sigset_t *mask) +{ +#if defined(SYS_signalfd) + int ret; + + ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8); + if (!(ret == -1 && errno == ENOSYS)) + return ret; +#endif + + return kvm_signalfd_compat(mask); +} int kvm_eventfd(int *fds) { diff --git a/qemu/qemu-kvm.h b/qemu/qemu-kvm.h index 8fa3c1b..a0dd4a8 100644 --- a/qemu/qemu-kvm.h +++ b/qemu/qemu-kvm.h @@ -10,6 +10,8 @@ #include "cpu.h" +#include <signal.h> + int kvm_main_loop(void); int kvm_qemu_init(void); int kvm_qemu_create_context(void); @@ -79,6 +81,16 @@ int handle_powerpc_dcr_read(int vcpu, uint32_t dcrn, uint32_t *data); int handle_powerpc_dcr_write(int vcpu,uint32_t dcrn, uint32_t data); #endif +#if !defined(SYS_signalfd) +struct signalfd_siginfo { + uint32_t ssi_signo; + uint8_t pad[124]; +}; +#else +#include <linux/signalfd.h> +#endif + +int kvm_signalfd(const sigset_t *mask); int kvm_eventfd(int *fds); #define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1)) ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel