15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU aio implementation 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright IBM, Corp. 2008 55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Authors: 75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Anthony Liguori <aliguori@us.ibm.com> 85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This work is licensed under the terms of the GNU GPL, version 2. See 105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the COPYING file in the top-level directory. 115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h" 15e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "block/block.h" 16031d655004e505a15e92580a16a181d1d247c4d5David 'Digit' Turner#include "qemu/queue.h" 17d0edecb426b34ddb9b10b81dea19aee04a61a385David 'Digit' Turner#include "qemu/sockets.h" 18d413fa5f2916a2a46494edb320340486b262644cDavid 'Digit' Turner#include "android/iolooper.h" 195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct AioHandler AioHandler; 215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* The list of registered AIO handlers */ 23a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turnerstatic QLIST_HEAD(, AioHandler) aio_handlers; 245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* This is a simple lock used to protect the aio_handlers list. Specifically, 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * it's used to ensure that no callbacks are removed while we're walking and 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * dispatching callbacks. 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int walking_handlers; 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct AioHandler 325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner IOHandler *io_read; 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner IOHandler *io_write; 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner AioFlushHandler *io_flush; 377627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner AioProcessQueue *io_process_queue; 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int deleted; 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 40a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner QLIST_ENTRY(AioHandler) node; 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic AioHandler *find_aio_handler(int fd) 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner AioHandler *node; 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 47a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner QLIST_FOREACH(node, &aio_handlers, node) { 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (node->fd == fd) 495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!node->deleted) 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return node; 515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_aio_set_fd_handler(int fd, 575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner IOHandler *io_read, 585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner IOHandler *io_write, 595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner AioFlushHandler *io_flush, 607627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner AioProcessQueue *io_process_queue, 615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner AioHandler *node; 645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node = find_aio_handler(fd); 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Are we deleting the fd handler? */ 685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!io_read && !io_write) { 695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (node) { 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* If the lock is held, just mark the node as deleted */ 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (walking_handlers) 725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->deleted = 1; 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else { 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Otherwise, delete it for real. We can't just mark it as 755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * deleted because deleted nodes are only cleaned up after 765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * releasing the walking_handlers lock. 775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 78a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner QLIST_REMOVE(node, node); 79aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(node); 805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (node == NULL) { 845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Alloc and insert if it's not already there */ 85aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner node = g_malloc0(sizeof(AioHandler)); 865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->fd = fd; 87a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner QLIST_INSERT_HEAD(&aio_handlers, node, node); 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Update handler with latest information */ 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->io_read = io_read; 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->io_write = io_write; 925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->io_flush = io_flush; 937627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner node->io_process_queue = io_process_queue; 945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->opaque = opaque; 955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque); 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_aio_flush(void) 1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner AioHandler *node; 1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* 1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * If there are pending emulated aio start them now so flush 1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * will be able to return 1. 1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_wait(); 1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 116a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner QLIST_FOREACH(node, &aio_handlers, node) { 1177627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner if (node->io_flush) { 1187627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner ret |= node->io_flush(node->opaque); 1197627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner } 1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1217627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner } while (qemu_bh_poll() || ret > 0); 1227627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner} 1237627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner 1247627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turnerint qemu_aio_process_queue(void) 1257627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner{ 1267627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner AioHandler *node; 1277627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner int ret = 0; 1287627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner 1297627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner walking_handlers = 1; 1307627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner 1317627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner QLIST_FOREACH(node, &aio_handlers, node) { 1327627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner if (node->io_process_queue) { 1337627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner if (node->io_process_queue(node->opaque)) { 1347627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner ret = 1; 1357627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner } 1367627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner } 1377627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner } 1387627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner 1397627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner walking_handlers = 0; 1407627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner 1417627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner return ret; 1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_aio_wait(void) 1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner IoLooper* looper; 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_bh_poll()) 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1527627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner /* 1537627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner * If there are callbacks left that have been queued, we need to call then. 1547627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner * Return afterwards to avoid waiting needlessly in select(). 1557627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner */ 1567627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner if (qemu_aio_process_queue()) 1577627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner return; 1587627ed7924456c88d3e8631c2cddcc7d54107ffaDavid Turner 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner looper = iolooper_new(); 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner AioHandler *node; 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner iolooper_reset(looper); 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner walking_handlers = 1; 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fill fd sets */ 168a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner QLIST_FOREACH(node, &aio_handlers, node) { 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* If there aren't pending AIO operations, don't invoke callbacks. 1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Otherwise, if there are no AIO requests, qemu_aio_wait() would 1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * wait indefinitely. 1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (node->io_flush && node->io_flush(node->opaque) == 0) 1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!node->deleted && node->io_read) { 1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner iolooper_add_read(looper, node->fd); 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!node->deleted && node->io_write) { 1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner iolooper_add_write(looper, node->fd); 1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner walking_handlers = 0; 1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 186cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije /* No AIO operations? Get us out of here */ 187cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije if (!iolooper_has_operations(looper)) { 188cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije break; 189cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije } 190cc19d3eeef59cbd354c1c618f7421d6fe5e0a098Ot ten Thije 1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* wait until next event */ 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = iolooper_wait(looper, -1); 1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* if we have any readable fds, dispatch event */ 1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret > 0) { 1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner walking_handlers = 1; 1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* we have to walk very carefully in case 1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * qemu_aio_set_fd_handler is called while we're walking */ 200a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner node = QLIST_FIRST(&aio_handlers); 2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (node) { 2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner AioHandler *tmp; 2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!node->deleted && 2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner iolooper_is_read(looper, node->fd) && 2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->io_read) { 2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->io_read(node->opaque); 2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!node->deleted && 2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner iolooper_is_write(looper, node->fd) && 2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->io_write) { 2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner node->io_write(node->opaque); 2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner tmp = node; 216a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner node = QLIST_NEXT(node, node); 2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (tmp->deleted) { 219a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner QLIST_REMOVE(tmp, node); 220aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner g_free(tmp); 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner walking_handlers = 0; 2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (ret == 0); 2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner iolooper_free(looper); 2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 230