Statistics
| Branch: | Revision:

root / aio-posix.c @ 6a1751b7

History | View | Annotate | Download (6.2 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
    int deleted;
27 6b5f8762 Stefan Hajnoczi
    int pollfds_idx;
28 a76bab49 aliguori
    void *opaque;
29 72cf2d4f Blue Swirl
    QLIST_ENTRY(AioHandler) node;
30 a76bab49 aliguori
};
31 a76bab49 aliguori
32 a915f4bc Paolo Bonzini
static AioHandler *find_aio_handler(AioContext *ctx, int fd)
33 a76bab49 aliguori
{
34 a76bab49 aliguori
    AioHandler *node;
35 a76bab49 aliguori
36 a915f4bc Paolo Bonzini
    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
37 cd9ba1eb Paolo Bonzini
        if (node->pfd.fd == fd)
38 79d5ca56 Alexander Graf
            if (!node->deleted)
39 79d5ca56 Alexander Graf
                return node;
40 a76bab49 aliguori
    }
41 a76bab49 aliguori
42 a76bab49 aliguori
    return NULL;
43 a76bab49 aliguori
}
44 a76bab49 aliguori
45 a915f4bc Paolo Bonzini
void aio_set_fd_handler(AioContext *ctx,
46 a915f4bc Paolo Bonzini
                        int fd,
47 a915f4bc Paolo Bonzini
                        IOHandler *io_read,
48 a915f4bc Paolo Bonzini
                        IOHandler *io_write,
49 a915f4bc Paolo Bonzini
                        void *opaque)
50 a76bab49 aliguori
{
51 a76bab49 aliguori
    AioHandler *node;
52 a76bab49 aliguori
53 a915f4bc Paolo Bonzini
    node = find_aio_handler(ctx, fd);
54 a76bab49 aliguori
55 a76bab49 aliguori
    /* Are we deleting the fd handler? */
56 a76bab49 aliguori
    if (!io_read && !io_write) {
57 a76bab49 aliguori
        if (node) {
58 e3713e00 Paolo Bonzini
            g_source_remove_poll(&ctx->source, &node->pfd);
59 e3713e00 Paolo Bonzini
60 a76bab49 aliguori
            /* If the lock is held, just mark the node as deleted */
61 cd9ba1eb Paolo Bonzini
            if (ctx->walking_handlers) {
62 a76bab49 aliguori
                node->deleted = 1;
63 cd9ba1eb Paolo Bonzini
                node->pfd.revents = 0;
64 cd9ba1eb Paolo Bonzini
            } else {
65 a76bab49 aliguori
                /* Otherwise, delete it for real.  We can't just mark it as
66 a76bab49 aliguori
                 * deleted because deleted nodes are only cleaned up after
67 a76bab49 aliguori
                 * releasing the walking_handlers lock.
68 a76bab49 aliguori
                 */
69 72cf2d4f Blue Swirl
                QLIST_REMOVE(node, node);
70 7267c094 Anthony Liguori
                g_free(node);
71 a76bab49 aliguori
            }
72 a76bab49 aliguori
        }
73 a76bab49 aliguori
    } else {
74 a76bab49 aliguori
        if (node == NULL) {
75 a76bab49 aliguori
            /* Alloc and insert if it's not already there */
76 7267c094 Anthony Liguori
            node = g_malloc0(sizeof(AioHandler));
77 cd9ba1eb Paolo Bonzini
            node->pfd.fd = fd;
78 a915f4bc Paolo Bonzini
            QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
79 e3713e00 Paolo Bonzini
80 e3713e00 Paolo Bonzini
            g_source_add_poll(&ctx->source, &node->pfd);
81 a76bab49 aliguori
        }
82 a76bab49 aliguori
        /* Update handler with latest information */
83 a76bab49 aliguori
        node->io_read = io_read;
84 a76bab49 aliguori
        node->io_write = io_write;
85 a76bab49 aliguori
        node->opaque = opaque;
86 6b5f8762 Stefan Hajnoczi
        node->pollfds_idx = -1;
87 cd9ba1eb Paolo Bonzini
88 b5a01a70 Stefan Hajnoczi
        node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
89 b5a01a70 Stefan Hajnoczi
        node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
90 a76bab49 aliguori
    }
91 7ed2b24c Paolo Bonzini
92 7ed2b24c Paolo Bonzini
    aio_notify(ctx);
93 9958c351 Paolo Bonzini
}
94 9958c351 Paolo Bonzini
95 a915f4bc Paolo Bonzini
void aio_set_event_notifier(AioContext *ctx,
96 a915f4bc Paolo Bonzini
                            EventNotifier *notifier,
97 f2e5dca4 Stefan Hajnoczi
                            EventNotifierHandler *io_read)
98 a76bab49 aliguori
{
99 a915f4bc Paolo Bonzini
    aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
100 f2e5dca4 Stefan Hajnoczi
                       (IOHandler *)io_read, NULL, notifier);
101 a76bab49 aliguori
}
102 a76bab49 aliguori
103 cd9ba1eb Paolo Bonzini
bool aio_pending(AioContext *ctx)
104 cd9ba1eb Paolo Bonzini
{
105 cd9ba1eb Paolo Bonzini
    AioHandler *node;
106 cd9ba1eb Paolo Bonzini
107 cd9ba1eb Paolo Bonzini
    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
108 cd9ba1eb Paolo Bonzini
        int revents;
109 cd9ba1eb Paolo Bonzini
110 cd9ba1eb Paolo Bonzini
        revents = node->pfd.revents & node->pfd.events;
111 cd9ba1eb Paolo Bonzini
        if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
112 cd9ba1eb Paolo Bonzini
            return true;
113 cd9ba1eb Paolo Bonzini
        }
114 cd9ba1eb Paolo Bonzini
        if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
115 cd9ba1eb Paolo Bonzini
            return true;
116 cd9ba1eb Paolo Bonzini
        }
117 cd9ba1eb Paolo Bonzini
    }
118 cd9ba1eb Paolo Bonzini
119 cd9ba1eb Paolo Bonzini
    return false;
120 cd9ba1eb Paolo Bonzini
}
121 cd9ba1eb Paolo Bonzini
122 d0c8d2c0 Stefan Hajnoczi
static bool aio_dispatch(AioContext *ctx)
123 a76bab49 aliguori
{
124 9eb0bfca Paolo Bonzini
    AioHandler *node;
125 d0c8d2c0 Stefan Hajnoczi
    bool progress = false;
126 7c0628b2 Paolo Bonzini
127 cd9ba1eb Paolo Bonzini
    /*
128 cd9ba1eb Paolo Bonzini
     * We have to walk very carefully in case qemu_aio_set_fd_handler is
129 cd9ba1eb Paolo Bonzini
     * called while we're walking.
130 cd9ba1eb Paolo Bonzini
     */
131 cd9ba1eb Paolo Bonzini
    node = QLIST_FIRST(&ctx->aio_handlers);
132 cd9ba1eb Paolo Bonzini
    while (node) {
133 cd9ba1eb Paolo Bonzini
        AioHandler *tmp;
134 cd9ba1eb Paolo Bonzini
        int revents;
135 cd9ba1eb Paolo Bonzini
136 cd9ba1eb Paolo Bonzini
        ctx->walking_handlers++;
137 cd9ba1eb Paolo Bonzini
138 cd9ba1eb Paolo Bonzini
        revents = node->pfd.revents & node->pfd.events;
139 cd9ba1eb Paolo Bonzini
        node->pfd.revents = 0;
140 cd9ba1eb Paolo Bonzini
141 d0c8d2c0 Stefan Hajnoczi
        if (!node->deleted &&
142 d0c8d2c0 Stefan Hajnoczi
            (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
143 d0c8d2c0 Stefan Hajnoczi
            node->io_read) {
144 cd9ba1eb Paolo Bonzini
            node->io_read(node->opaque);
145 164a101f Stefan Hajnoczi
146 164a101f Stefan Hajnoczi
            /* aio_notify() does not count as progress */
147 164a101f Stefan Hajnoczi
            if (node->opaque != &ctx->notifier) {
148 164a101f Stefan Hajnoczi
                progress = true;
149 164a101f Stefan Hajnoczi
            }
150 cd9ba1eb Paolo Bonzini
        }
151 d0c8d2c0 Stefan Hajnoczi
        if (!node->deleted &&
152 d0c8d2c0 Stefan Hajnoczi
            (revents & (G_IO_OUT | G_IO_ERR)) &&
153 d0c8d2c0 Stefan Hajnoczi
            node->io_write) {
154 cd9ba1eb Paolo Bonzini
            node->io_write(node->opaque);
155 cd9ba1eb Paolo Bonzini
            progress = true;
156 cd9ba1eb Paolo Bonzini
        }
157 cd9ba1eb Paolo Bonzini
158 cd9ba1eb Paolo Bonzini
        tmp = node;
159 cd9ba1eb Paolo Bonzini
        node = QLIST_NEXT(node, node);
160 cd9ba1eb Paolo Bonzini
161 cd9ba1eb Paolo Bonzini
        ctx->walking_handlers--;
162 cd9ba1eb Paolo Bonzini
163 cd9ba1eb Paolo Bonzini
        if (!ctx->walking_handlers && tmp->deleted) {
164 cd9ba1eb Paolo Bonzini
            QLIST_REMOVE(tmp, node);
165 cd9ba1eb Paolo Bonzini
            g_free(tmp);
166 cd9ba1eb Paolo Bonzini
        }
167 cd9ba1eb Paolo Bonzini
    }
168 d0c8d2c0 Stefan Hajnoczi
    return progress;
169 d0c8d2c0 Stefan Hajnoczi
}
170 d0c8d2c0 Stefan Hajnoczi
171 d0c8d2c0 Stefan Hajnoczi
bool aio_poll(AioContext *ctx, bool blocking)
172 d0c8d2c0 Stefan Hajnoczi
{
173 d0c8d2c0 Stefan Hajnoczi
    AioHandler *node;
174 d0c8d2c0 Stefan Hajnoczi
    int ret;
175 164a101f Stefan Hajnoczi
    bool progress;
176 d0c8d2c0 Stefan Hajnoczi
177 d0c8d2c0 Stefan Hajnoczi
    progress = false;
178 d0c8d2c0 Stefan Hajnoczi
179 d0c8d2c0 Stefan Hajnoczi
    /*
180 d0c8d2c0 Stefan Hajnoczi
     * If there are callbacks left that have been queued, we need to call them.
181 d0c8d2c0 Stefan Hajnoczi
     * Do not call select in this case, because it is possible that the caller
182 d0c8d2c0 Stefan Hajnoczi
     * does not need a complete flush (as is the case for qemu_aio_wait loops).
183 d0c8d2c0 Stefan Hajnoczi
     */
184 d0c8d2c0 Stefan Hajnoczi
    if (aio_bh_poll(ctx)) {
185 d0c8d2c0 Stefan Hajnoczi
        blocking = false;
186 d0c8d2c0 Stefan Hajnoczi
        progress = true;
187 d0c8d2c0 Stefan Hajnoczi
    }
188 d0c8d2c0 Stefan Hajnoczi
189 d0c8d2c0 Stefan Hajnoczi
    if (aio_dispatch(ctx)) {
190 d0c8d2c0 Stefan Hajnoczi
        progress = true;
191 d0c8d2c0 Stefan Hajnoczi
    }
192 cd9ba1eb Paolo Bonzini
193 7c0628b2 Paolo Bonzini
    if (progress && !blocking) {
194 bcdc1857 Paolo Bonzini
        return true;
195 bafbd6a1 Paolo Bonzini
    }
196 8febfa26 Kevin Wolf
197 a915f4bc Paolo Bonzini
    ctx->walking_handlers++;
198 a76bab49 aliguori
199 6b5f8762 Stefan Hajnoczi
    g_array_set_size(ctx->pollfds, 0);
200 a76bab49 aliguori
201 6b5f8762 Stefan Hajnoczi
    /* fill pollfds */
202 a915f4bc Paolo Bonzini
    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
203 6b5f8762 Stefan Hajnoczi
        node->pollfds_idx = -1;
204 6b5f8762 Stefan Hajnoczi
        if (!node->deleted && node->pfd.events) {
205 6b5f8762 Stefan Hajnoczi
            GPollFD pfd = {
206 6b5f8762 Stefan Hajnoczi
                .fd = node->pfd.fd,
207 6b5f8762 Stefan Hajnoczi
                .events = node->pfd.events,
208 6b5f8762 Stefan Hajnoczi
            };
209 6b5f8762 Stefan Hajnoczi
            node->pollfds_idx = ctx->pollfds->len;
210 6b5f8762 Stefan Hajnoczi
            g_array_append_val(ctx->pollfds, pfd);
211 9eb0bfca Paolo Bonzini
        }
212 9eb0bfca Paolo Bonzini
    }
213 a76bab49 aliguori
214 a915f4bc Paolo Bonzini
    ctx->walking_handlers--;
215 a76bab49 aliguori
216 164a101f Stefan Hajnoczi
    /* early return if we only have the aio_notify() fd */
217 164a101f Stefan Hajnoczi
    if (ctx->pollfds->len == 1) {
218 7c0628b2 Paolo Bonzini
        return progress;
219 9eb0bfca Paolo Bonzini
    }
220 a76bab49 aliguori
221 9eb0bfca Paolo Bonzini
    /* wait until next event */
222 6b5f8762 Stefan Hajnoczi
    ret = g_poll((GPollFD *)ctx->pollfds->data,
223 6b5f8762 Stefan Hajnoczi
                 ctx->pollfds->len,
224 6b5f8762 Stefan Hajnoczi
                 blocking ? -1 : 0);
225 9eb0bfca Paolo Bonzini
226 9eb0bfca Paolo Bonzini
    /* if we have any readable fds, dispatch event */
227 9eb0bfca Paolo Bonzini
    if (ret > 0) {
228 6b5f8762 Stefan Hajnoczi
        QLIST_FOREACH(node, &ctx->aio_handlers, node) {
229 6b5f8762 Stefan Hajnoczi
            if (node->pollfds_idx != -1) {
230 6b5f8762 Stefan Hajnoczi
                GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
231 6b5f8762 Stefan Hajnoczi
                                              node->pollfds_idx);
232 6b5f8762 Stefan Hajnoczi
                node->pfd.revents = pfd->revents;
233 9eb0bfca Paolo Bonzini
            }
234 a76bab49 aliguori
        }
235 6b5f8762 Stefan Hajnoczi
        if (aio_dispatch(ctx)) {
236 6b5f8762 Stefan Hajnoczi
            progress = true;
237 6b5f8762 Stefan Hajnoczi
        }
238 9eb0bfca Paolo Bonzini
    }
239 bcdc1857 Paolo Bonzini
240 164a101f Stefan Hajnoczi
    return progress;
241 a76bab49 aliguori
}