root / aio-win32.c @ 5a37532d
History | View | Annotate | Download (5.8 kB)
1 | a76bab49 | aliguori | /*
|
---|---|---|---|
2 | a76bab49 | aliguori | * QEMU aio implementation
|
3 | a76bab49 | aliguori | *
|
4 | f42b2207 | Paolo Bonzini | * Copyright IBM Corp., 2008
|
5 | f42b2207 | Paolo Bonzini | * Copyright Red Hat Inc., 2012
|
6 | a76bab49 | aliguori | *
|
7 | a76bab49 | aliguori | * Authors:
|
8 | a76bab49 | aliguori | * Anthony Liguori <aliguori@us.ibm.com>
|
9 | f42b2207 | Paolo Bonzini | * Paolo Bonzini <pbonzini@redhat.com>
|
10 | a76bab49 | aliguori | *
|
11 | a76bab49 | aliguori | * This work is licensed under the terms of the GNU GPL, version 2. See
|
12 | a76bab49 | aliguori | * the COPYING file in the top-level directory.
|
13 | a76bab49 | aliguori | *
|
14 | 6b620ca3 | Paolo Bonzini | * Contributions after 2012-01-13 are licensed under the terms of the
|
15 | 6b620ca3 | Paolo Bonzini | * GNU GPL, version 2 or (at your option) any later version.
|
16 | a76bab49 | aliguori | */
|
17 | a76bab49 | aliguori | |
18 | a76bab49 | aliguori | #include "qemu-common.h" |
19 | 737e150e | Paolo Bonzini | #include "block/block.h" |
20 | 1de7afc9 | Paolo Bonzini | #include "qemu/queue.h" |
21 | 1de7afc9 | Paolo Bonzini | #include "qemu/sockets.h" |
22 | a76bab49 | aliguori | |
23 | f42b2207 | Paolo Bonzini | struct AioHandler {
|
24 | f42b2207 | Paolo Bonzini | EventNotifier *e; |
25 | f42b2207 | Paolo Bonzini | EventNotifierHandler *io_notify; |
26 | f42b2207 | Paolo Bonzini | AioFlushEventNotifierHandler *io_flush; |
27 | cd9ba1eb | Paolo Bonzini | GPollFD pfd; |
28 | a76bab49 | aliguori | int deleted;
|
29 | 72cf2d4f | Blue Swirl | QLIST_ENTRY(AioHandler) node; |
30 | a76bab49 | aliguori | }; |
31 | a76bab49 | aliguori | |
32 | f42b2207 | Paolo Bonzini | void aio_set_event_notifier(AioContext *ctx,
|
33 | f42b2207 | Paolo Bonzini | EventNotifier *e, |
34 | f42b2207 | Paolo Bonzini | EventNotifierHandler *io_notify, |
35 | f42b2207 | Paolo Bonzini | AioFlushEventNotifierHandler *io_flush) |
36 | a76bab49 | aliguori | { |
37 | a76bab49 | aliguori | AioHandler *node; |
38 | a76bab49 | aliguori | |
39 | a915f4bc | Paolo Bonzini | QLIST_FOREACH(node, &ctx->aio_handlers, node) { |
40 | f42b2207 | Paolo Bonzini | if (node->e == e && !node->deleted) {
|
41 | f42b2207 | Paolo Bonzini | break;
|
42 | f42b2207 | Paolo Bonzini | } |
43 | a76bab49 | aliguori | } |
44 | a76bab49 | aliguori | |
45 | a76bab49 | aliguori | /* Are we deleting the fd handler? */
|
46 | f42b2207 | Paolo Bonzini | if (!io_notify) {
|
47 | a76bab49 | aliguori | if (node) {
|
48 | e3713e00 | Paolo Bonzini | g_source_remove_poll(&ctx->source, &node->pfd); |
49 | e3713e00 | Paolo Bonzini | |
50 | a76bab49 | aliguori | /* If the lock is held, just mark the node as deleted */
|
51 | cd9ba1eb | Paolo Bonzini | if (ctx->walking_handlers) {
|
52 | a76bab49 | aliguori | node->deleted = 1;
|
53 | cd9ba1eb | Paolo Bonzini | node->pfd.revents = 0;
|
54 | cd9ba1eb | Paolo Bonzini | } else {
|
55 | a76bab49 | aliguori | /* Otherwise, delete it for real. We can't just mark it as
|
56 | a76bab49 | aliguori | * deleted because deleted nodes are only cleaned up after
|
57 | a76bab49 | aliguori | * releasing the walking_handlers lock.
|
58 | a76bab49 | aliguori | */
|
59 | 72cf2d4f | Blue Swirl | QLIST_REMOVE(node, node); |
60 | 7267c094 | Anthony Liguori | g_free(node); |
61 | a76bab49 | aliguori | } |
62 | a76bab49 | aliguori | } |
63 | a76bab49 | aliguori | } else {
|
64 | a76bab49 | aliguori | if (node == NULL) { |
65 | a76bab49 | aliguori | /* Alloc and insert if it's not already there */
|
66 | 7267c094 | Anthony Liguori | node = g_malloc0(sizeof(AioHandler));
|
67 | f42b2207 | Paolo Bonzini | node->e = e; |
68 | f42b2207 | Paolo Bonzini | node->pfd.fd = (uintptr_t)event_notifier_get_handle(e); |
69 | f42b2207 | Paolo Bonzini | node->pfd.events = G_IO_IN; |
70 | a915f4bc | Paolo Bonzini | QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node); |
71 | e3713e00 | Paolo Bonzini | |
72 | e3713e00 | Paolo Bonzini | g_source_add_poll(&ctx->source, &node->pfd); |
73 | a76bab49 | aliguori | } |
74 | a76bab49 | aliguori | /* Update handler with latest information */
|
75 | f42b2207 | Paolo Bonzini | node->io_notify = io_notify; |
76 | a76bab49 | aliguori | node->io_flush = io_flush; |
77 | a76bab49 | aliguori | } |
78 | 7ed2b24c | Paolo Bonzini | |
79 | 7ed2b24c | Paolo Bonzini | aio_notify(ctx); |
80 | 9958c351 | Paolo Bonzini | } |
81 | 9958c351 | Paolo Bonzini | |
82 | cd9ba1eb | Paolo Bonzini | bool aio_pending(AioContext *ctx)
|
83 | cd9ba1eb | Paolo Bonzini | { |
84 | cd9ba1eb | Paolo Bonzini | AioHandler *node; |
85 | cd9ba1eb | Paolo Bonzini | |
86 | cd9ba1eb | Paolo Bonzini | QLIST_FOREACH(node, &ctx->aio_handlers, node) { |
87 | f42b2207 | Paolo Bonzini | if (node->pfd.revents && node->io_notify) {
|
88 | cd9ba1eb | Paolo Bonzini | return true; |
89 | cd9ba1eb | Paolo Bonzini | } |
90 | cd9ba1eb | Paolo Bonzini | } |
91 | cd9ba1eb | Paolo Bonzini | |
92 | cd9ba1eb | Paolo Bonzini | return false; |
93 | cd9ba1eb | Paolo Bonzini | } |
94 | cd9ba1eb | Paolo Bonzini | |
95 | 7c0628b2 | Paolo Bonzini | bool aio_poll(AioContext *ctx, bool blocking) |
96 | a76bab49 | aliguori | { |
97 | 9eb0bfca | Paolo Bonzini | AioHandler *node; |
98 | f42b2207 | Paolo Bonzini | HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
|
99 | 7c0628b2 | Paolo Bonzini | bool busy, progress;
|
100 | f42b2207 | Paolo Bonzini | int count;
|
101 | 7c0628b2 | Paolo Bonzini | |
102 | 7c0628b2 | Paolo Bonzini | progress = false;
|
103 | a76bab49 | aliguori | |
104 | 8febfa26 | Kevin Wolf | /*
|
105 | 8febfa26 | Kevin Wolf | * If there are callbacks left that have been queued, we need to call then.
|
106 | bcdc1857 | Paolo Bonzini | * Do not call select in this case, because it is possible that the caller
|
107 | bcdc1857 | Paolo Bonzini | * does not need a complete flush (as is the case for qemu_aio_wait loops).
|
108 | 8febfa26 | Kevin Wolf | */
|
109 | a915f4bc | Paolo Bonzini | if (aio_bh_poll(ctx)) {
|
110 | 7c0628b2 | Paolo Bonzini | blocking = false;
|
111 | 7c0628b2 | Paolo Bonzini | progress = true;
|
112 | 7c0628b2 | Paolo Bonzini | } |
113 | 7c0628b2 | Paolo Bonzini | |
114 | cd9ba1eb | Paolo Bonzini | /*
|
115 | cd9ba1eb | Paolo Bonzini | * Then dispatch any pending callbacks from the GSource.
|
116 | cd9ba1eb | Paolo Bonzini | *
|
117 | cd9ba1eb | Paolo Bonzini | * We have to walk very carefully in case qemu_aio_set_fd_handler is
|
118 | cd9ba1eb | Paolo Bonzini | * called while we're walking.
|
119 | cd9ba1eb | Paolo Bonzini | */
|
120 | cd9ba1eb | Paolo Bonzini | node = QLIST_FIRST(&ctx->aio_handlers); |
121 | cd9ba1eb | Paolo Bonzini | while (node) {
|
122 | cd9ba1eb | Paolo Bonzini | AioHandler *tmp; |
123 | cd9ba1eb | Paolo Bonzini | |
124 | cd9ba1eb | Paolo Bonzini | ctx->walking_handlers++; |
125 | cd9ba1eb | Paolo Bonzini | |
126 | f42b2207 | Paolo Bonzini | if (node->pfd.revents && node->io_notify) {
|
127 | f42b2207 | Paolo Bonzini | node->pfd.revents = 0;
|
128 | f42b2207 | Paolo Bonzini | node->io_notify(node->e); |
129 | cd9ba1eb | Paolo Bonzini | progress = true;
|
130 | cd9ba1eb | Paolo Bonzini | } |
131 | cd9ba1eb | Paolo Bonzini | |
132 | cd9ba1eb | Paolo Bonzini | tmp = node; |
133 | cd9ba1eb | Paolo Bonzini | node = QLIST_NEXT(node, node); |
134 | cd9ba1eb | Paolo Bonzini | |
135 | cd9ba1eb | Paolo Bonzini | ctx->walking_handlers--; |
136 | cd9ba1eb | Paolo Bonzini | |
137 | cd9ba1eb | Paolo Bonzini | if (!ctx->walking_handlers && tmp->deleted) {
|
138 | cd9ba1eb | Paolo Bonzini | QLIST_REMOVE(tmp, node); |
139 | cd9ba1eb | Paolo Bonzini | g_free(tmp); |
140 | cd9ba1eb | Paolo Bonzini | } |
141 | cd9ba1eb | Paolo Bonzini | } |
142 | cd9ba1eb | Paolo Bonzini | |
143 | 7c0628b2 | Paolo Bonzini | if (progress && !blocking) {
|
144 | bcdc1857 | Paolo Bonzini | return true; |
145 | bafbd6a1 | Paolo Bonzini | } |
146 | 8febfa26 | Kevin Wolf | |
147 | a915f4bc | Paolo Bonzini | ctx->walking_handlers++; |
148 | a76bab49 | aliguori | |
149 | 9eb0bfca | Paolo Bonzini | /* fill fd sets */
|
150 | 9eb0bfca | Paolo Bonzini | busy = false;
|
151 | f42b2207 | Paolo Bonzini | count = 0;
|
152 | a915f4bc | Paolo Bonzini | QLIST_FOREACH(node, &ctx->aio_handlers, node) { |
153 | 9eb0bfca | Paolo Bonzini | /* If there aren't pending AIO operations, don't invoke callbacks.
|
154 | 9eb0bfca | Paolo Bonzini | * Otherwise, if there are no AIO requests, qemu_aio_wait() would
|
155 | 9eb0bfca | Paolo Bonzini | * wait indefinitely.
|
156 | 9eb0bfca | Paolo Bonzini | */
|
157 | 4231c88d | Paolo Bonzini | if (!node->deleted && node->io_flush) {
|
158 | f42b2207 | Paolo Bonzini | if (node->io_flush(node->e) == 0) { |
159 | 9eb0bfca | Paolo Bonzini | continue;
|
160 | a76bab49 | aliguori | } |
161 | 9eb0bfca | Paolo Bonzini | busy = true;
|
162 | 9eb0bfca | Paolo Bonzini | } |
163 | f42b2207 | Paolo Bonzini | if (!node->deleted && node->io_notify) {
|
164 | f42b2207 | Paolo Bonzini | events[count++] = event_notifier_get_handle(node->e); |
165 | 9eb0bfca | Paolo Bonzini | } |
166 | 9eb0bfca | Paolo Bonzini | } |
167 | a76bab49 | aliguori | |
168 | a915f4bc | Paolo Bonzini | ctx->walking_handlers--; |
169 | a76bab49 | aliguori | |
170 | 9eb0bfca | Paolo Bonzini | /* No AIO operations? Get us out of here */
|
171 | 9eb0bfca | Paolo Bonzini | if (!busy) {
|
172 | 7c0628b2 | Paolo Bonzini | return progress;
|
173 | 9eb0bfca | Paolo Bonzini | } |
174 | a76bab49 | aliguori | |
175 | 9eb0bfca | Paolo Bonzini | /* wait until next event */
|
176 | b022b4a4 | Paolo Bonzini | while (count > 0) { |
177 | f42b2207 | Paolo Bonzini | int timeout = blocking ? INFINITE : 0; |
178 | f42b2207 | Paolo Bonzini | int ret = WaitForMultipleObjects(count, events, FALSE, timeout);
|
179 | f42b2207 | Paolo Bonzini | |
180 | f42b2207 | Paolo Bonzini | /* if we have any signaled events, dispatch event */
|
181 | f42b2207 | Paolo Bonzini | if ((DWORD) (ret - WAIT_OBJECT_0) >= count) {
|
182 | f42b2207 | Paolo Bonzini | break;
|
183 | f42b2207 | Paolo Bonzini | } |
184 | f42b2207 | Paolo Bonzini | |
185 | f42b2207 | Paolo Bonzini | blocking = false;
|
186 | 9eb0bfca | Paolo Bonzini | |
187 | 9eb0bfca | Paolo Bonzini | /* we have to walk very carefully in case
|
188 | 9eb0bfca | Paolo Bonzini | * qemu_aio_set_fd_handler is called while we're walking */
|
189 | a915f4bc | Paolo Bonzini | node = QLIST_FIRST(&ctx->aio_handlers); |
190 | 9eb0bfca | Paolo Bonzini | while (node) {
|
191 | 9eb0bfca | Paolo Bonzini | AioHandler *tmp; |
192 | 9eb0bfca | Paolo Bonzini | |
193 | a915f4bc | Paolo Bonzini | ctx->walking_handlers++; |
194 | 2db2bfc0 | Paolo Bonzini | |
195 | 9eb0bfca | Paolo Bonzini | if (!node->deleted &&
|
196 | f42b2207 | Paolo Bonzini | event_notifier_get_handle(node->e) == events[ret - WAIT_OBJECT_0] && |
197 | f42b2207 | Paolo Bonzini | node->io_notify) { |
198 | f42b2207 | Paolo Bonzini | node->io_notify(node->e); |
199 | cd9ba1eb | Paolo Bonzini | progress = true;
|
200 | a76bab49 | aliguori | } |
201 | a76bab49 | aliguori | |
202 | 9eb0bfca | Paolo Bonzini | tmp = node; |
203 | 9eb0bfca | Paolo Bonzini | node = QLIST_NEXT(node, node); |
204 | 9eb0bfca | Paolo Bonzini | |
205 | a915f4bc | Paolo Bonzini | ctx->walking_handlers--; |
206 | 2db2bfc0 | Paolo Bonzini | |
207 | a915f4bc | Paolo Bonzini | if (!ctx->walking_handlers && tmp->deleted) {
|
208 | 9eb0bfca | Paolo Bonzini | QLIST_REMOVE(tmp, node); |
209 | 9eb0bfca | Paolo Bonzini | g_free(tmp); |
210 | 9eb0bfca | Paolo Bonzini | } |
211 | a76bab49 | aliguori | } |
212 | b022b4a4 | Paolo Bonzini | |
213 | b022b4a4 | Paolo Bonzini | /* Try again, but only call each handler once. */
|
214 | b022b4a4 | Paolo Bonzini | events[ret - WAIT_OBJECT_0] = events[--count]; |
215 | 9eb0bfca | Paolo Bonzini | } |
216 | bcdc1857 | Paolo Bonzini | |
217 | 2ea9b58f | Kevin Wolf | assert(progress || busy); |
218 | 2ea9b58f | Kevin Wolf | return true; |
219 | a76bab49 | aliguori | } |