Statistics
| Branch: | Revision:

root / aio-posix.c @ 3bd88451

History | View | Annotate | Download (6.7 kB)

1 a76bab49 aliguori
/*
2 a76bab49 aliguori
 * QEMU aio implementation
3 a76bab49 aliguori
 *
4 a76bab49 aliguori
 * Copyright IBM, Corp. 2008
5 a76bab49 aliguori
 *
6 a76bab49 aliguori
 * Authors:
7 a76bab49 aliguori
 *  Anthony Liguori   <aliguori@us.ibm.com>
8 a76bab49 aliguori
 *
9 a76bab49 aliguori
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10 a76bab49 aliguori
 * the COPYING file in the top-level directory.
11 a76bab49 aliguori
 *
12 6b620ca3 Paolo Bonzini
 * Contributions after 2012-01-13 are licensed under the terms of the
13 6b620ca3 Paolo Bonzini
 * GNU GPL, version 2 or (at your option) any later version.
14 a76bab49 aliguori
 */
15 a76bab49 aliguori
16 a76bab49 aliguori
#include "qemu-common.h"
17 737e150e Paolo Bonzini
#include "block/block.h"
18 1de7afc9 Paolo Bonzini
#include "qemu/queue.h"
19 1de7afc9 Paolo Bonzini
#include "qemu/sockets.h"
20 a76bab49 aliguori
21 a76bab49 aliguori
struct AioHandler
22 a76bab49 aliguori
{
23 cd9ba1eb Paolo Bonzini
    GPollFD pfd;
24 a76bab49 aliguori
    IOHandler *io_read;
25 a76bab49 aliguori
    IOHandler *io_write;
26 a76bab49 aliguori
    AioFlushHandler *io_flush;
27 a76bab49 aliguori
    int deleted;
28 6b5f8762 Stefan Hajnoczi
    int pollfds_idx;
29 a76bab49 aliguori
    void *opaque;
30 72cf2d4f Blue Swirl
    QLIST_ENTRY(AioHandler) node;
31 a76bab49 aliguori
};
32 a76bab49 aliguori
33 a915f4bc Paolo Bonzini
static AioHandler *find_aio_handler(AioContext *ctx, int fd)
34 a76bab49 aliguori
{
35 a76bab49 aliguori
    AioHandler *node;
36 a76bab49 aliguori
37 a915f4bc Paolo Bonzini
    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
38 cd9ba1eb Paolo Bonzini
        if (node->pfd.fd == fd)
39 79d5ca56 Alexander Graf
            if (!node->deleted)
40 79d5ca56 Alexander Graf
                return node;
41 a76bab49 aliguori
    }
42 a76bab49 aliguori
43 a76bab49 aliguori
    return NULL;
44 a76bab49 aliguori
}
45 a76bab49 aliguori
46 a915f4bc Paolo Bonzini
void aio_set_fd_handler(AioContext *ctx,
47 a915f4bc Paolo Bonzini
                        int fd,
48 a915f4bc Paolo Bonzini
                        IOHandler *io_read,
49 a915f4bc Paolo Bonzini
                        IOHandler *io_write,
50 a915f4bc Paolo Bonzini
                        AioFlushHandler *io_flush,
51 a915f4bc Paolo Bonzini
                        void *opaque)
52 a76bab49 aliguori
{
53 a76bab49 aliguori
    AioHandler *node;
54 a76bab49 aliguori
55 a915f4bc Paolo Bonzini
    node = find_aio_handler(ctx, fd);
56 a76bab49 aliguori
57 a76bab49 aliguori
    /* Are we deleting the fd handler? */
58 a76bab49 aliguori
    if (!io_read && !io_write) {
59 a76bab49 aliguori
        if (node) {
60 e3713e00 Paolo Bonzini
            g_source_remove_poll(&ctx->source, &node->pfd);
61 e3713e00 Paolo Bonzini
62 a76bab49 aliguori
            /* If the lock is held, just mark the node as deleted */
63 cd9ba1eb Paolo Bonzini
            if (ctx->walking_handlers) {
64 a76bab49 aliguori
                node->deleted = 1;
65 cd9ba1eb Paolo Bonzini
                node->pfd.revents = 0;
66 cd9ba1eb Paolo Bonzini
            } else {
67 a76bab49 aliguori
                /* Otherwise, delete it for real.  We can't just mark it as
68 a76bab49 aliguori
                 * deleted because deleted nodes are only cleaned up after
69 a76bab49 aliguori
                 * releasing the walking_handlers lock.
70 a76bab49 aliguori
                 */
71 72cf2d4f Blue Swirl
                QLIST_REMOVE(node, node);
72 7267c094 Anthony Liguori
                g_free(node);
73 a76bab49 aliguori
            }
74 a76bab49 aliguori
        }
75 a76bab49 aliguori
    } else {
76 a76bab49 aliguori
        if (node == NULL) {
77 a76bab49 aliguori
            /* Alloc and insert if it's not already there */
78 7267c094 Anthony Liguori
            node = g_malloc0(sizeof(AioHandler));
79 cd9ba1eb Paolo Bonzini
            node->pfd.fd = fd;
80 a915f4bc Paolo Bonzini
            QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
81 e3713e00 Paolo Bonzini
82 e3713e00 Paolo Bonzini
            g_source_add_poll(&ctx->source, &node->pfd);
83 a76bab49 aliguori
        }
84 a76bab49 aliguori
        /* Update handler with latest information */
85 a76bab49 aliguori
        node->io_read = io_read;
86 a76bab49 aliguori
        node->io_write = io_write;
87 a76bab49 aliguori
        node->io_flush = io_flush;
88 a76bab49 aliguori
        node->opaque = opaque;
89 6b5f8762 Stefan Hajnoczi
        node->pollfds_idx = -1;
90 cd9ba1eb Paolo Bonzini
91 b5a01a70 Stefan Hajnoczi
        node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
92 b5a01a70 Stefan Hajnoczi
        node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
93 a76bab49 aliguori
    }
94 7ed2b24c Paolo Bonzini
95 7ed2b24c Paolo Bonzini
    aio_notify(ctx);
96 9958c351 Paolo Bonzini
}
97 9958c351 Paolo Bonzini
98 a915f4bc Paolo Bonzini
void aio_set_event_notifier(AioContext *ctx,
99 a915f4bc Paolo Bonzini
                            EventNotifier *notifier,
100 a915f4bc Paolo Bonzini
                            EventNotifierHandler *io_read,
101 a915f4bc Paolo Bonzini
                            AioFlushEventNotifierHandler *io_flush)
102 a76bab49 aliguori
{
103 a915f4bc Paolo Bonzini
    aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
104 a915f4bc Paolo Bonzini
                       (IOHandler *)io_read, NULL,
105 a915f4bc Paolo Bonzini
                       (AioFlushHandler *)io_flush, notifier);
106 a76bab49 aliguori
}
107 a76bab49 aliguori
108 cd9ba1eb Paolo Bonzini
bool aio_pending(AioContext *ctx)
109 cd9ba1eb Paolo Bonzini
{
110 cd9ba1eb Paolo Bonzini
    AioHandler *node;
111 cd9ba1eb Paolo Bonzini
112 cd9ba1eb Paolo Bonzini
    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
113 cd9ba1eb Paolo Bonzini
        int revents;
114 cd9ba1eb Paolo Bonzini
115 cd9ba1eb Paolo Bonzini
        revents = node->pfd.revents & node->pfd.events;
116 cd9ba1eb Paolo Bonzini
        if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
117 cd9ba1eb Paolo Bonzini
            return true;
118 cd9ba1eb Paolo Bonzini
        }
119 cd9ba1eb Paolo Bonzini
        if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
120 cd9ba1eb Paolo Bonzini
            return true;
121 cd9ba1eb Paolo Bonzini
        }
122 cd9ba1eb Paolo Bonzini
    }
123 cd9ba1eb Paolo Bonzini
124 cd9ba1eb Paolo Bonzini
    return false;
125 cd9ba1eb Paolo Bonzini
}
126 cd9ba1eb Paolo Bonzini
127 d0c8d2c0 Stefan Hajnoczi
static bool aio_dispatch(AioContext *ctx)
128 a76bab49 aliguori
{
129 9eb0bfca Paolo Bonzini
    AioHandler *node;
130 d0c8d2c0 Stefan Hajnoczi
    bool progress = false;
131 7c0628b2 Paolo Bonzini
132 cd9ba1eb Paolo Bonzini
    /*
133 cd9ba1eb Paolo Bonzini
     * We have to walk very carefully in case qemu_aio_set_fd_handler is
134 cd9ba1eb Paolo Bonzini
     * called while we're walking.
135 cd9ba1eb Paolo Bonzini
     */
136 cd9ba1eb Paolo Bonzini
    node = QLIST_FIRST(&ctx->aio_handlers);
137 cd9ba1eb Paolo Bonzini
    while (node) {
138 cd9ba1eb Paolo Bonzini
        AioHandler *tmp;
139 cd9ba1eb Paolo Bonzini
        int revents;
140 cd9ba1eb Paolo Bonzini
141 cd9ba1eb Paolo Bonzini
        ctx->walking_handlers++;
142 cd9ba1eb Paolo Bonzini
143 cd9ba1eb Paolo Bonzini
        revents = node->pfd.revents & node->pfd.events;
144 cd9ba1eb Paolo Bonzini
        node->pfd.revents = 0;
145 cd9ba1eb Paolo Bonzini
146 d0c8d2c0 Stefan Hajnoczi
        if (!node->deleted &&
147 d0c8d2c0 Stefan Hajnoczi
            (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
148 d0c8d2c0 Stefan Hajnoczi
            node->io_read) {
149 cd9ba1eb Paolo Bonzini
            node->io_read(node->opaque);
150 cd9ba1eb Paolo Bonzini
            progress = true;
151 cd9ba1eb Paolo Bonzini
        }
152 d0c8d2c0 Stefan Hajnoczi
        if (!node->deleted &&
153 d0c8d2c0 Stefan Hajnoczi
            (revents & (G_IO_OUT | G_IO_ERR)) &&
154 d0c8d2c0 Stefan Hajnoczi
            node->io_write) {
155 cd9ba1eb Paolo Bonzini
            node->io_write(node->opaque);
156 cd9ba1eb Paolo Bonzini
            progress = true;
157 cd9ba1eb Paolo Bonzini
        }
158 cd9ba1eb Paolo Bonzini
159 cd9ba1eb Paolo Bonzini
        tmp = node;
160 cd9ba1eb Paolo Bonzini
        node = QLIST_NEXT(node, node);
161 cd9ba1eb Paolo Bonzini
162 cd9ba1eb Paolo Bonzini
        ctx->walking_handlers--;
163 cd9ba1eb Paolo Bonzini
164 cd9ba1eb Paolo Bonzini
        if (!ctx->walking_handlers && tmp->deleted) {
165 cd9ba1eb Paolo Bonzini
            QLIST_REMOVE(tmp, node);
166 cd9ba1eb Paolo Bonzini
            g_free(tmp);
167 cd9ba1eb Paolo Bonzini
        }
168 cd9ba1eb Paolo Bonzini
    }
169 d0c8d2c0 Stefan Hajnoczi
    return progress;
170 d0c8d2c0 Stefan Hajnoczi
}
171 d0c8d2c0 Stefan Hajnoczi
172 d0c8d2c0 Stefan Hajnoczi
bool aio_poll(AioContext *ctx, bool blocking)
173 d0c8d2c0 Stefan Hajnoczi
{
174 d0c8d2c0 Stefan Hajnoczi
    AioHandler *node;
175 d0c8d2c0 Stefan Hajnoczi
    int ret;
176 d0c8d2c0 Stefan Hajnoczi
    bool busy, progress;
177 d0c8d2c0 Stefan Hajnoczi
178 d0c8d2c0 Stefan Hajnoczi
    progress = false;
179 d0c8d2c0 Stefan Hajnoczi
180 d0c8d2c0 Stefan Hajnoczi
    /*
181 d0c8d2c0 Stefan Hajnoczi
     * If there are callbacks left that have been queued, we need to call them.
182 d0c8d2c0 Stefan Hajnoczi
     * Do not call select in this case, because it is possible that the caller
183 d0c8d2c0 Stefan Hajnoczi
     * does not need a complete flush (as is the case for qemu_aio_wait loops).
184 d0c8d2c0 Stefan Hajnoczi
     */
185 d0c8d2c0 Stefan Hajnoczi
    if (aio_bh_poll(ctx)) {
186 d0c8d2c0 Stefan Hajnoczi
        blocking = false;
187 d0c8d2c0 Stefan Hajnoczi
        progress = true;
188 d0c8d2c0 Stefan Hajnoczi
    }
189 d0c8d2c0 Stefan Hajnoczi
190 d0c8d2c0 Stefan Hajnoczi
    if (aio_dispatch(ctx)) {
191 d0c8d2c0 Stefan Hajnoczi
        progress = true;
192 d0c8d2c0 Stefan Hajnoczi
    }
193 cd9ba1eb Paolo Bonzini
194 7c0628b2 Paolo Bonzini
    if (progress && !blocking) {
195 bcdc1857 Paolo Bonzini
        return true;
196 bafbd6a1 Paolo Bonzini
    }
197 8febfa26 Kevin Wolf
198 a915f4bc Paolo Bonzini
    ctx->walking_handlers++;
199 a76bab49 aliguori
200 6b5f8762 Stefan Hajnoczi
    g_array_set_size(ctx->pollfds, 0);
201 a76bab49 aliguori
202 6b5f8762 Stefan Hajnoczi
    /* fill pollfds */
203 9eb0bfca Paolo Bonzini
    busy = false;
204 a915f4bc Paolo Bonzini
    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
205 6b5f8762 Stefan Hajnoczi
        node->pollfds_idx = -1;
206 6b5f8762 Stefan Hajnoczi
207 9eb0bfca Paolo Bonzini
        /* If there aren't pending AIO operations, don't invoke callbacks.
208 9eb0bfca Paolo Bonzini
         * Otherwise, if there are no AIO requests, qemu_aio_wait() would
209 9eb0bfca Paolo Bonzini
         * wait indefinitely.
210 9eb0bfca Paolo Bonzini
         */
211 4231c88d Paolo Bonzini
        if (!node->deleted && node->io_flush) {
212 9eb0bfca Paolo Bonzini
            if (node->io_flush(node->opaque) == 0) {
213 9eb0bfca Paolo Bonzini
                continue;
214 a76bab49 aliguori
            }
215 9eb0bfca Paolo Bonzini
            busy = true;
216 9eb0bfca Paolo Bonzini
        }
217 6b5f8762 Stefan Hajnoczi
        if (!node->deleted && node->pfd.events) {
218 6b5f8762 Stefan Hajnoczi
            GPollFD pfd = {
219 6b5f8762 Stefan Hajnoczi
                .fd = node->pfd.fd,
220 6b5f8762 Stefan Hajnoczi
                .events = node->pfd.events,
221 6b5f8762 Stefan Hajnoczi
            };
222 6b5f8762 Stefan Hajnoczi
            node->pollfds_idx = ctx->pollfds->len;
223 6b5f8762 Stefan Hajnoczi
            g_array_append_val(ctx->pollfds, pfd);
224 9eb0bfca Paolo Bonzini
        }
225 9eb0bfca Paolo Bonzini
    }
226 a76bab49 aliguori
227 a915f4bc Paolo Bonzini
    ctx->walking_handlers--;
228 a76bab49 aliguori
229 9eb0bfca Paolo Bonzini
    /* No AIO operations?  Get us out of here */
230 9eb0bfca Paolo Bonzini
    if (!busy) {
231 7c0628b2 Paolo Bonzini
        return progress;
232 9eb0bfca Paolo Bonzini
    }
233 a76bab49 aliguori
234 9eb0bfca Paolo Bonzini
    /* wait until next event */
235 6b5f8762 Stefan Hajnoczi
    ret = g_poll((GPollFD *)ctx->pollfds->data,
236 6b5f8762 Stefan Hajnoczi
                 ctx->pollfds->len,
237 6b5f8762 Stefan Hajnoczi
                 blocking ? -1 : 0);
238 9eb0bfca Paolo Bonzini
239 9eb0bfca Paolo Bonzini
    /* if we have any readable fds, dispatch event */
240 9eb0bfca Paolo Bonzini
    if (ret > 0) {
241 6b5f8762 Stefan Hajnoczi
        QLIST_FOREACH(node, &ctx->aio_handlers, node) {
242 6b5f8762 Stefan Hajnoczi
            if (node->pollfds_idx != -1) {
243 6b5f8762 Stefan Hajnoczi
                GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
244 6b5f8762 Stefan Hajnoczi
                                              node->pollfds_idx);
245 6b5f8762 Stefan Hajnoczi
                node->pfd.revents = pfd->revents;
246 9eb0bfca Paolo Bonzini
            }
247 a76bab49 aliguori
        }
248 6b5f8762 Stefan Hajnoczi
        if (aio_dispatch(ctx)) {
249 6b5f8762 Stefan Hajnoczi
            progress = true;
250 6b5f8762 Stefan Hajnoczi
        }
251 9eb0bfca Paolo Bonzini
    }
252 bcdc1857 Paolo Bonzini
253 2ea9b58f Kevin Wolf
    assert(progress || busy);
254 2ea9b58f Kevin Wolf
    return true;
255 a76bab49 aliguori
}