root / aio-posix.c @ feature-archipelago
History | View | Annotate | Download (6.2 kB)
1 | a76bab49 | aliguori | /*
|
---|---|---|---|
2 | a76bab49 | aliguori | * QEMU aio implementation
|
3 | a76bab49 | aliguori | *
|
4 | a76bab49 | aliguori | * Copyright IBM, Corp. 2008
|
5 | a76bab49 | aliguori | *
|
6 | a76bab49 | aliguori | * Authors:
|
7 | a76bab49 | aliguori | * Anthony Liguori <aliguori@us.ibm.com>
|
8 | a76bab49 | aliguori | *
|
9 | a76bab49 | aliguori | * This work is licensed under the terms of the GNU GPL, version 2. See
|
10 | a76bab49 | aliguori | * the COPYING file in the top-level directory.
|
11 | a76bab49 | aliguori | *
|
12 | 6b620ca3 | Paolo Bonzini | * Contributions after 2012-01-13 are licensed under the terms of the
|
13 | 6b620ca3 | Paolo Bonzini | * GNU GPL, version 2 or (at your option) any later version.
|
14 | a76bab49 | aliguori | */
|
15 | a76bab49 | aliguori | |
16 | a76bab49 | aliguori | #include "qemu-common.h" |
17 | 737e150e | Paolo Bonzini | #include "block/block.h" |
18 | 1de7afc9 | Paolo Bonzini | #include "qemu/queue.h" |
19 | 1de7afc9 | Paolo Bonzini | #include "qemu/sockets.h" |
20 | a76bab49 | aliguori | |
21 | a76bab49 | aliguori | struct AioHandler
|
22 | a76bab49 | aliguori | { |
23 | cd9ba1eb | Paolo Bonzini | GPollFD pfd; |
24 | a76bab49 | aliguori | IOHandler *io_read; |
25 | a76bab49 | aliguori | IOHandler *io_write; |
26 | a76bab49 | aliguori | int deleted;
|
27 | 6b5f8762 | Stefan Hajnoczi | int pollfds_idx;
|
28 | a76bab49 | aliguori | void *opaque;
|
29 | 72cf2d4f | Blue Swirl | QLIST_ENTRY(AioHandler) node; |
30 | a76bab49 | aliguori | }; |
31 | a76bab49 | aliguori | |
32 | a915f4bc | Paolo Bonzini | static AioHandler *find_aio_handler(AioContext *ctx, int fd) |
33 | a76bab49 | aliguori | { |
34 | a76bab49 | aliguori | AioHandler *node; |
35 | a76bab49 | aliguori | |
36 | a915f4bc | Paolo Bonzini | QLIST_FOREACH(node, &ctx->aio_handlers, node) { |
37 | cd9ba1eb | Paolo Bonzini | if (node->pfd.fd == fd)
|
38 | 79d5ca56 | Alexander Graf | if (!node->deleted)
|
39 | 79d5ca56 | Alexander Graf | return node;
|
40 | a76bab49 | aliguori | } |
41 | a76bab49 | aliguori | |
42 | a76bab49 | aliguori | return NULL; |
43 | a76bab49 | aliguori | } |
44 | a76bab49 | aliguori | |
45 | a915f4bc | Paolo Bonzini | void aio_set_fd_handler(AioContext *ctx,
|
46 | a915f4bc | Paolo Bonzini | int fd,
|
47 | a915f4bc | Paolo Bonzini | IOHandler *io_read, |
48 | a915f4bc | Paolo Bonzini | IOHandler *io_write, |
49 | a915f4bc | Paolo Bonzini | void *opaque)
|
50 | a76bab49 | aliguori | { |
51 | a76bab49 | aliguori | AioHandler *node; |
52 | a76bab49 | aliguori | |
53 | a915f4bc | Paolo Bonzini | node = find_aio_handler(ctx, fd); |
54 | a76bab49 | aliguori | |
55 | a76bab49 | aliguori | /* Are we deleting the fd handler? */
|
56 | a76bab49 | aliguori | if (!io_read && !io_write) {
|
57 | a76bab49 | aliguori | if (node) {
|
58 | e3713e00 | Paolo Bonzini | g_source_remove_poll(&ctx->source, &node->pfd); |
59 | e3713e00 | Paolo Bonzini | |
60 | a76bab49 | aliguori | /* If the lock is held, just mark the node as deleted */
|
61 | cd9ba1eb | Paolo Bonzini | if (ctx->walking_handlers) {
|
62 | a76bab49 | aliguori | node->deleted = 1;
|
63 | cd9ba1eb | Paolo Bonzini | node->pfd.revents = 0;
|
64 | cd9ba1eb | Paolo Bonzini | } else {
|
65 | a76bab49 | aliguori | /* Otherwise, delete it for real. We can't just mark it as
|
66 | a76bab49 | aliguori | * deleted because deleted nodes are only cleaned up after
|
67 | a76bab49 | aliguori | * releasing the walking_handlers lock.
|
68 | a76bab49 | aliguori | */
|
69 | 72cf2d4f | Blue Swirl | QLIST_REMOVE(node, node); |
70 | 7267c094 | Anthony Liguori | g_free(node); |
71 | a76bab49 | aliguori | } |
72 | a76bab49 | aliguori | } |
73 | a76bab49 | aliguori | } else {
|
74 | a76bab49 | aliguori | if (node == NULL) { |
75 | a76bab49 | aliguori | /* Alloc and insert if it's not already there */
|
76 | 7267c094 | Anthony Liguori | node = g_malloc0(sizeof(AioHandler));
|
77 | cd9ba1eb | Paolo Bonzini | node->pfd.fd = fd; |
78 | a915f4bc | Paolo Bonzini | QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node); |
79 | e3713e00 | Paolo Bonzini | |
80 | e3713e00 | Paolo Bonzini | g_source_add_poll(&ctx->source, &node->pfd); |
81 | a76bab49 | aliguori | } |
82 | a76bab49 | aliguori | /* Update handler with latest information */
|
83 | a76bab49 | aliguori | node->io_read = io_read; |
84 | a76bab49 | aliguori | node->io_write = io_write; |
85 | a76bab49 | aliguori | node->opaque = opaque; |
86 | 6b5f8762 | Stefan Hajnoczi | node->pollfds_idx = -1;
|
87 | cd9ba1eb | Paolo Bonzini | |
88 | b5a01a70 | Stefan Hajnoczi | node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
|
89 | b5a01a70 | Stefan Hajnoczi | node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
|
90 | a76bab49 | aliguori | } |
91 | 7ed2b24c | Paolo Bonzini | |
92 | 7ed2b24c | Paolo Bonzini | aio_notify(ctx); |
93 | 9958c351 | Paolo Bonzini | } |
94 | 9958c351 | Paolo Bonzini | |
95 | a915f4bc | Paolo Bonzini | void aio_set_event_notifier(AioContext *ctx,
|
96 | a915f4bc | Paolo Bonzini | EventNotifier *notifier, |
97 | f2e5dca4 | Stefan Hajnoczi | EventNotifierHandler *io_read) |
98 | a76bab49 | aliguori | { |
99 | a915f4bc | Paolo Bonzini | aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), |
100 | f2e5dca4 | Stefan Hajnoczi | (IOHandler *)io_read, NULL, notifier);
|
101 | a76bab49 | aliguori | } |
102 | a76bab49 | aliguori | |
103 | cd9ba1eb | Paolo Bonzini | bool aio_pending(AioContext *ctx)
|
104 | cd9ba1eb | Paolo Bonzini | { |
105 | cd9ba1eb | Paolo Bonzini | AioHandler *node; |
106 | cd9ba1eb | Paolo Bonzini | |
107 | cd9ba1eb | Paolo Bonzini | QLIST_FOREACH(node, &ctx->aio_handlers, node) { |
108 | cd9ba1eb | Paolo Bonzini | int revents;
|
109 | cd9ba1eb | Paolo Bonzini | |
110 | cd9ba1eb | Paolo Bonzini | revents = node->pfd.revents & node->pfd.events; |
111 | cd9ba1eb | Paolo Bonzini | if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
|
112 | cd9ba1eb | Paolo Bonzini | return true; |
113 | cd9ba1eb | Paolo Bonzini | } |
114 | cd9ba1eb | Paolo Bonzini | if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
|
115 | cd9ba1eb | Paolo Bonzini | return true; |
116 | cd9ba1eb | Paolo Bonzini | } |
117 | cd9ba1eb | Paolo Bonzini | } |
118 | cd9ba1eb | Paolo Bonzini | |
119 | cd9ba1eb | Paolo Bonzini | return false; |
120 | cd9ba1eb | Paolo Bonzini | } |
121 | cd9ba1eb | Paolo Bonzini | |
122 | d0c8d2c0 | Stefan Hajnoczi | static bool aio_dispatch(AioContext *ctx) |
123 | a76bab49 | aliguori | { |
124 | 9eb0bfca | Paolo Bonzini | AioHandler *node; |
125 | d0c8d2c0 | Stefan Hajnoczi | bool progress = false; |
126 | 7c0628b2 | Paolo Bonzini | |
127 | cd9ba1eb | Paolo Bonzini | /*
|
128 | cd9ba1eb | Paolo Bonzini | * We have to walk very carefully in case qemu_aio_set_fd_handler is
|
129 | cd9ba1eb | Paolo Bonzini | * called while we're walking.
|
130 | cd9ba1eb | Paolo Bonzini | */
|
131 | cd9ba1eb | Paolo Bonzini | node = QLIST_FIRST(&ctx->aio_handlers); |
132 | cd9ba1eb | Paolo Bonzini | while (node) {
|
133 | cd9ba1eb | Paolo Bonzini | AioHandler *tmp; |
134 | cd9ba1eb | Paolo Bonzini | int revents;
|
135 | cd9ba1eb | Paolo Bonzini | |
136 | cd9ba1eb | Paolo Bonzini | ctx->walking_handlers++; |
137 | cd9ba1eb | Paolo Bonzini | |
138 | cd9ba1eb | Paolo Bonzini | revents = node->pfd.revents & node->pfd.events; |
139 | cd9ba1eb | Paolo Bonzini | node->pfd.revents = 0;
|
140 | cd9ba1eb | Paolo Bonzini | |
141 | d0c8d2c0 | Stefan Hajnoczi | if (!node->deleted &&
|
142 | d0c8d2c0 | Stefan Hajnoczi | (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) && |
143 | d0c8d2c0 | Stefan Hajnoczi | node->io_read) { |
144 | cd9ba1eb | Paolo Bonzini | node->io_read(node->opaque); |
145 | 164a101f | Stefan Hajnoczi | |
146 | 164a101f | Stefan Hajnoczi | /* aio_notify() does not count as progress */
|
147 | 164a101f | Stefan Hajnoczi | if (node->opaque != &ctx->notifier) {
|
148 | 164a101f | Stefan Hajnoczi | progress = true;
|
149 | 164a101f | Stefan Hajnoczi | } |
150 | cd9ba1eb | Paolo Bonzini | } |
151 | d0c8d2c0 | Stefan Hajnoczi | if (!node->deleted &&
|
152 | d0c8d2c0 | Stefan Hajnoczi | (revents & (G_IO_OUT | G_IO_ERR)) && |
153 | d0c8d2c0 | Stefan Hajnoczi | node->io_write) { |
154 | cd9ba1eb | Paolo Bonzini | node->io_write(node->opaque); |
155 | cd9ba1eb | Paolo Bonzini | progress = true;
|
156 | cd9ba1eb | Paolo Bonzini | } |
157 | cd9ba1eb | Paolo Bonzini | |
158 | cd9ba1eb | Paolo Bonzini | tmp = node; |
159 | cd9ba1eb | Paolo Bonzini | node = QLIST_NEXT(node, node); |
160 | cd9ba1eb | Paolo Bonzini | |
161 | cd9ba1eb | Paolo Bonzini | ctx->walking_handlers--; |
162 | cd9ba1eb | Paolo Bonzini | |
163 | cd9ba1eb | Paolo Bonzini | if (!ctx->walking_handlers && tmp->deleted) {
|
164 | cd9ba1eb | Paolo Bonzini | QLIST_REMOVE(tmp, node); |
165 | cd9ba1eb | Paolo Bonzini | g_free(tmp); |
166 | cd9ba1eb | Paolo Bonzini | } |
167 | cd9ba1eb | Paolo Bonzini | } |
168 | 438e1f47 | Alex Bligh | |
169 | 438e1f47 | Alex Bligh | /* Run our timers */
|
170 | 438e1f47 | Alex Bligh | progress |= timerlistgroup_run_timers(&ctx->tlg); |
171 | 438e1f47 | Alex Bligh | |
172 | d0c8d2c0 | Stefan Hajnoczi | return progress;
|
173 | d0c8d2c0 | Stefan Hajnoczi | } |
174 | d0c8d2c0 | Stefan Hajnoczi | |
175 | d0c8d2c0 | Stefan Hajnoczi | bool aio_poll(AioContext *ctx, bool blocking) |
176 | d0c8d2c0 | Stefan Hajnoczi | { |
177 | d0c8d2c0 | Stefan Hajnoczi | AioHandler *node; |
178 | d0c8d2c0 | Stefan Hajnoczi | int ret;
|
179 | 164a101f | Stefan Hajnoczi | bool progress;
|
180 | d0c8d2c0 | Stefan Hajnoczi | |
181 | d0c8d2c0 | Stefan Hajnoczi | progress = false;
|
182 | d0c8d2c0 | Stefan Hajnoczi | |
183 | d0c8d2c0 | Stefan Hajnoczi | /*
|
184 | d0c8d2c0 | Stefan Hajnoczi | * If there are callbacks left that have been queued, we need to call them.
|
185 | d0c8d2c0 | Stefan Hajnoczi | * Do not call select in this case, because it is possible that the caller
|
186 | d0c8d2c0 | Stefan Hajnoczi | * does not need a complete flush (as is the case for qemu_aio_wait loops).
|
187 | d0c8d2c0 | Stefan Hajnoczi | */
|
188 | d0c8d2c0 | Stefan Hajnoczi | if (aio_bh_poll(ctx)) {
|
189 | d0c8d2c0 | Stefan Hajnoczi | blocking = false;
|
190 | d0c8d2c0 | Stefan Hajnoczi | progress = true;
|
191 | d0c8d2c0 | Stefan Hajnoczi | } |
192 | d0c8d2c0 | Stefan Hajnoczi | |
193 | d0c8d2c0 | Stefan Hajnoczi | if (aio_dispatch(ctx)) {
|
194 | d0c8d2c0 | Stefan Hajnoczi | progress = true;
|
195 | d0c8d2c0 | Stefan Hajnoczi | } |
196 | cd9ba1eb | Paolo Bonzini | |
197 | 7c0628b2 | Paolo Bonzini | if (progress && !blocking) {
|
198 | bcdc1857 | Paolo Bonzini | return true; |
199 | bafbd6a1 | Paolo Bonzini | } |
200 | 8febfa26 | Kevin Wolf | |
201 | a915f4bc | Paolo Bonzini | ctx->walking_handlers++; |
202 | a76bab49 | aliguori | |
203 | 6b5f8762 | Stefan Hajnoczi | g_array_set_size(ctx->pollfds, 0);
|
204 | a76bab49 | aliguori | |
205 | 6b5f8762 | Stefan Hajnoczi | /* fill pollfds */
|
206 | a915f4bc | Paolo Bonzini | QLIST_FOREACH(node, &ctx->aio_handlers, node) { |
207 | 6b5f8762 | Stefan Hajnoczi | node->pollfds_idx = -1;
|
208 | 6b5f8762 | Stefan Hajnoczi | if (!node->deleted && node->pfd.events) {
|
209 | 6b5f8762 | Stefan Hajnoczi | GPollFD pfd = { |
210 | 6b5f8762 | Stefan Hajnoczi | .fd = node->pfd.fd, |
211 | 6b5f8762 | Stefan Hajnoczi | .events = node->pfd.events, |
212 | 6b5f8762 | Stefan Hajnoczi | }; |
213 | 6b5f8762 | Stefan Hajnoczi | node->pollfds_idx = ctx->pollfds->len; |
214 | 6b5f8762 | Stefan Hajnoczi | g_array_append_val(ctx->pollfds, pfd); |
215 | 9eb0bfca | Paolo Bonzini | } |
216 | 9eb0bfca | Paolo Bonzini | } |
217 | a76bab49 | aliguori | |
218 | a915f4bc | Paolo Bonzini | ctx->walking_handlers--; |
219 | a76bab49 | aliguori | |
220 | 9eb0bfca | Paolo Bonzini | /* wait until next event */
|
221 | 438e1f47 | Alex Bligh | ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data, |
222 | 438e1f47 | Alex Bligh | ctx->pollfds->len, |
223 | 438e1f47 | Alex Bligh | blocking ? timerlistgroup_deadline_ns(&ctx->tlg) : 0);
|
224 | 9eb0bfca | Paolo Bonzini | |
225 | 9eb0bfca | Paolo Bonzini | /* if we have any readable fds, dispatch event */
|
226 | 9eb0bfca | Paolo Bonzini | if (ret > 0) { |
227 | 6b5f8762 | Stefan Hajnoczi | QLIST_FOREACH(node, &ctx->aio_handlers, node) { |
228 | 6b5f8762 | Stefan Hajnoczi | if (node->pollfds_idx != -1) { |
229 | 6b5f8762 | Stefan Hajnoczi | GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD, |
230 | 6b5f8762 | Stefan Hajnoczi | node->pollfds_idx); |
231 | 6b5f8762 | Stefan Hajnoczi | node->pfd.revents = pfd->revents; |
232 | 9eb0bfca | Paolo Bonzini | } |
233 | a76bab49 | aliguori | } |
234 | 438e1f47 | Alex Bligh | } |
235 | 438e1f47 | Alex Bligh | |
236 | 438e1f47 | Alex Bligh | /* Run dispatch even if there were no readable fds to run timers */
|
237 | 438e1f47 | Alex Bligh | if (aio_dispatch(ctx)) {
|
238 | 438e1f47 | Alex Bligh | progress = true;
|
239 | 9eb0bfca | Paolo Bonzini | } |
240 | bcdc1857 | Paolo Bonzini | |
241 | 164a101f | Stefan Hajnoczi | return progress;
|
242 | a76bab49 | aliguori | } |