Message ID | 1348577763-12920-3-git-send-email-pbonzini@redhat.com |
---|---|
State | New |
Headers | show |
On Tue, Sep 25, 2012 at 02:55:48PM +0200, Paolo Bonzini wrote: > 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 -1; If we're changing the return value representation, then we might as well: return -errno; But no caller actually checks the return value.
diff --git a/event_notifier.c b/event_notifier.c index 2c207e1..88c114b 100644 --- a/event_notifier.c +++ b/event_notifier.c @@ -20,48 +20,99 @@ 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) { + goto fail; + } + ret = fcntl_setfl(fds[1], O_NONBLOCK); + if (ret < 0) { + 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 -1; + } + 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; } diff --git a/event_notifier.h b/event_notifier.h index f0ec2f2..f04d12d 100644 --- a/event_notifier.h +++ b/event_notifier.h @@ -16,7 +16,8 @@ #include "qemu-common.h" struct EventNotifier { - int fd; + int rfd; + int wfd; }; typedef void EventNotifierHandler(EventNotifier *);