master
c 190 lines 5.15 KB
Raw
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * poll(2) file descriptor monitoring
4 *
5 * Uses ppoll(2) when available, g_poll() otherwise.
6 */
7
8 #include "qemu/osdep.h"
9 #include "aio-posix.h"
10 #include "qemu/rcu_queue.h"
11
12 /*
13 * These thread-local variables are used only in fdmon_poll_wait() around the
14 * call to the poll() system call. In particular they are not used while
15 * aio_poll is performing callbacks, which makes it much easier to think about
16 * reentrancy!
17 *
18 * Stack-allocated arrays would be perfect but they have size limitations;
19 * heap allocation is expensive enough that we want to reuse arrays across
20 * calls to aio_poll(). And because poll() has to be called without holding
21 * any lock, the arrays cannot be stored in AioContext. Thread-local data
22 * has none of the disadvantages of these three options.
23 */
24 static __thread GPollFD *pollfds;
25 static __thread AioHandler **nodes;
26 static __thread unsigned npfd, nalloc;
27 static __thread Notifier pollfds_cleanup_notifier;
28
29 static void pollfds_cleanup(Notifier *n, void *unused)
30 {
31 g_assert(npfd == 0);
32 g_free(pollfds);
33 g_free(nodes);
34 nalloc = 0;
35 }
36
37 static void add_pollfd(AioHandler *node)
38 {
39 if (npfd == nalloc) {
40 if (nalloc == 0) {
41 pollfds_cleanup_notifier.notify = pollfds_cleanup;
42 qemu_thread_atexit_add(&pollfds_cleanup_notifier);
43 nalloc = 8;
44 } else {
45 g_assert(nalloc <= INT_MAX);
46 nalloc *= 2;
47 }
48 pollfds = g_renew(GPollFD, pollfds, nalloc);
49 nodes = g_renew(AioHandler *, nodes, nalloc);
50 }
51 nodes[npfd] = node;
52 pollfds[npfd] = (GPollFD) {
53 .fd = node->pfd.fd,
54 .events = node->pfd.events,
55 };
56 npfd++;
57 }
58
59 static int fdmon_poll_wait(AioContext *ctx, AioHandlerList *ready_list,
60 int64_t timeout)
61 {
62 AioHandler *node;
63 int ret;
64
65 assert(npfd == 0);
66
67 QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
68 if (!QLIST_IS_INSERTED(node, node_deleted) && node->pfd.events) {
69 add_pollfd(node);
70 }
71 }
72
73 /* epoll(7) is faster above a certain number of fds */
74 if (fdmon_epoll_try_upgrade(ctx, npfd)) {
75 QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
76 if (!QLIST_IS_INSERTED(node, node_deleted) && node->pfd.events) {
77 g_source_remove_poll(&ctx->source, &node->pfd);
78 }
79 }
80 npfd = 0; /* we won't need pollfds[], reset npfd */
81 return ctx->fdmon_ops->wait(ctx, ready_list, timeout);
82 }
83
84 ret = qemu_poll_ns(pollfds, npfd, timeout);
85 if (ret > 0) {
86 int i;
87
88 for (i = 0; i < npfd; i++) {
89 int revents = pollfds[i].revents;
90
91 if (revents) {
92 aio_add_ready_handler(ready_list, nodes[i], revents);
93 }
94 }
95 }
96
97 npfd = 0;
98 return ret;
99 }
100
101 static void fdmon_poll_update(AioContext *ctx,
102 AioHandler *old_node,
103 AioHandler *new_node)
104 {
105 if (old_node) {
106 /*
107 * If the GSource is in the process of being destroyed then
108 * g_source_remove_poll() causes an assertion failure. Skip removal in
109 * that case, because glib cleans up its state during destruction
110 * anyway.
111 */
112 if (!g_source_is_destroyed(&ctx->source)) {
113 g_source_remove_poll(&ctx->source, &old_node->pfd);
114 }
115 }
116
117 if (new_node) {
118 g_source_add_poll(&ctx->source, &new_node->pfd);
119 }
120 }
121
122 static void fdmon_poll_gsource_prepare(AioContext *ctx)
123 {
124 /* Do nothing */
125 }
126
127 static bool fdmon_poll_gsource_check(AioContext *ctx)
128 {
129 AioHandler *node;
130 bool result = false;
131
132 /*
133 * We have to walk very carefully in case aio_set_fd_handler is
134 * called while we're walking.
135 */
136 qemu_lockcnt_inc(&ctx->list_lock);
137
138 QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
139 int revents = node->pfd.revents & node->pfd.events;
140
141 if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
142 result = true;
143 break;
144 }
145 if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
146 result = true;
147 break;
148 }
149 }
150
151 qemu_lockcnt_dec(&ctx->list_lock);
152
153 return result;
154 }
155
156 static void fdmon_poll_gsource_dispatch(AioContext *ctx,
157 AioHandlerList *ready_list)
158 {
159 AioHandler *node;
160
161 QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
162 int revents = node->pfd.revents;
163
164 if (revents) {
165 aio_add_ready_handler(ready_list, node, revents);
166 }
167 }
168 }
169
170 const FDMonOps fdmon_poll_ops = {
171 .update = fdmon_poll_update,
172 .wait = fdmon_poll_wait,
173 .need_wait = aio_poll_disabled,
174 .gsource_prepare = fdmon_poll_gsource_prepare,
175 .gsource_check = fdmon_poll_gsource_check,
176 .gsource_dispatch = fdmon_poll_gsource_dispatch,
177 };
178
179 void fdmon_poll_downgrade(AioContext *ctx)
180 {
181 AioHandler *node;
182
183 ctx->fdmon_ops = &fdmon_poll_ops;
184
185 QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
186 if (!QLIST_IS_INSERTED(node, node_deleted) && node->pfd.events) {
187 g_source_add_poll(&ctx->source, &node->pfd);
188 }
189 }
190 }