signalfd compatibility

Port qemu-kvm's signalfd compat code.

commit 5a7fdd0abd7cd24dac205317a4195446ab8748b5
Author: Anthony Liguori <aliguori@us.ibm.com>
Date:   Wed May 7 11:55:47 2008 -0500

    Use signalfd() in io-thread

    This patch reworks the IO thread to use signalfd() instead of sigtimedwait()
    This will eliminate the need to use SIGIO everywhere.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
Marcelo Tosatti 2010-10-11 15:31:15 -03:00 committed by Anthony Liguori
parent 296acb643b
commit dcc38d1cce
4 changed files with 179 additions and 0 deletions

View File

@ -125,6 +125,7 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y))
common-obj-y += iov.o acl.o common-obj-y += iov.o acl.o
common-obj-$(CONFIG_THREAD) += qemu-thread.o common-obj-$(CONFIG_THREAD) += qemu-thread.o
common-obj-$(CONFIG_IOTHREAD) += compatfd.o
common-obj-y += notify.o event_notifier.o common-obj-y += notify.o event_notifier.o
common-obj-y += qemu-timer.o common-obj-y += qemu-timer.o

117
compatfd.c Normal file
View File

@ -0,0 +1,117 @@
/*
* signalfd/eventfd compatibility
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "qemu-common.h"
#include "compatfd.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;
sigset_t all;
sigfillset(&all);
sigprocmask(SIG_BLOCK, &all, NULL);
do {
siginfo_t siginfo;
err = sigwaitinfo(&info->mask, &siginfo);
if (err == -1 && errno == EINTR) {
err = 0;
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 qemu_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;
}
qemu_set_cloexec(fds[0]);
qemu_set_cloexec(fds[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 qemu_signalfd(const sigset_t *mask)
{
#if defined(CONFIG_SIGNALFD)
int ret;
ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
if (ret != -1) {
qemu_set_cloexec(ret);
return ret;
}
#endif
return qemu_signalfd_compat(mask);
}

43
compatfd.h Normal file
View File

@ -0,0 +1,43 @@
/*
* signalfd/eventfd compatibility
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#ifndef QEMU_COMPATFD_H
#define QEMU_COMPATFD_H
#include <signal.h>
struct qemu_signalfd_siginfo {
uint32_t ssi_signo; /* Signal number */
int32_t ssi_errno; /* Error number (unused) */
int32_t ssi_code; /* Signal code */
uint32_t ssi_pid; /* PID of sender */
uint32_t ssi_uid; /* Real UID of sender */
int32_t ssi_fd; /* File descriptor (SIGIO) */
uint32_t ssi_tid; /* Kernel timer ID (POSIX timers) */
uint32_t ssi_band; /* Band event (SIGIO) */
uint32_t ssi_overrun; /* POSIX timer overrun count */
uint32_t ssi_trapno; /* Trap number that caused signal */
int32_t ssi_status; /* Exit status or signal (SIGCHLD) */
int32_t ssi_int; /* Integer sent by sigqueue(2) */
uint64_t ssi_ptr; /* Pointer sent by sigqueue(2) */
uint64_t ssi_utime; /* User CPU time consumed (SIGCHLD) */
uint64_t ssi_stime; /* System CPU time consumed (SIGCHLD) */
uint64_t ssi_addr; /* Address that generated signal
(for hardware-generated signals) */
uint8_t pad[48]; /* Pad size to 128 bytes (allow for
additional fields in the future) */
};
int qemu_signalfd(const sigset_t *mask);
#endif

18
configure vendored
View File

@ -1957,6 +1957,21 @@ if compile_prog "" "" ; then
splice=yes splice=yes
fi fi
##########################################
# signalfd probe
signalfd="no"
cat > $TMPC << EOF
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }
EOF
if compile_prog "" "" ; then
signalfd=yes
fi
# check if eventfd is supported # check if eventfd is supported
eventfd=no eventfd=no
cat > $TMPC << EOF cat > $TMPC << EOF
@ -2559,6 +2574,9 @@ fi
if test "$fdt" = "yes" ; then if test "$fdt" = "yes" ; then
echo "CONFIG_FDT=y" >> $config_host_mak echo "CONFIG_FDT=y" >> $config_host_mak
fi fi
if test "$signalfd" = "yes" ; then
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
fi
if test "$need_offsetof" = "yes" ; then if test "$need_offsetof" = "yes" ; then
echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
fi fi