event_notifier: enable it to use pipes
This takes the eventfd emulation code from the main loop. When the EventNotifier is used for the main loop too, we need this compatibility code. Without CONFIG_EVENTFD, event_notifier_get_fd is only usable for the "read" side of the notifier, for example to set a select() handler. The return value of event_notifier_set changes to the cleaner 0/-errno. No caller is actually checking the return value. Reviewed-by: Anthony Liguori <anthony@codemonkey.ws> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
fc97a652de
commit
d0cc2fbfa6
@ -20,48 +20,101 @@
|
||||
|
||||
void event_notifier_init_fd(EventNotifier *e, int fd)
|
||||
{
|
||||
e->fd = fd;
|
||||
e->rfd = fd;
|
||||
e->wfd = fd;
|
||||
}
|
||||
|
||||
int event_notifier_init(EventNotifier *e, int active)
|
||||
{
|
||||
int fds[2];
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_EVENTFD
|
||||
int fd = eventfd(!!active, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
e->fd = fd;
|
||||
return 0;
|
||||
ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
#else
|
||||
return -ENOSYS;
|
||||
ret = -1;
|
||||
errno = ENOSYS;
|
||||
#endif
|
||||
if (ret >= 0) {
|
||||
e->rfd = e->wfd = ret;
|
||||
} else {
|
||||
if (errno != ENOSYS) {
|
||||
return -errno;
|
||||
}
|
||||
if (qemu_pipe(fds) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
ret = fcntl_setfl(fds[0], O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
ret = fcntl_setfl(fds[1], O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
e->rfd = fds[0];
|
||||
e->wfd = fds[1];
|
||||
}
|
||||
if (active) {
|
||||
event_notifier_set(e);
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
close(e->fd);
|
||||
if (e->rfd != e->wfd) {
|
||||
close(e->rfd);
|
||||
}
|
||||
close(e->wfd);
|
||||
}
|
||||
|
||||
int event_notifier_get_fd(EventNotifier *e)
|
||||
{
|
||||
return e->fd;
|
||||
return e->rfd;
|
||||
}
|
||||
|
||||
int event_notifier_set_handler(EventNotifier *e,
|
||||
EventNotifierHandler *handler)
|
||||
{
|
||||
return qemu_set_fd_handler(e->fd, (IOHandler *)handler, NULL, e);
|
||||
return qemu_set_fd_handler(e->rfd, (IOHandler *)handler, NULL, e);
|
||||
}
|
||||
|
||||
int event_notifier_set(EventNotifier *e)
|
||||
{
|
||||
uint64_t value = 1;
|
||||
int r = write(e->fd, &value, sizeof(value));
|
||||
return r == sizeof(value);
|
||||
static const uint64_t value = 1;
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
ret = write(e->wfd, &value, sizeof(value));
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
/* EAGAIN is fine, a read must be pending. */
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_notifier_test_and_clear(EventNotifier *e)
|
||||
{
|
||||
uint64_t value;
|
||||
int r = read(e->fd, &value, sizeof(value));
|
||||
return r == sizeof(value);
|
||||
int value;
|
||||
ssize_t len;
|
||||
char buffer[512];
|
||||
|
||||
/* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
|
||||
value = 0;
|
||||
do {
|
||||
len = read(e->rfd, buffer, sizeof(buffer));
|
||||
value |= (len > 0);
|
||||
} while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ struct EventNotifier {
|
||||
#ifdef _WIN32
|
||||
HANDLE event;
|
||||
#else
|
||||
int fd;
|
||||
int rfd;
|
||||
int wfd;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user