mirror of
				https://github.com/qemu/qemu.git
				synced 2025-10-30 01:47:31 +00:00 
			
		
		
		
	 d73415a315
			
		
	
	
		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));
 | |
|     }
 | |
| }
 |