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