Browse Source
Replace signalfd with signal handler/pipe. There is no way to interrupt
the CPU execution loop when a file descriptor becomes readable. This
results in a large performance regression in sparc emulation during
bootup.
This patch switches us to signal handler/pipe which was originally
suggested by Ian Jackson. The signal handler lets us interrupt the
CPU emulation loop while the write to a pipe lets us avoid the
select/signal race condition.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5451 c046a42c-6fe2-441c-8c8c-71466251a162
stable-0.10
9 changed files with 55 additions and 233 deletions
@ -1,127 +0,0 @@ |
|||
/*
|
|||
* 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; |
|||
} |
|||
|
|||
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) |
|||
return ret; |
|||
#endif |
|||
|
|||
return qemu_signalfd_compat(mask); |
|||
} |
|||
|
|||
int qemu_eventfd(int *fds) |
|||
{ |
|||
#if defined(CONFIG_eventfd) |
|||
int ret; |
|||
|
|||
ret = syscall(SYS_eventfd, 0); |
|||
if (ret >= 0) { |
|||
fds[0] = fds[1] = ret; |
|||
return 0; |
|||
} |
|||
#endif |
|||
|
|||
return pipe(fds); |
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
/*
|
|||
* 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; |
|||
uint8_t pad[124]; |
|||
}; |
|||
|
|||
int qemu_signalfd(const sigset_t *mask); |
|||
|
|||
int qemu_eventfd(int *fds); |
|||
|
|||
#endif |
|||
Loading…
Reference in new issue