d73415a315
clang's C11 atomic_fetch_*() functions only take a C11 atomic type pointer argument. QEMU uses direct types (int, etc) and this causes a compiler error when a QEMU code calls these functions in a source file that also included <stdatomic.h> via a system header file: $ CC=clang CXX=clang++ ./configure ... && make ../util/async.c:79:17: error: address argument to atomic operation must be a pointer to _Atomic type ('unsigned int *' invalid) Avoid using atomic_*() names in QEMU's atomic.h since that namespace is used by <stdatomic.h>. Prefix QEMU's APIs with 'q' so that atomic.h and <stdatomic.h> can co-exist. I checked /usr/include on my machine and searched GitHub for existing "qatomic_" users but there seem to be none. This patch was generated using: $ git grep -h -o '\<atomic\(64\)\?_[a-z0-9_]\+' include/qemu/atomic.h | \ sort -u >/tmp/changed_identifiers $ for identifier in $(</tmp/changed_identifiers); do sed -i "s%\<$identifier\>%q$identifier%g" \ $(git grep -I -l "\<$identifier\>") done I manually fixed line-wrap issues and misaligned rST tables. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20200923105646.47864-1-stefanha@redhat.com>
156 lines
4.0 KiB
C
156 lines
4.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* epoll(7) file descriptor monitoring
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include <sys/epoll.h>
|
|
#include "qemu/rcu_queue.h"
|
|
#include "aio-posix.h"
|
|
|
|
/* The fd number threshold to switch to epoll */
|
|
#define EPOLL_ENABLE_THRESHOLD 64
|
|
|
|
void fdmon_epoll_disable(AioContext *ctx)
|
|
{
|
|
if (ctx->epollfd >= 0) {
|
|
close(ctx->epollfd);
|
|
ctx->epollfd = -1;
|
|
}
|
|
|
|
/* Switch back */
|
|
ctx->fdmon_ops = &fdmon_poll_ops;
|
|
}
|
|
|
|
static inline int epoll_events_from_pfd(int pfd_events)
|
|
{
|
|
return (pfd_events & G_IO_IN ? EPOLLIN : 0) |
|
|
(pfd_events & G_IO_OUT ? EPOLLOUT : 0) |
|
|
(pfd_events & G_IO_HUP ? EPOLLHUP : 0) |
|
|
(pfd_events & G_IO_ERR ? EPOLLERR : 0);
|
|
}
|
|
|
|
static void fdmon_epoll_update(AioContext *ctx,
|
|
AioHandler *old_node,
|
|
AioHandler *new_node)
|
|
{
|
|
struct epoll_event event = {
|
|
.data.ptr = new_node,
|
|
.events = new_node ? epoll_events_from_pfd(new_node->pfd.events) : 0,
|
|
};
|
|
int r;
|
|
|
|
if (!new_node) {
|
|
r = epoll_ctl(ctx->epollfd, EPOLL_CTL_DEL, old_node->pfd.fd, &event);
|
|
} else if (!old_node) {
|
|
r = epoll_ctl(ctx->epollfd, EPOLL_CTL_ADD, new_node->pfd.fd, &event);
|
|
} else {
|
|
r = epoll_ctl(ctx->epollfd, EPOLL_CTL_MOD, new_node->pfd.fd, &event);
|
|
}
|
|
|
|
if (r) {
|
|
fdmon_epoll_disable(ctx);
|
|
}
|
|
}
|
|
|
|
static int fdmon_epoll_wait(AioContext *ctx, AioHandlerList *ready_list,
|
|
int64_t timeout)
|
|
{
|
|
GPollFD pfd = {
|
|
.fd = ctx->epollfd,
|
|
.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR,
|
|
};
|
|
AioHandler *node;
|
|
int i, ret = 0;
|
|
struct epoll_event events[128];
|
|
|
|
/* Fall back while external clients are disabled */
|
|
if (qatomic_read(&ctx->external_disable_cnt)) {
|
|
return fdmon_poll_ops.wait(ctx, ready_list, timeout);
|
|
}
|
|
|
|
if (timeout > 0) {
|
|
ret = qemu_poll_ns(&pfd, 1, timeout);
|
|
if (ret > 0) {
|
|
timeout = 0;
|
|
}
|
|
}
|
|
if (timeout <= 0 || ret > 0) {
|
|
ret = epoll_wait(ctx->epollfd, events,
|
|
ARRAY_SIZE(events),
|
|
timeout);
|
|
if (ret <= 0) {
|
|
goto out;
|
|
}
|
|
for (i = 0; i < ret; i++) {
|
|
int ev = events[i].events;
|
|
int revents = (ev & EPOLLIN ? G_IO_IN : 0) |
|
|
(ev & EPOLLOUT ? G_IO_OUT : 0) |
|
|
(ev & EPOLLHUP ? G_IO_HUP : 0) |
|
|
(ev & EPOLLERR ? G_IO_ERR : 0);
|
|
|
|
node = events[i].data.ptr;
|
|
aio_add_ready_handler(ready_list, node, revents);
|
|
}
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static const FDMonOps fdmon_epoll_ops = {
|
|
.update = fdmon_epoll_update,
|
|
.wait = fdmon_epoll_wait,
|
|
.need_wait = aio_poll_disabled,
|
|
};
|
|
|
|
static bool fdmon_epoll_try_enable(AioContext *ctx)
|
|
{
|
|
AioHandler *node;
|
|
struct epoll_event event;
|
|
|
|
QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
|
|
int r;
|
|
if (QLIST_IS_INSERTED(node, node_deleted) || !node->pfd.events) {
|
|
continue;
|
|
}
|
|
event.events = epoll_events_from_pfd(node->pfd.events);
|
|
event.data.ptr = node;
|
|
r = epoll_ctl(ctx->epollfd, EPOLL_CTL_ADD, node->pfd.fd, &event);
|
|
if (r) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ctx->fdmon_ops = &fdmon_epoll_ops;
|
|
return true;
|
|
}
|
|
|
|
bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd)
|
|
{
|
|
if (ctx->epollfd < 0) {
|
|
return false;
|
|
}
|
|
|
|
/* Do not upgrade while external clients are disabled */
|
|
if (qatomic_read(&ctx->external_disable_cnt)) {
|
|
return false;
|
|
}
|
|
|
|
if (npfd >= EPOLL_ENABLE_THRESHOLD) {
|
|
if (fdmon_epoll_try_enable(ctx)) {
|
|
return true;
|
|
} else {
|
|
fdmon_epoll_disable(ctx);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void fdmon_epoll_setup(AioContext *ctx)
|
|
{
|
|
ctx->epollfd = epoll_create1(EPOLL_CLOEXEC);
|
|
if (ctx->epollfd == -1) {
|
|
fprintf(stderr, "Failed to create epoll instance: %s", strerror(errno));
|
|
}
|
|
}
|