1c2b38b27SPaolo Bonzini /*
2c2b38b27SPaolo Bonzini * QEMU aio implementation
3c2b38b27SPaolo Bonzini *
4c2b38b27SPaolo Bonzini * Copyright IBM Corp., 2008
5c2b38b27SPaolo Bonzini * Copyright Red Hat Inc., 2012
6c2b38b27SPaolo Bonzini *
7c2b38b27SPaolo Bonzini * Authors:
8c2b38b27SPaolo Bonzini * Anthony Liguori <aliguori@us.ibm.com>
9c2b38b27SPaolo Bonzini * Paolo Bonzini <pbonzini@redhat.com>
10c2b38b27SPaolo Bonzini *
11c2b38b27SPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2. See
12c2b38b27SPaolo Bonzini * the COPYING file in the top-level directory.
13c2b38b27SPaolo Bonzini *
14c2b38b27SPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the
15c2b38b27SPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version.
16c2b38b27SPaolo Bonzini */
17c2b38b27SPaolo Bonzini
18c2b38b27SPaolo Bonzini #include "qemu/osdep.h"
19c2b38b27SPaolo Bonzini #include "block/block.h"
20eada6d92SVolker Rümelin #include "qemu/main-loop.h"
21*51483f6cSPeter Maydell #include "qemu/lockcnt.h"
22c2b38b27SPaolo Bonzini #include "qemu/queue.h"
23c2b38b27SPaolo Bonzini #include "qemu/sockets.h"
24c2b38b27SPaolo Bonzini #include "qapi/error.h"
25c2b38b27SPaolo Bonzini #include "qemu/rcu_queue.h"
26e2a3a219SMarc-André Lureau #include "qemu/error-report.h"
27c2b38b27SPaolo Bonzini
28c2b38b27SPaolo Bonzini struct AioHandler {
29c2b38b27SPaolo Bonzini EventNotifier *e;
30c2b38b27SPaolo Bonzini IOHandler *io_read;
31c2b38b27SPaolo Bonzini IOHandler *io_write;
32c2b38b27SPaolo Bonzini EventNotifierHandler *io_notify;
33c2b38b27SPaolo Bonzini GPollFD pfd;
34c2b38b27SPaolo Bonzini int deleted;
35c2b38b27SPaolo Bonzini void *opaque;
36c2b38b27SPaolo Bonzini QLIST_ENTRY(AioHandler) node;
37c2b38b27SPaolo Bonzini };
38c2b38b27SPaolo Bonzini
aio_remove_fd_handler(AioContext * ctx,AioHandler * node)39fef16601SRemy Noel static void aio_remove_fd_handler(AioContext *ctx, AioHandler *node)
40c2b38b27SPaolo Bonzini {
41da0652c0SYonggang Luo /*
42da0652c0SYonggang Luo * If the GSource is in the process of being destroyed then
43da0652c0SYonggang Luo * g_source_remove_poll() causes an assertion failure. Skip
44da0652c0SYonggang Luo * removal in that case, because glib cleans up its state during
45da0652c0SYonggang Luo * destruction anyway.
46da0652c0SYonggang Luo */
47da0652c0SYonggang Luo if (!g_source_is_destroyed(&ctx->source)) {
48da0652c0SYonggang Luo g_source_remove_poll(&ctx->source, &node->pfd);
49da0652c0SYonggang Luo }
50da0652c0SYonggang Luo
51c2b38b27SPaolo Bonzini /* If aio_poll is in progress, just mark the node as deleted */
52c2b38b27SPaolo Bonzini if (qemu_lockcnt_count(&ctx->list_lock)) {
53c2b38b27SPaolo Bonzini node->deleted = 1;
54c2b38b27SPaolo Bonzini node->pfd.revents = 0;
55c2b38b27SPaolo Bonzini } else {
56c2b38b27SPaolo Bonzini /* Otherwise, delete it for real. We can't just mark it as
57c2b38b27SPaolo Bonzini * deleted because deleted nodes are only cleaned up after
58c2b38b27SPaolo Bonzini * releasing the list_lock.
59c2b38b27SPaolo Bonzini */
60c2b38b27SPaolo Bonzini QLIST_REMOVE(node, node);
61c2b38b27SPaolo Bonzini g_free(node);
62c2b38b27SPaolo Bonzini }
63c2b38b27SPaolo Bonzini }
64fef16601SRemy Noel
aio_set_fd_handler(AioContext * ctx,int fd,IOHandler * io_read,IOHandler * io_write,AioPollFn * io_poll,IOHandler * io_poll_ready,void * opaque)65fef16601SRemy Noel void aio_set_fd_handler(AioContext *ctx,
66fef16601SRemy Noel int fd,
67fef16601SRemy Noel IOHandler *io_read,
68fef16601SRemy Noel IOHandler *io_write,
69fef16601SRemy Noel AioPollFn *io_poll,
70826cc324SStefan Hajnoczi IOHandler *io_poll_ready,
71fef16601SRemy Noel void *opaque)
72fef16601SRemy Noel {
73fef16601SRemy Noel AioHandler *old_node;
74fef16601SRemy Noel AioHandler *node = NULL;
75abe34282SMarc-André Lureau SOCKET s;
76fef16601SRemy Noel
77e2a3a219SMarc-André Lureau if (!fd_is_socket(fd)) {
78e2a3a219SMarc-André Lureau error_report("fd=%d is not a socket, AIO implementation is missing", fd);
79e2a3a219SMarc-André Lureau return;
80e2a3a219SMarc-André Lureau }
81e2a3a219SMarc-André Lureau
82abe34282SMarc-André Lureau s = _get_osfhandle(fd);
83abe34282SMarc-André Lureau
84fef16601SRemy Noel qemu_lockcnt_lock(&ctx->list_lock);
85fef16601SRemy Noel QLIST_FOREACH(old_node, &ctx->aio_handlers, node) {
86abe34282SMarc-André Lureau if (old_node->pfd.fd == s && !old_node->deleted) {
87fef16601SRemy Noel break;
88fef16601SRemy Noel }
89fef16601SRemy Noel }
90fef16601SRemy Noel
91fef16601SRemy Noel if (io_read || io_write) {
92c2b38b27SPaolo Bonzini HANDLE event;
9355d41b16SAlistair Francis long bitmask = 0;
94c2b38b27SPaolo Bonzini
95c2b38b27SPaolo Bonzini /* Alloc and insert if it's not already there */
96c2b38b27SPaolo Bonzini node = g_new0(AioHandler, 1);
97abe34282SMarc-André Lureau node->pfd.fd = s;
98c2b38b27SPaolo Bonzini
99c2b38b27SPaolo Bonzini node->pfd.events = 0;
100c2b38b27SPaolo Bonzini if (node->io_read) {
101c2b38b27SPaolo Bonzini node->pfd.events |= G_IO_IN;
102c2b38b27SPaolo Bonzini }
103c2b38b27SPaolo Bonzini if (node->io_write) {
104c2b38b27SPaolo Bonzini node->pfd.events |= G_IO_OUT;
105c2b38b27SPaolo Bonzini }
106c2b38b27SPaolo Bonzini
107c2b38b27SPaolo Bonzini node->e = &ctx->notifier;
108c2b38b27SPaolo Bonzini
109c2b38b27SPaolo Bonzini /* Update handler with latest information */
110c2b38b27SPaolo Bonzini node->opaque = opaque;
111c2b38b27SPaolo Bonzini node->io_read = io_read;
112c2b38b27SPaolo Bonzini node->io_write = io_write;
113c2b38b27SPaolo Bonzini
11455d41b16SAlistair Francis if (io_read) {
11555d41b16SAlistair Francis bitmask |= FD_READ | FD_ACCEPT | FD_CLOSE;
11655d41b16SAlistair Francis }
11755d41b16SAlistair Francis
11855d41b16SAlistair Francis if (io_write) {
11955d41b16SAlistair Francis bitmask |= FD_WRITE | FD_CONNECT;
12055d41b16SAlistair Francis }
12155d41b16SAlistair Francis
122fef16601SRemy Noel QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
123c2b38b27SPaolo Bonzini event = event_notifier_get_handle(&ctx->notifier);
124abe34282SMarc-André Lureau qemu_socket_select(fd, event, bitmask, NULL);
125c2b38b27SPaolo Bonzini }
126fef16601SRemy Noel if (old_node) {
127fef16601SRemy Noel aio_remove_fd_handler(ctx, old_node);
128fef16601SRemy Noel }
129c2b38b27SPaolo Bonzini
130c2b38b27SPaolo Bonzini qemu_lockcnt_unlock(&ctx->list_lock);
131c2b38b27SPaolo Bonzini aio_notify(ctx);
132c2b38b27SPaolo Bonzini }
133c2b38b27SPaolo Bonzini
aio_set_event_notifier(AioContext * ctx,EventNotifier * e,EventNotifierHandler * io_notify,AioPollFn * io_poll,EventNotifierHandler * io_poll_ready)134c2b38b27SPaolo Bonzini void aio_set_event_notifier(AioContext *ctx,
135c2b38b27SPaolo Bonzini EventNotifier *e,
136c2b38b27SPaolo Bonzini EventNotifierHandler *io_notify,
137826cc324SStefan Hajnoczi AioPollFn *io_poll,
138826cc324SStefan Hajnoczi EventNotifierHandler *io_poll_ready)
139c2b38b27SPaolo Bonzini {
140c2b38b27SPaolo Bonzini AioHandler *node;
141c2b38b27SPaolo Bonzini
142c2b38b27SPaolo Bonzini qemu_lockcnt_lock(&ctx->list_lock);
143c2b38b27SPaolo Bonzini QLIST_FOREACH(node, &ctx->aio_handlers, node) {
144c2b38b27SPaolo Bonzini if (node->e == e && !node->deleted) {
145c2b38b27SPaolo Bonzini break;
146c2b38b27SPaolo Bonzini }
147c2b38b27SPaolo Bonzini }
148c2b38b27SPaolo Bonzini
149c2b38b27SPaolo Bonzini /* Are we deleting the fd handler? */
150c2b38b27SPaolo Bonzini if (!io_notify) {
151c2b38b27SPaolo Bonzini if (node) {
152fef16601SRemy Noel aio_remove_fd_handler(ctx, node);
153c2b38b27SPaolo Bonzini }
154c2b38b27SPaolo Bonzini } else {
155c2b38b27SPaolo Bonzini if (node == NULL) {
156c2b38b27SPaolo Bonzini /* Alloc and insert if it's not already there */
157c2b38b27SPaolo Bonzini node = g_new0(AioHandler, 1);
158c2b38b27SPaolo Bonzini node->e = e;
159c2b38b27SPaolo Bonzini node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
160c2b38b27SPaolo Bonzini node->pfd.events = G_IO_IN;
161c2b38b27SPaolo Bonzini QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
162c2b38b27SPaolo Bonzini
163c2b38b27SPaolo Bonzini g_source_add_poll(&ctx->source, &node->pfd);
164c2b38b27SPaolo Bonzini }
165c2b38b27SPaolo Bonzini /* Update handler with latest information */
166c2b38b27SPaolo Bonzini node->io_notify = io_notify;
167c2b38b27SPaolo Bonzini }
168c2b38b27SPaolo Bonzini
169c2b38b27SPaolo Bonzini qemu_lockcnt_unlock(&ctx->list_lock);
170c2b38b27SPaolo Bonzini aio_notify(ctx);
171c2b38b27SPaolo Bonzini }
172c2b38b27SPaolo Bonzini
aio_set_event_notifier_poll(AioContext * ctx,EventNotifier * notifier,EventNotifierHandler * io_poll_begin,EventNotifierHandler * io_poll_end)173c2b38b27SPaolo Bonzini void aio_set_event_notifier_poll(AioContext *ctx,
174c2b38b27SPaolo Bonzini EventNotifier *notifier,
175c2b38b27SPaolo Bonzini EventNotifierHandler *io_poll_begin,
176c2b38b27SPaolo Bonzini EventNotifierHandler *io_poll_end)
177c2b38b27SPaolo Bonzini {
178c2b38b27SPaolo Bonzini /* Not implemented */
179c2b38b27SPaolo Bonzini }
180c2b38b27SPaolo Bonzini
aio_prepare(AioContext * ctx)181c2b38b27SPaolo Bonzini bool aio_prepare(AioContext *ctx)
182c2b38b27SPaolo Bonzini {
183c2b38b27SPaolo Bonzini static struct timeval tv0;
184c2b38b27SPaolo Bonzini AioHandler *node;
185c2b38b27SPaolo Bonzini bool have_select_revents = false;
186c2b38b27SPaolo Bonzini fd_set rfds, wfds;
187c2b38b27SPaolo Bonzini
188c2b38b27SPaolo Bonzini /*
189c2b38b27SPaolo Bonzini * We have to walk very carefully in case aio_set_fd_handler is
190c2b38b27SPaolo Bonzini * called while we're walking.
191c2b38b27SPaolo Bonzini */
192c2b38b27SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock);
193c2b38b27SPaolo Bonzini
194c2b38b27SPaolo Bonzini /* fill fd sets */
195c2b38b27SPaolo Bonzini FD_ZERO(&rfds);
196c2b38b27SPaolo Bonzini FD_ZERO(&wfds);
197c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
198c2b38b27SPaolo Bonzini if (node->io_read) {
199c2b38b27SPaolo Bonzini FD_SET ((SOCKET)node->pfd.fd, &rfds);
200c2b38b27SPaolo Bonzini }
201c2b38b27SPaolo Bonzini if (node->io_write) {
202c2b38b27SPaolo Bonzini FD_SET ((SOCKET)node->pfd.fd, &wfds);
203c2b38b27SPaolo Bonzini }
204c2b38b27SPaolo Bonzini }
205c2b38b27SPaolo Bonzini
206c2b38b27SPaolo Bonzini if (select(0, &rfds, &wfds, NULL, &tv0) > 0) {
207c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
208c2b38b27SPaolo Bonzini node->pfd.revents = 0;
209c2b38b27SPaolo Bonzini if (FD_ISSET(node->pfd.fd, &rfds)) {
210c2b38b27SPaolo Bonzini node->pfd.revents |= G_IO_IN;
211c2b38b27SPaolo Bonzini have_select_revents = true;
212c2b38b27SPaolo Bonzini }
213c2b38b27SPaolo Bonzini
214c2b38b27SPaolo Bonzini if (FD_ISSET(node->pfd.fd, &wfds)) {
215c2b38b27SPaolo Bonzini node->pfd.revents |= G_IO_OUT;
216c2b38b27SPaolo Bonzini have_select_revents = true;
217c2b38b27SPaolo Bonzini }
218c2b38b27SPaolo Bonzini }
219c2b38b27SPaolo Bonzini }
220c2b38b27SPaolo Bonzini
221c2b38b27SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock);
222c2b38b27SPaolo Bonzini return have_select_revents;
223c2b38b27SPaolo Bonzini }
224c2b38b27SPaolo Bonzini
aio_pending(AioContext * ctx)225c2b38b27SPaolo Bonzini bool aio_pending(AioContext *ctx)
226c2b38b27SPaolo Bonzini {
227c2b38b27SPaolo Bonzini AioHandler *node;
228c2b38b27SPaolo Bonzini bool result = false;
229c2b38b27SPaolo Bonzini
230c2b38b27SPaolo Bonzini /*
231c2b38b27SPaolo Bonzini * We have to walk very carefully in case aio_set_fd_handler is
232c2b38b27SPaolo Bonzini * called while we're walking.
233c2b38b27SPaolo Bonzini */
234c2b38b27SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock);
235c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
236c2b38b27SPaolo Bonzini if (node->pfd.revents && node->io_notify) {
237c2b38b27SPaolo Bonzini result = true;
238c2b38b27SPaolo Bonzini break;
239c2b38b27SPaolo Bonzini }
240c2b38b27SPaolo Bonzini
241c2b38b27SPaolo Bonzini if ((node->pfd.revents & G_IO_IN) && node->io_read) {
242c2b38b27SPaolo Bonzini result = true;
243c2b38b27SPaolo Bonzini break;
244c2b38b27SPaolo Bonzini }
245c2b38b27SPaolo Bonzini if ((node->pfd.revents & G_IO_OUT) && node->io_write) {
246c2b38b27SPaolo Bonzini result = true;
247c2b38b27SPaolo Bonzini break;
248c2b38b27SPaolo Bonzini }
249c2b38b27SPaolo Bonzini }
250c2b38b27SPaolo Bonzini
251c2b38b27SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock);
252c2b38b27SPaolo Bonzini return result;
253c2b38b27SPaolo Bonzini }
254c2b38b27SPaolo Bonzini
aio_dispatch_handlers(AioContext * ctx,HANDLE event)255c2b38b27SPaolo Bonzini static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
256c2b38b27SPaolo Bonzini {
257c2b38b27SPaolo Bonzini AioHandler *node;
258c2b38b27SPaolo Bonzini bool progress = false;
259c2b38b27SPaolo Bonzini AioHandler *tmp;
260c2b38b27SPaolo Bonzini
261c2b38b27SPaolo Bonzini /*
262c2b38b27SPaolo Bonzini * We have to walk very carefully in case aio_set_fd_handler is
263c2b38b27SPaolo Bonzini * called while we're walking.
264c2b38b27SPaolo Bonzini */
265c2b38b27SPaolo Bonzini QLIST_FOREACH_SAFE_RCU(node, &ctx->aio_handlers, node, tmp) {
266c2b38b27SPaolo Bonzini int revents = node->pfd.revents;
267c2b38b27SPaolo Bonzini
268c2b38b27SPaolo Bonzini if (!node->deleted &&
269c2b38b27SPaolo Bonzini (revents || event_notifier_get_handle(node->e) == event) &&
270c2b38b27SPaolo Bonzini node->io_notify) {
271c2b38b27SPaolo Bonzini node->pfd.revents = 0;
272c2b38b27SPaolo Bonzini node->io_notify(node->e);
273c2b38b27SPaolo Bonzini
274c2b38b27SPaolo Bonzini /* aio_notify() does not count as progress */
275c2b38b27SPaolo Bonzini if (node->e != &ctx->notifier) {
276c2b38b27SPaolo Bonzini progress = true;
277c2b38b27SPaolo Bonzini }
278c2b38b27SPaolo Bonzini }
279c2b38b27SPaolo Bonzini
280c2b38b27SPaolo Bonzini if (!node->deleted &&
281c2b38b27SPaolo Bonzini (node->io_read || node->io_write)) {
282c2b38b27SPaolo Bonzini node->pfd.revents = 0;
283c2b38b27SPaolo Bonzini if ((revents & G_IO_IN) && node->io_read) {
284c2b38b27SPaolo Bonzini node->io_read(node->opaque);
285c2b38b27SPaolo Bonzini progress = true;
286c2b38b27SPaolo Bonzini }
287c2b38b27SPaolo Bonzini if ((revents & G_IO_OUT) && node->io_write) {
288c2b38b27SPaolo Bonzini node->io_write(node->opaque);
289c2b38b27SPaolo Bonzini progress = true;
290c2b38b27SPaolo Bonzini }
291c2b38b27SPaolo Bonzini
292c2b38b27SPaolo Bonzini /* if the next select() will return an event, we have progressed */
293c2b38b27SPaolo Bonzini if (event == event_notifier_get_handle(&ctx->notifier)) {
294c2b38b27SPaolo Bonzini WSANETWORKEVENTS ev;
295c2b38b27SPaolo Bonzini WSAEnumNetworkEvents(node->pfd.fd, event, &ev);
296c2b38b27SPaolo Bonzini if (ev.lNetworkEvents) {
297c2b38b27SPaolo Bonzini progress = true;
298c2b38b27SPaolo Bonzini }
299c2b38b27SPaolo Bonzini }
300c2b38b27SPaolo Bonzini }
301c2b38b27SPaolo Bonzini
302c2b38b27SPaolo Bonzini if (node->deleted) {
303c2b38b27SPaolo Bonzini if (qemu_lockcnt_dec_if_lock(&ctx->list_lock)) {
304c2b38b27SPaolo Bonzini QLIST_REMOVE(node, node);
305c2b38b27SPaolo Bonzini g_free(node);
306c2b38b27SPaolo Bonzini qemu_lockcnt_inc_and_unlock(&ctx->list_lock);
307c2b38b27SPaolo Bonzini }
308c2b38b27SPaolo Bonzini }
309c2b38b27SPaolo Bonzini }
310c2b38b27SPaolo Bonzini
311c2b38b27SPaolo Bonzini return progress;
312c2b38b27SPaolo Bonzini }
313c2b38b27SPaolo Bonzini
aio_dispatch(AioContext * ctx)314a153bf52SPaolo Bonzini void aio_dispatch(AioContext *ctx)
315c2b38b27SPaolo Bonzini {
316bd451435SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock);
317a153bf52SPaolo Bonzini aio_bh_poll(ctx);
318a153bf52SPaolo Bonzini aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE);
319bd451435SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock);
320a153bf52SPaolo Bonzini timerlistgroup_run_timers(&ctx->tlg);
321c2b38b27SPaolo Bonzini }
322c2b38b27SPaolo Bonzini
aio_poll(AioContext * ctx,bool blocking)323c2b38b27SPaolo Bonzini bool aio_poll(AioContext *ctx, bool blocking)
324c2b38b27SPaolo Bonzini {
325c2b38b27SPaolo Bonzini AioHandler *node;
326e0d034bbSBin Meng HANDLE events[MAXIMUM_WAIT_OBJECTS];
327c2b38b27SPaolo Bonzini bool progress, have_select_revents, first;
328e0d034bbSBin Meng unsigned count;
329c2b38b27SPaolo Bonzini int timeout;
330c2b38b27SPaolo Bonzini
3315710a3e0SPaolo Bonzini /*
3325710a3e0SPaolo Bonzini * There cannot be two concurrent aio_poll calls for the same AioContext (or
3335710a3e0SPaolo Bonzini * an aio_poll concurrent with a GSource prepare/check/dispatch callback).
3345710a3e0SPaolo Bonzini * We rely on this below to avoid slow locked accesses to ctx->notify_me.
335eada6d92SVolker Rümelin *
336eada6d92SVolker Rümelin * aio_poll() may only be called in the AioContext's thread. iohandler_ctx
337eada6d92SVolker Rümelin * is special in that it runs in the main thread, but that thread's context
338eada6d92SVolker Rümelin * is qemu_aio_context.
3395710a3e0SPaolo Bonzini */
340eada6d92SVolker Rümelin assert(in_aio_context_home_thread(ctx == iohandler_get_aio_context() ?
341eada6d92SVolker Rümelin qemu_get_aio_context() : ctx));
342c2b38b27SPaolo Bonzini progress = false;
343c2b38b27SPaolo Bonzini
344c2b38b27SPaolo Bonzini /* aio_notify can avoid the expensive event_notifier_set if
345c2b38b27SPaolo Bonzini * everything (file descriptors, bottom halves, timers) will
346c2b38b27SPaolo Bonzini * be re-evaluated before the next blocking poll(). This is
347c2b38b27SPaolo Bonzini * already true when aio_poll is called with blocking == false;
348c2b38b27SPaolo Bonzini * if blocking == true, it is only true after poll() returns,
349c2b38b27SPaolo Bonzini * so disable the optimization now.
350c2b38b27SPaolo Bonzini */
351c2b38b27SPaolo Bonzini if (blocking) {
352d73415a3SStefan Hajnoczi qatomic_set(&ctx->notify_me, qatomic_read(&ctx->notify_me) + 2);
3535710a3e0SPaolo Bonzini /*
3545710a3e0SPaolo Bonzini * Write ctx->notify_me before computing the timeout
3555710a3e0SPaolo Bonzini * (reading bottom half flags, etc.). Pairs with
3565710a3e0SPaolo Bonzini * smp_mb in aio_notify().
3575710a3e0SPaolo Bonzini */
3585710a3e0SPaolo Bonzini smp_mb();
359c2b38b27SPaolo Bonzini }
360c2b38b27SPaolo Bonzini
361c2b38b27SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock);
362c2b38b27SPaolo Bonzini have_select_revents = aio_prepare(ctx);
363c2b38b27SPaolo Bonzini
364c2b38b27SPaolo Bonzini /* fill fd sets */
365c2b38b27SPaolo Bonzini count = 0;
366c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
36760f782b6SStefan Hajnoczi if (!node->deleted && node->io_notify) {
368e0d034bbSBin Meng assert(count < MAXIMUM_WAIT_OBJECTS);
369c2b38b27SPaolo Bonzini events[count++] = event_notifier_get_handle(node->e);
370c2b38b27SPaolo Bonzini }
371c2b38b27SPaolo Bonzini }
372c2b38b27SPaolo Bonzini
373c2b38b27SPaolo Bonzini first = true;
374c2b38b27SPaolo Bonzini
375c2b38b27SPaolo Bonzini /* ctx->notifier is always registered. */
376c2b38b27SPaolo Bonzini assert(count > 0);
377c2b38b27SPaolo Bonzini
378c2b38b27SPaolo Bonzini /* Multiple iterations, all of them non-blocking except the first,
379c2b38b27SPaolo Bonzini * may be necessary to process all pending events. After the first
380c2b38b27SPaolo Bonzini * WaitForMultipleObjects call ctx->notify_me will be decremented.
381c2b38b27SPaolo Bonzini */
382c2b38b27SPaolo Bonzini do {
383c2b38b27SPaolo Bonzini HANDLE event;
384c2b38b27SPaolo Bonzini int ret;
385c2b38b27SPaolo Bonzini
386c2b38b27SPaolo Bonzini timeout = blocking && !have_select_revents
387c2b38b27SPaolo Bonzini ? qemu_timeout_ns_to_ms(aio_compute_timeout(ctx)) : 0;
388c2b38b27SPaolo Bonzini ret = WaitForMultipleObjects(count, events, FALSE, timeout);
389c2b38b27SPaolo Bonzini if (blocking) {
390c2b38b27SPaolo Bonzini assert(first);
391d73415a3SStefan Hajnoczi qatomic_store_release(&ctx->notify_me,
392d73415a3SStefan Hajnoczi qatomic_read(&ctx->notify_me) - 2);
393b37548fcSFam Zheng aio_notify_accept(ctx);
394c2b38b27SPaolo Bonzini }
395c2b38b27SPaolo Bonzini
396c2b38b27SPaolo Bonzini if (first) {
397c2b38b27SPaolo Bonzini progress |= aio_bh_poll(ctx);
398c2b38b27SPaolo Bonzini first = false;
399c2b38b27SPaolo Bonzini }
400c2b38b27SPaolo Bonzini
401c2b38b27SPaolo Bonzini /* if we have any signaled events, dispatch event */
402c2b38b27SPaolo Bonzini event = NULL;
403c2b38b27SPaolo Bonzini if ((DWORD) (ret - WAIT_OBJECT_0) < count) {
404c2b38b27SPaolo Bonzini event = events[ret - WAIT_OBJECT_0];
405c2b38b27SPaolo Bonzini events[ret - WAIT_OBJECT_0] = events[--count];
406c2b38b27SPaolo Bonzini } else if (!have_select_revents) {
407c2b38b27SPaolo Bonzini break;
408c2b38b27SPaolo Bonzini }
409c2b38b27SPaolo Bonzini
410c2b38b27SPaolo Bonzini have_select_revents = false;
411c2b38b27SPaolo Bonzini blocking = false;
412c2b38b27SPaolo Bonzini
413c2b38b27SPaolo Bonzini progress |= aio_dispatch_handlers(ctx, event);
414c2b38b27SPaolo Bonzini } while (count > 0);
415c2b38b27SPaolo Bonzini
416bd451435SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock);
417bd451435SPaolo Bonzini
418c2b38b27SPaolo Bonzini progress |= timerlistgroup_run_timers(&ctx->tlg);
419c2b38b27SPaolo Bonzini return progress;
420c2b38b27SPaolo Bonzini }
421c2b38b27SPaolo Bonzini
aio_context_setup(AioContext * ctx)422c2b38b27SPaolo Bonzini void aio_context_setup(AioContext *ctx)
423c2b38b27SPaolo Bonzini {
424c2b38b27SPaolo Bonzini }
425c2b38b27SPaolo Bonzini
aio_context_destroy(AioContext * ctx)426cd0a6d2bSJie Wang void aio_context_destroy(AioContext *ctx)
427cd0a6d2bSJie Wang {
428cd0a6d2bSJie Wang }
429cd0a6d2bSJie Wang
aio_context_use_g_source(AioContext * ctx)430ba607ca8SStefan Hajnoczi void aio_context_use_g_source(AioContext *ctx)
431ba607ca8SStefan Hajnoczi {
432ba607ca8SStefan Hajnoczi }
433ba607ca8SStefan Hajnoczi
aio_context_set_poll_params(AioContext * ctx,int64_t max_ns,int64_t grow,int64_t shrink,Error ** errp)434c2b38b27SPaolo Bonzini void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
435c2b38b27SPaolo Bonzini int64_t grow, int64_t shrink, Error **errp)
436c2b38b27SPaolo Bonzini {
43790c558beSPeter Xu if (max_ns) {
438c2b38b27SPaolo Bonzini error_setg(errp, "AioContext polling is not implemented on Windows");
439c2b38b27SPaolo Bonzini }
44090c558beSPeter Xu }
4411793ad02SStefano Garzarella
aio_context_set_aio_params(AioContext * ctx,int64_t max_batch)442897a06c6SPhilippe Mathieu-Daudé void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch)
4431793ad02SStefano Garzarella {
4441793ad02SStefano Garzarella }
445