1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * epoll(7) file descriptor monitoring
6 #include "qemu/osdep.h"
8 #include "qemu/rcu_queue.h"
11 /* The fd number threshold to switch to epoll */
12 #define EPOLL_ENABLE_THRESHOLD 64
14 void fdmon_epoll_disable(AioContext
*ctx
)
16 if (ctx
->epollfd
>= 0) {
22 ctx
->fdmon_ops
= &fdmon_poll_ops
;
25 static inline int epoll_events_from_pfd(int pfd_events
)
27 return (pfd_events
& G_IO_IN
? EPOLLIN
: 0) |
28 (pfd_events
& G_IO_OUT
? EPOLLOUT
: 0) |
29 (pfd_events
& G_IO_HUP
? EPOLLHUP
: 0) |
30 (pfd_events
& G_IO_ERR
? EPOLLERR
: 0);
33 static void fdmon_epoll_update(AioContext
*ctx
,
37 struct epoll_event event
= {
39 .events
= new_node
? epoll_events_from_pfd(new_node
->pfd
.events
) : 0,
44 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_DEL
, old_node
->pfd
.fd
, &event
);
45 } else if (!old_node
) {
46 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_ADD
, new_node
->pfd
.fd
, &event
);
48 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_MOD
, new_node
->pfd
.fd
, &event
);
52 fdmon_epoll_disable(ctx
);
56 static int fdmon_epoll_wait(AioContext
*ctx
, AioHandlerList
*ready_list
,
61 .events
= G_IO_IN
| G_IO_OUT
| G_IO_HUP
| G_IO_ERR
,
65 struct epoll_event events
[128];
68 ret
= qemu_poll_ns(&pfd
, 1, timeout
);
73 if (timeout
<= 0 || ret
> 0) {
74 ret
= epoll_wait(ctx
->epollfd
, events
,
80 for (i
= 0; i
< ret
; i
++) {
81 int ev
= events
[i
].events
;
82 int revents
= (ev
& EPOLLIN
? G_IO_IN
: 0) |
83 (ev
& EPOLLOUT
? G_IO_OUT
: 0) |
84 (ev
& EPOLLHUP
? G_IO_HUP
: 0) |
85 (ev
& EPOLLERR
? G_IO_ERR
: 0);
87 node
= events
[i
].data
.ptr
;
88 aio_add_ready_handler(ready_list
, node
, revents
);
95 static const FDMonOps fdmon_epoll_ops
= {
96 .update
= fdmon_epoll_update
,
97 .wait
= fdmon_epoll_wait
,
98 .need_wait
= aio_poll_disabled
,
101 static bool fdmon_epoll_try_enable(AioContext
*ctx
)
104 struct epoll_event event
;
106 QLIST_FOREACH_RCU(node
, &ctx
->aio_handlers
, node
) {
108 if (QLIST_IS_INSERTED(node
, node_deleted
) || !node
->pfd
.events
) {
111 event
.events
= epoll_events_from_pfd(node
->pfd
.events
);
112 event
.data
.ptr
= node
;
113 r
= epoll_ctl(ctx
->epollfd
, EPOLL_CTL_ADD
, node
->pfd
.fd
, &event
);
119 ctx
->fdmon_ops
= &fdmon_epoll_ops
;
123 bool fdmon_epoll_try_upgrade(AioContext
*ctx
, unsigned npfd
)
127 if (ctx
->epollfd
< 0) {
131 if (npfd
< EPOLL_ENABLE_THRESHOLD
) {
135 /* The list must not change while we add fds to epoll */
136 if (!qemu_lockcnt_dec_if_lock(&ctx
->list_lock
)) {
140 ok
= fdmon_epoll_try_enable(ctx
);
142 qemu_lockcnt_inc_and_unlock(&ctx
->list_lock
);
145 fdmon_epoll_disable(ctx
);
150 void fdmon_epoll_setup(AioContext
*ctx
)
152 ctx
->epollfd
= epoll_create1(EPOLL_CLOEXEC
);
153 if (ctx
->epollfd
== -1) {
154 fprintf(stderr
, "Failed to create epoll instance: %s", strerror(errno
));