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