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