Skip to content

Commit

Permalink
signalfd compatibility
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
matosatti authored and Anthony Liguori committed Oct 20, 2010
1 parent 296acb6 commit dcc38d1
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile.objs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y))

common-obj-y += iov.o acl.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 += qemu-timer.o

Expand Down
117 changes: 117 additions & 0 deletions compatfd.c
Original file line number Diff line number Diff line change
@@ -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 changes: 43 additions & 0 deletions compatfd.h
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,21 @@ if compile_prog "" "" ; then
splice=yes
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
eventfd=no
cat > $TMPC << EOF
Expand Down Expand Up @@ -2559,6 +2574,9 @@ fi
if test "$fdt" = "yes" ; then
echo "CONFIG_FDT=y" >> $config_host_mak
fi
if test "$signalfd" = "yes" ; then
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
fi
if test "$need_offsetof" = "yes" ; then
echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
fi
Expand Down

0 comments on commit dcc38d1

Please sign in to comment.