1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * epoll(7) file descriptor monitoring
6 #include "qemu/osdep.h"
8 #include "qemu/lockcnt.h"
9 #include "qemu/rcu_queue.h"
10 #include "aio-posix.h"
12 /* The fd number threshold to switch to epoll */
13 #define EPOLL_ENABLE_THRESHOLD 64
15 void fdmon_epoll_disable(AioContext
*ctx
)
17 if (ctx
->epollfd
>= 0) {
23 ctx
->fdmon_ops
= &fdmon_poll_ops
;
26 static inline int epoll_events_from_pfd(int pfd_events
)
28 return (pfd_events
& G_IO_IN
? EPOLLIN
: 0) |
29 (pfd_events
& G_IO_OUT
? EPOLLOUT
: 0) |
30 (pfd_events
& G_IO_HUP
? EPOLLHUP
: 0) |
31 (pfd_events
& G_IO_ERR
? EPOLLERR
: 0);
34 static void fdmon_epoll_update(AioContext
*ctx
,
38 struct epoll_event event
= {
40 .events
= new_node
? epoll_events_from_pfd(new_node
->pfd
.events
) : 0,
45 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_DEL
, old_node
->pfd
.fd
, &event
);
46 } else if (!old_node
) {
47 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_ADD
, new_node
->pfd
.fd
, &event
);
49 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_MOD
, new_node
->pfd
.fd
, &event
);
53 fdmon_epoll_disable(ctx
);
57 static int fdmon_epoll_wait(AioContext
*ctx
, AioHandlerList
*ready_list
,
62 .events
= G_IO_IN
| G_IO_OUT
| G_IO_HUP
| G_IO_ERR
,
66 struct epoll_event events
[128];
69 ret
= qemu_poll_ns(&pfd
, 1, timeout
);
74 if (timeout
<= 0 || ret
> 0) {
75 ret
= epoll_wait(ctx
->epollfd
, events
,
81 for (i
= 0; i
< ret
; i
++) {
82 int ev
= events
[i
].events
;
83 int revents
= (ev
& EPOLLIN
? G_IO_IN
: 0) |
84 (ev
& EPOLLOUT
? G_IO_OUT
: 0) |
85 (ev
& EPOLLHUP
? G_IO_HUP
: 0) |
86 (ev
& EPOLLERR
? G_IO_ERR
: 0);
88 node
= events
[i
].data
.ptr
;
89 aio_add_ready_handler(ready_list
, node
, revents
);
96 static const FDMonOps fdmon_epoll_ops
= {
97 .update
= fdmon_epoll_update
,
98 .wait
= fdmon_epoll_wait
,
99 .need_wait
= aio_poll_disabled
,
102 static bool fdmon_epoll_try_enable(AioContext
*ctx
)
105 struct epoll_event event
;
107 QLIST_FOREACH_RCU(node
, &ctx
->aio_handlers
, node
) {
109 if (QLIST_IS_INSERTED(node
, node_deleted
) || !node
->pfd
.events
) {
112 event
.events
= epoll_events_from_pfd(node
->pfd
.events
);
113 event
.data
.ptr
= node
;
114 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_ADD
, node
->pfd
.fd
, &event
);
120 ctx
->fdmon_ops
= &fdmon_epoll_ops
;
124 bool fdmon_epoll_try_upgrade(AioContext
*ctx
, unsigned npfd
)
128 if (ctx
->epollfd
< 0) {
132 if (npfd
< EPOLL_ENABLE_THRESHOLD
) {
136 /* The list must not change while we add fds to epoll */
137 if (!qemu_lockcnt_dec_if_lock(&ctx
->list_lock
)) {
141 ok
= fdmon_epoll_try_enable(ctx
);
143 qemu_lockcnt_inc_and_unlock(&ctx
->list_lock
);
146 fdmon_epoll_disable(ctx
);
151 void fdmon_epoll_setup(AioContext
*ctx
)
153 ctx
->epollfd
= epoll_create1(EPOLL_CLOEXEC
);
154 if (ctx
->epollfd
== -1) {
155 fprintf(stderr
, "Failed to create epoll instance: %s", strerror(errno
));