mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
3bcf0fb3f2
event_notifier_get_fd(const EventNotifier *e) always returns EventNotifier's read file descriptor (rfd). This is not a problem when the EventNotifier is backed by a an eventfd, as a single file descriptor is used both for reading and triggering events (rfd == wfd). But, when EventNotifier is backed by a pipe pair, we have two file descriptors, one that can only be used for reads (rfd), and the other only for writes (wfd). There's, at least, one known situation in which we need to obtain wfd instead of rfd, which is when setting up the file that's going to be sent to the peer in vhost's SET_VRING_CALL. Add a new event_notifier_get_wfd(const EventNotifier *e) that can be used to obtain wfd where needed. Signed-off-by: Sergio Lopez <slp@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20220304100854.14829-2-slp@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
146 lines
2.8 KiB
C
146 lines
2.8 KiB
C
/*
|
|
* event notifier support
|
|
*
|
|
* Copyright Red Hat, Inc. 2010
|
|
*
|
|
* Authors:
|
|
* Michael S. Tsirkin <mst@redhat.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
* See the COPYING file in the top-level directory.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu-common.h"
|
|
#include "qemu/cutils.h"
|
|
#include "qemu/event_notifier.h"
|
|
#include "qemu/main-loop.h"
|
|
|
|
#ifdef CONFIG_EVENTFD
|
|
#include <sys/eventfd.h>
|
|
#endif
|
|
|
|
#ifdef CONFIG_EVENTFD
|
|
/*
|
|
* Initialize @e with existing file descriptor @fd.
|
|
* @fd must be a genuine eventfd object, emulation with pipe won't do.
|
|
*/
|
|
void event_notifier_init_fd(EventNotifier *e, int fd)
|
|
{
|
|
e->rfd = fd;
|
|
e->wfd = fd;
|
|
e->initialized = true;
|
|
}
|
|
#endif
|
|
|
|
int event_notifier_init(EventNotifier *e, int active)
|
|
{
|
|
int fds[2];
|
|
int ret;
|
|
|
|
#ifdef CONFIG_EVENTFD
|
|
ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
|
#else
|
|
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];
|
|
}
|
|
e->initialized = true;
|
|
if (active) {
|
|
event_notifier_set(e);
|
|
}
|
|
return 0;
|
|
|
|
fail:
|
|
close(fds[0]);
|
|
close(fds[1]);
|
|
return ret;
|
|
}
|
|
|
|
void event_notifier_cleanup(EventNotifier *e)
|
|
{
|
|
if (!e->initialized) {
|
|
return;
|
|
}
|
|
|
|
if (e->rfd != e->wfd) {
|
|
close(e->rfd);
|
|
}
|
|
|
|
e->rfd = -1;
|
|
close(e->wfd);
|
|
e->wfd = -1;
|
|
e->initialized = false;
|
|
}
|
|
|
|
int event_notifier_get_fd(const EventNotifier *e)
|
|
{
|
|
return e->rfd;
|
|
}
|
|
|
|
int event_notifier_get_wfd(const EventNotifier *e)
|
|
{
|
|
return e->wfd;
|
|
}
|
|
|
|
int event_notifier_set(EventNotifier *e)
|
|
{
|
|
static const uint64_t value = 1;
|
|
ssize_t ret;
|
|
|
|
if (!e->initialized) {
|
|
return -1;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int value;
|
|
ssize_t len;
|
|
char buffer[512];
|
|
|
|
if (!e->initialized) {
|
|
return 0;
|
|
}
|
|
|
|
/* 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;
|
|
}
|