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 "qemu-common.h" 20c2b38b27SPaolo Bonzini #include "block/block.h" 21*eada6d92SVolker Rümelin #include "qemu/main-loop.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" 26c2b38b27SPaolo Bonzini 27c2b38b27SPaolo Bonzini struct AioHandler { 28c2b38b27SPaolo Bonzini EventNotifier *e; 29c2b38b27SPaolo Bonzini IOHandler *io_read; 30c2b38b27SPaolo Bonzini IOHandler *io_write; 31c2b38b27SPaolo Bonzini EventNotifierHandler *io_notify; 32c2b38b27SPaolo Bonzini GPollFD pfd; 33c2b38b27SPaolo Bonzini int deleted; 34c2b38b27SPaolo Bonzini void *opaque; 35c2b38b27SPaolo Bonzini bool is_external; 36c2b38b27SPaolo Bonzini QLIST_ENTRY(AioHandler) node; 37c2b38b27SPaolo Bonzini }; 38c2b38b27SPaolo Bonzini 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 65fef16601SRemy Noel void aio_set_fd_handler(AioContext *ctx, 66fef16601SRemy Noel int fd, 67fef16601SRemy Noel bool is_external, 68fef16601SRemy Noel IOHandler *io_read, 69fef16601SRemy Noel IOHandler *io_write, 70fef16601SRemy Noel AioPollFn *io_poll, 71fef16601SRemy Noel void *opaque) 72fef16601SRemy Noel { 73fef16601SRemy Noel /* fd is a SOCKET in our case */ 74fef16601SRemy Noel AioHandler *old_node; 75fef16601SRemy Noel AioHandler *node = NULL; 76fef16601SRemy Noel 77fef16601SRemy Noel qemu_lockcnt_lock(&ctx->list_lock); 78fef16601SRemy Noel QLIST_FOREACH(old_node, &ctx->aio_handlers, node) { 79fef16601SRemy Noel if (old_node->pfd.fd == fd && !old_node->deleted) { 80fef16601SRemy Noel break; 81fef16601SRemy Noel } 82fef16601SRemy Noel } 83fef16601SRemy Noel 84fef16601SRemy Noel if (io_read || io_write) { 85c2b38b27SPaolo Bonzini HANDLE event; 8655d41b16SAlistair Francis long bitmask = 0; 87c2b38b27SPaolo Bonzini 88c2b38b27SPaolo Bonzini /* Alloc and insert if it's not already there */ 89c2b38b27SPaolo Bonzini node = g_new0(AioHandler, 1); 90c2b38b27SPaolo Bonzini node->pfd.fd = fd; 91c2b38b27SPaolo Bonzini 92c2b38b27SPaolo Bonzini node->pfd.events = 0; 93c2b38b27SPaolo Bonzini if (node->io_read) { 94c2b38b27SPaolo Bonzini node->pfd.events |= G_IO_IN; 95c2b38b27SPaolo Bonzini } 96c2b38b27SPaolo Bonzini if (node->io_write) { 97c2b38b27SPaolo Bonzini node->pfd.events |= G_IO_OUT; 98c2b38b27SPaolo Bonzini } 99c2b38b27SPaolo Bonzini 100c2b38b27SPaolo Bonzini node->e = &ctx->notifier; 101c2b38b27SPaolo Bonzini 102c2b38b27SPaolo Bonzini /* Update handler with latest information */ 103c2b38b27SPaolo Bonzini node->opaque = opaque; 104c2b38b27SPaolo Bonzini node->io_read = io_read; 105c2b38b27SPaolo Bonzini node->io_write = io_write; 106c2b38b27SPaolo Bonzini node->is_external = is_external; 107c2b38b27SPaolo Bonzini 10855d41b16SAlistair Francis if (io_read) { 10955d41b16SAlistair Francis bitmask |= FD_READ | FD_ACCEPT | FD_CLOSE; 11055d41b16SAlistair Francis } 11155d41b16SAlistair Francis 11255d41b16SAlistair Francis if (io_write) { 11355d41b16SAlistair Francis bitmask |= FD_WRITE | FD_CONNECT; 11455d41b16SAlistair Francis } 11555d41b16SAlistair Francis 116fef16601SRemy Noel QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node); 117c2b38b27SPaolo Bonzini event = event_notifier_get_handle(&ctx->notifier); 11855d41b16SAlistair Francis WSAEventSelect(node->pfd.fd, event, bitmask); 119c2b38b27SPaolo Bonzini } 120fef16601SRemy Noel if (old_node) { 121fef16601SRemy Noel aio_remove_fd_handler(ctx, old_node); 122fef16601SRemy Noel } 123c2b38b27SPaolo Bonzini 124c2b38b27SPaolo Bonzini qemu_lockcnt_unlock(&ctx->list_lock); 125c2b38b27SPaolo Bonzini aio_notify(ctx); 126c2b38b27SPaolo Bonzini } 127c2b38b27SPaolo Bonzini 128c2b38b27SPaolo Bonzini void aio_set_fd_poll(AioContext *ctx, int fd, 129c2b38b27SPaolo Bonzini IOHandler *io_poll_begin, 130c2b38b27SPaolo Bonzini IOHandler *io_poll_end) 131c2b38b27SPaolo Bonzini { 132c2b38b27SPaolo Bonzini /* Not implemented */ 133c2b38b27SPaolo Bonzini } 134c2b38b27SPaolo Bonzini 135c2b38b27SPaolo Bonzini void aio_set_event_notifier(AioContext *ctx, 136c2b38b27SPaolo Bonzini EventNotifier *e, 137c2b38b27SPaolo Bonzini bool is_external, 138c2b38b27SPaolo Bonzini EventNotifierHandler *io_notify, 139c2b38b27SPaolo Bonzini AioPollFn *io_poll) 140c2b38b27SPaolo Bonzini { 141c2b38b27SPaolo Bonzini AioHandler *node; 142c2b38b27SPaolo Bonzini 143c2b38b27SPaolo Bonzini qemu_lockcnt_lock(&ctx->list_lock); 144c2b38b27SPaolo Bonzini QLIST_FOREACH(node, &ctx->aio_handlers, node) { 145c2b38b27SPaolo Bonzini if (node->e == e && !node->deleted) { 146c2b38b27SPaolo Bonzini break; 147c2b38b27SPaolo Bonzini } 148c2b38b27SPaolo Bonzini } 149c2b38b27SPaolo Bonzini 150c2b38b27SPaolo Bonzini /* Are we deleting the fd handler? */ 151c2b38b27SPaolo Bonzini if (!io_notify) { 152c2b38b27SPaolo Bonzini if (node) { 153fef16601SRemy Noel aio_remove_fd_handler(ctx, node); 154c2b38b27SPaolo Bonzini } 155c2b38b27SPaolo Bonzini } else { 156c2b38b27SPaolo Bonzini if (node == NULL) { 157c2b38b27SPaolo Bonzini /* Alloc and insert if it's not already there */ 158c2b38b27SPaolo Bonzini node = g_new0(AioHandler, 1); 159c2b38b27SPaolo Bonzini node->e = e; 160c2b38b27SPaolo Bonzini node->pfd.fd = (uintptr_t)event_notifier_get_handle(e); 161c2b38b27SPaolo Bonzini node->pfd.events = G_IO_IN; 162c2b38b27SPaolo Bonzini node->is_external = is_external; 163c2b38b27SPaolo Bonzini QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node); 164c2b38b27SPaolo Bonzini 165c2b38b27SPaolo Bonzini g_source_add_poll(&ctx->source, &node->pfd); 166c2b38b27SPaolo Bonzini } 167c2b38b27SPaolo Bonzini /* Update handler with latest information */ 168c2b38b27SPaolo Bonzini node->io_notify = io_notify; 169c2b38b27SPaolo Bonzini } 170c2b38b27SPaolo Bonzini 171c2b38b27SPaolo Bonzini qemu_lockcnt_unlock(&ctx->list_lock); 172c2b38b27SPaolo Bonzini aio_notify(ctx); 173c2b38b27SPaolo Bonzini } 174c2b38b27SPaolo Bonzini 175c2b38b27SPaolo Bonzini void aio_set_event_notifier_poll(AioContext *ctx, 176c2b38b27SPaolo Bonzini EventNotifier *notifier, 177c2b38b27SPaolo Bonzini EventNotifierHandler *io_poll_begin, 178c2b38b27SPaolo Bonzini EventNotifierHandler *io_poll_end) 179c2b38b27SPaolo Bonzini { 180c2b38b27SPaolo Bonzini /* Not implemented */ 181c2b38b27SPaolo Bonzini } 182c2b38b27SPaolo Bonzini 183c2b38b27SPaolo Bonzini bool aio_prepare(AioContext *ctx) 184c2b38b27SPaolo Bonzini { 185c2b38b27SPaolo Bonzini static struct timeval tv0; 186c2b38b27SPaolo Bonzini AioHandler *node; 187c2b38b27SPaolo Bonzini bool have_select_revents = false; 188c2b38b27SPaolo Bonzini fd_set rfds, wfds; 189c2b38b27SPaolo Bonzini 190c2b38b27SPaolo Bonzini /* 191c2b38b27SPaolo Bonzini * We have to walk very carefully in case aio_set_fd_handler is 192c2b38b27SPaolo Bonzini * called while we're walking. 193c2b38b27SPaolo Bonzini */ 194c2b38b27SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock); 195c2b38b27SPaolo Bonzini 196c2b38b27SPaolo Bonzini /* fill fd sets */ 197c2b38b27SPaolo Bonzini FD_ZERO(&rfds); 198c2b38b27SPaolo Bonzini FD_ZERO(&wfds); 199c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { 200c2b38b27SPaolo Bonzini if (node->io_read) { 201c2b38b27SPaolo Bonzini FD_SET ((SOCKET)node->pfd.fd, &rfds); 202c2b38b27SPaolo Bonzini } 203c2b38b27SPaolo Bonzini if (node->io_write) { 204c2b38b27SPaolo Bonzini FD_SET ((SOCKET)node->pfd.fd, &wfds); 205c2b38b27SPaolo Bonzini } 206c2b38b27SPaolo Bonzini } 207c2b38b27SPaolo Bonzini 208c2b38b27SPaolo Bonzini if (select(0, &rfds, &wfds, NULL, &tv0) > 0) { 209c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { 210c2b38b27SPaolo Bonzini node->pfd.revents = 0; 211c2b38b27SPaolo Bonzini if (FD_ISSET(node->pfd.fd, &rfds)) { 212c2b38b27SPaolo Bonzini node->pfd.revents |= G_IO_IN; 213c2b38b27SPaolo Bonzini have_select_revents = true; 214c2b38b27SPaolo Bonzini } 215c2b38b27SPaolo Bonzini 216c2b38b27SPaolo Bonzini if (FD_ISSET(node->pfd.fd, &wfds)) { 217c2b38b27SPaolo Bonzini node->pfd.revents |= G_IO_OUT; 218c2b38b27SPaolo Bonzini have_select_revents = true; 219c2b38b27SPaolo Bonzini } 220c2b38b27SPaolo Bonzini } 221c2b38b27SPaolo Bonzini } 222c2b38b27SPaolo Bonzini 223c2b38b27SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock); 224c2b38b27SPaolo Bonzini return have_select_revents; 225c2b38b27SPaolo Bonzini } 226c2b38b27SPaolo Bonzini 227c2b38b27SPaolo Bonzini bool aio_pending(AioContext *ctx) 228c2b38b27SPaolo Bonzini { 229c2b38b27SPaolo Bonzini AioHandler *node; 230c2b38b27SPaolo Bonzini bool result = false; 231c2b38b27SPaolo Bonzini 232c2b38b27SPaolo Bonzini /* 233c2b38b27SPaolo Bonzini * We have to walk very carefully in case aio_set_fd_handler is 234c2b38b27SPaolo Bonzini * called while we're walking. 235c2b38b27SPaolo Bonzini */ 236c2b38b27SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock); 237c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { 238c2b38b27SPaolo Bonzini if (node->pfd.revents && node->io_notify) { 239c2b38b27SPaolo Bonzini result = true; 240c2b38b27SPaolo Bonzini break; 241c2b38b27SPaolo Bonzini } 242c2b38b27SPaolo Bonzini 243c2b38b27SPaolo Bonzini if ((node->pfd.revents & G_IO_IN) && node->io_read) { 244c2b38b27SPaolo Bonzini result = true; 245c2b38b27SPaolo Bonzini break; 246c2b38b27SPaolo Bonzini } 247c2b38b27SPaolo Bonzini if ((node->pfd.revents & G_IO_OUT) && node->io_write) { 248c2b38b27SPaolo Bonzini result = true; 249c2b38b27SPaolo Bonzini break; 250c2b38b27SPaolo Bonzini } 251c2b38b27SPaolo Bonzini } 252c2b38b27SPaolo Bonzini 253c2b38b27SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock); 254c2b38b27SPaolo Bonzini return result; 255c2b38b27SPaolo Bonzini } 256c2b38b27SPaolo Bonzini 257c2b38b27SPaolo Bonzini static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event) 258c2b38b27SPaolo Bonzini { 259c2b38b27SPaolo Bonzini AioHandler *node; 260c2b38b27SPaolo Bonzini bool progress = false; 261c2b38b27SPaolo Bonzini AioHandler *tmp; 262c2b38b27SPaolo Bonzini 263c2b38b27SPaolo Bonzini /* 264c2b38b27SPaolo Bonzini * We have to walk very carefully in case aio_set_fd_handler is 265c2b38b27SPaolo Bonzini * called while we're walking. 266c2b38b27SPaolo Bonzini */ 267c2b38b27SPaolo Bonzini QLIST_FOREACH_SAFE_RCU(node, &ctx->aio_handlers, node, tmp) { 268c2b38b27SPaolo Bonzini int revents = node->pfd.revents; 269c2b38b27SPaolo Bonzini 270c2b38b27SPaolo Bonzini if (!node->deleted && 271c2b38b27SPaolo Bonzini (revents || event_notifier_get_handle(node->e) == event) && 272c2b38b27SPaolo Bonzini node->io_notify) { 273c2b38b27SPaolo Bonzini node->pfd.revents = 0; 274c2b38b27SPaolo Bonzini node->io_notify(node->e); 275c2b38b27SPaolo Bonzini 276c2b38b27SPaolo Bonzini /* aio_notify() does not count as progress */ 277c2b38b27SPaolo Bonzini if (node->e != &ctx->notifier) { 278c2b38b27SPaolo Bonzini progress = true; 279c2b38b27SPaolo Bonzini } 280c2b38b27SPaolo Bonzini } 281c2b38b27SPaolo Bonzini 282c2b38b27SPaolo Bonzini if (!node->deleted && 283c2b38b27SPaolo Bonzini (node->io_read || node->io_write)) { 284c2b38b27SPaolo Bonzini node->pfd.revents = 0; 285c2b38b27SPaolo Bonzini if ((revents & G_IO_IN) && node->io_read) { 286c2b38b27SPaolo Bonzini node->io_read(node->opaque); 287c2b38b27SPaolo Bonzini progress = true; 288c2b38b27SPaolo Bonzini } 289c2b38b27SPaolo Bonzini if ((revents & G_IO_OUT) && node->io_write) { 290c2b38b27SPaolo Bonzini node->io_write(node->opaque); 291c2b38b27SPaolo Bonzini progress = true; 292c2b38b27SPaolo Bonzini } 293c2b38b27SPaolo Bonzini 294c2b38b27SPaolo Bonzini /* if the next select() will return an event, we have progressed */ 295c2b38b27SPaolo Bonzini if (event == event_notifier_get_handle(&ctx->notifier)) { 296c2b38b27SPaolo Bonzini WSANETWORKEVENTS ev; 297c2b38b27SPaolo Bonzini WSAEnumNetworkEvents(node->pfd.fd, event, &ev); 298c2b38b27SPaolo Bonzini if (ev.lNetworkEvents) { 299c2b38b27SPaolo Bonzini progress = true; 300c2b38b27SPaolo Bonzini } 301c2b38b27SPaolo Bonzini } 302c2b38b27SPaolo Bonzini } 303c2b38b27SPaolo Bonzini 304c2b38b27SPaolo Bonzini if (node->deleted) { 305c2b38b27SPaolo Bonzini if (qemu_lockcnt_dec_if_lock(&ctx->list_lock)) { 306c2b38b27SPaolo Bonzini QLIST_REMOVE(node, node); 307c2b38b27SPaolo Bonzini g_free(node); 308c2b38b27SPaolo Bonzini qemu_lockcnt_inc_and_unlock(&ctx->list_lock); 309c2b38b27SPaolo Bonzini } 310c2b38b27SPaolo Bonzini } 311c2b38b27SPaolo Bonzini } 312c2b38b27SPaolo Bonzini 313c2b38b27SPaolo Bonzini return progress; 314c2b38b27SPaolo Bonzini } 315c2b38b27SPaolo Bonzini 316a153bf52SPaolo Bonzini void aio_dispatch(AioContext *ctx) 317c2b38b27SPaolo Bonzini { 318bd451435SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock); 319a153bf52SPaolo Bonzini aio_bh_poll(ctx); 320a153bf52SPaolo Bonzini aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE); 321bd451435SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock); 322a153bf52SPaolo Bonzini timerlistgroup_run_timers(&ctx->tlg); 323c2b38b27SPaolo Bonzini } 324c2b38b27SPaolo Bonzini 325c2b38b27SPaolo Bonzini bool aio_poll(AioContext *ctx, bool blocking) 326c2b38b27SPaolo Bonzini { 327c2b38b27SPaolo Bonzini AioHandler *node; 328c2b38b27SPaolo Bonzini HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; 329c2b38b27SPaolo Bonzini bool progress, have_select_revents, first; 330c2b38b27SPaolo Bonzini int count; 331c2b38b27SPaolo Bonzini int timeout; 332c2b38b27SPaolo Bonzini 3335710a3e0SPaolo Bonzini /* 3345710a3e0SPaolo Bonzini * There cannot be two concurrent aio_poll calls for the same AioContext (or 3355710a3e0SPaolo Bonzini * an aio_poll concurrent with a GSource prepare/check/dispatch callback). 3365710a3e0SPaolo Bonzini * We rely on this below to avoid slow locked accesses to ctx->notify_me. 337*eada6d92SVolker Rümelin * 338*eada6d92SVolker Rümelin * aio_poll() may only be called in the AioContext's thread. iohandler_ctx 339*eada6d92SVolker Rümelin * is special in that it runs in the main thread, but that thread's context 340*eada6d92SVolker Rümelin * is qemu_aio_context. 3415710a3e0SPaolo Bonzini */ 342*eada6d92SVolker Rümelin assert(in_aio_context_home_thread(ctx == iohandler_get_aio_context() ? 343*eada6d92SVolker Rümelin qemu_get_aio_context() : ctx)); 344c2b38b27SPaolo Bonzini progress = false; 345c2b38b27SPaolo Bonzini 346c2b38b27SPaolo Bonzini /* aio_notify can avoid the expensive event_notifier_set if 347c2b38b27SPaolo Bonzini * everything (file descriptors, bottom halves, timers) will 348c2b38b27SPaolo Bonzini * be re-evaluated before the next blocking poll(). This is 349c2b38b27SPaolo Bonzini * already true when aio_poll is called with blocking == false; 350c2b38b27SPaolo Bonzini * if blocking == true, it is only true after poll() returns, 351c2b38b27SPaolo Bonzini * so disable the optimization now. 352c2b38b27SPaolo Bonzini */ 353c2b38b27SPaolo Bonzini if (blocking) { 354d73415a3SStefan Hajnoczi qatomic_set(&ctx->notify_me, qatomic_read(&ctx->notify_me) + 2); 3555710a3e0SPaolo Bonzini /* 3565710a3e0SPaolo Bonzini * Write ctx->notify_me before computing the timeout 3575710a3e0SPaolo Bonzini * (reading bottom half flags, etc.). Pairs with 3585710a3e0SPaolo Bonzini * smp_mb in aio_notify(). 3595710a3e0SPaolo Bonzini */ 3605710a3e0SPaolo Bonzini smp_mb(); 361c2b38b27SPaolo Bonzini } 362c2b38b27SPaolo Bonzini 363c2b38b27SPaolo Bonzini qemu_lockcnt_inc(&ctx->list_lock); 364c2b38b27SPaolo Bonzini have_select_revents = aio_prepare(ctx); 365c2b38b27SPaolo Bonzini 366c2b38b27SPaolo Bonzini /* fill fd sets */ 367c2b38b27SPaolo Bonzini count = 0; 368c2b38b27SPaolo Bonzini QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { 369c2b38b27SPaolo Bonzini if (!node->deleted && node->io_notify 370c2b38b27SPaolo Bonzini && aio_node_check(ctx, node->is_external)) { 371c2b38b27SPaolo Bonzini events[count++] = event_notifier_get_handle(node->e); 372c2b38b27SPaolo Bonzini } 373c2b38b27SPaolo Bonzini } 374c2b38b27SPaolo Bonzini 375c2b38b27SPaolo Bonzini first = true; 376c2b38b27SPaolo Bonzini 377c2b38b27SPaolo Bonzini /* ctx->notifier is always registered. */ 378c2b38b27SPaolo Bonzini assert(count > 0); 379c2b38b27SPaolo Bonzini 380c2b38b27SPaolo Bonzini /* Multiple iterations, all of them non-blocking except the first, 381c2b38b27SPaolo Bonzini * may be necessary to process all pending events. After the first 382c2b38b27SPaolo Bonzini * WaitForMultipleObjects call ctx->notify_me will be decremented. 383c2b38b27SPaolo Bonzini */ 384c2b38b27SPaolo Bonzini do { 385c2b38b27SPaolo Bonzini HANDLE event; 386c2b38b27SPaolo Bonzini int ret; 387c2b38b27SPaolo Bonzini 388c2b38b27SPaolo Bonzini timeout = blocking && !have_select_revents 389c2b38b27SPaolo Bonzini ? qemu_timeout_ns_to_ms(aio_compute_timeout(ctx)) : 0; 390c2b38b27SPaolo Bonzini ret = WaitForMultipleObjects(count, events, FALSE, timeout); 391c2b38b27SPaolo Bonzini if (blocking) { 392c2b38b27SPaolo Bonzini assert(first); 393d73415a3SStefan Hajnoczi qatomic_store_release(&ctx->notify_me, 394d73415a3SStefan Hajnoczi qatomic_read(&ctx->notify_me) - 2); 395b37548fcSFam Zheng aio_notify_accept(ctx); 396c2b38b27SPaolo Bonzini } 397c2b38b27SPaolo Bonzini 398c2b38b27SPaolo Bonzini if (first) { 399c2b38b27SPaolo Bonzini progress |= aio_bh_poll(ctx); 400c2b38b27SPaolo Bonzini first = false; 401c2b38b27SPaolo Bonzini } 402c2b38b27SPaolo Bonzini 403c2b38b27SPaolo Bonzini /* if we have any signaled events, dispatch event */ 404c2b38b27SPaolo Bonzini event = NULL; 405c2b38b27SPaolo Bonzini if ((DWORD) (ret - WAIT_OBJECT_0) < count) { 406c2b38b27SPaolo Bonzini event = events[ret - WAIT_OBJECT_0]; 407c2b38b27SPaolo Bonzini events[ret - WAIT_OBJECT_0] = events[--count]; 408c2b38b27SPaolo Bonzini } else if (!have_select_revents) { 409c2b38b27SPaolo Bonzini break; 410c2b38b27SPaolo Bonzini } 411c2b38b27SPaolo Bonzini 412c2b38b27SPaolo Bonzini have_select_revents = false; 413c2b38b27SPaolo Bonzini blocking = false; 414c2b38b27SPaolo Bonzini 415c2b38b27SPaolo Bonzini progress |= aio_dispatch_handlers(ctx, event); 416c2b38b27SPaolo Bonzini } while (count > 0); 417c2b38b27SPaolo Bonzini 418bd451435SPaolo Bonzini qemu_lockcnt_dec(&ctx->list_lock); 419bd451435SPaolo Bonzini 420c2b38b27SPaolo Bonzini progress |= timerlistgroup_run_timers(&ctx->tlg); 421c2b38b27SPaolo Bonzini return progress; 422c2b38b27SPaolo Bonzini } 423c2b38b27SPaolo Bonzini 424c2b38b27SPaolo Bonzini void aio_context_setup(AioContext *ctx) 425c2b38b27SPaolo Bonzini { 426c2b38b27SPaolo Bonzini } 427c2b38b27SPaolo Bonzini 428cd0a6d2bSJie Wang void aio_context_destroy(AioContext *ctx) 429cd0a6d2bSJie Wang { 430cd0a6d2bSJie Wang } 431cd0a6d2bSJie Wang 432ba607ca8SStefan Hajnoczi void aio_context_use_g_source(AioContext *ctx) 433ba607ca8SStefan Hajnoczi { 434ba607ca8SStefan Hajnoczi } 435ba607ca8SStefan Hajnoczi 436c2b38b27SPaolo Bonzini void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, 437c2b38b27SPaolo Bonzini int64_t grow, int64_t shrink, Error **errp) 438c2b38b27SPaolo Bonzini { 43990c558beSPeter Xu if (max_ns) { 440c2b38b27SPaolo Bonzini error_setg(errp, "AioContext polling is not implemented on Windows"); 441c2b38b27SPaolo Bonzini } 44290c558beSPeter Xu } 443