Statistics
| Branch: | Revision:

root / aio-posix.c @ feature-archipelago

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 438e1f47 Alex Bligh
169 438e1f47 Alex Bligh
    /* Run our timers */
170 438e1f47 Alex Bligh
    progress |= timerlistgroup_run_timers(&ctx->tlg);
171 438e1f47 Alex Bligh
172 d0c8d2c0 Stefan Hajnoczi
    return progress;
173 d0c8d2c0 Stefan Hajnoczi
}
174 d0c8d2c0 Stefan Hajnoczi
175 d0c8d2c0 Stefan Hajnoczi
bool aio_poll(AioContext *ctx, bool blocking)
176 d0c8d2c0 Stefan Hajnoczi
{
177 d0c8d2c0 Stefan Hajnoczi
    AioHandler *node;
178 d0c8d2c0 Stefan Hajnoczi
    int ret;
179 164a101f Stefan Hajnoczi
    bool progress;
180 d0c8d2c0 Stefan Hajnoczi
181 d0c8d2c0 Stefan Hajnoczi
    progress = false;
182 d0c8d2c0 Stefan Hajnoczi
183 d0c8d2c0 Stefan Hajnoczi
    /*
184 d0c8d2c0 Stefan Hajnoczi
     * If there are callbacks left that have been queued, we need to call them.
185 d0c8d2c0 Stefan Hajnoczi
     * Do not call select in this case, because it is possible that the caller
186 d0c8d2c0 Stefan Hajnoczi
     * does not need a complete flush (as is the case for qemu_aio_wait loops).
187 d0c8d2c0 Stefan Hajnoczi
     */
188 d0c8d2c0 Stefan Hajnoczi
    if (aio_bh_poll(ctx)) {
189 d0c8d2c0 Stefan Hajnoczi
        blocking = false;
190 d0c8d2c0 Stefan Hajnoczi
        progress = true;
191 d0c8d2c0 Stefan Hajnoczi
    }
192 d0c8d2c0 Stefan Hajnoczi
193 d0c8d2c0 Stefan Hajnoczi
    if (aio_dispatch(ctx)) {
194 d0c8d2c0 Stefan Hajnoczi
        progress = true;
195 d0c8d2c0 Stefan Hajnoczi
    }
196 cd9ba1eb Paolo Bonzini
197 7c0628b2 Paolo Bonzini
    if (progress && !blocking) {
198 bcdc1857 Paolo Bonzini
        return true;
199 bafbd6a1 Paolo Bonzini
    }
200 8febfa26 Kevin Wolf
201 a915f4bc Paolo Bonzini
    ctx->walking_handlers++;
202 a76bab49 aliguori
203 6b5f8762 Stefan Hajnoczi
    g_array_set_size(ctx->pollfds, 0);
204 a76bab49 aliguori
205 6b5f8762 Stefan Hajnoczi
    /* fill pollfds */
206 a915f4bc Paolo Bonzini
    QLIST_FOREACH(node, &ctx->aio_handlers, node) {
207 6b5f8762 Stefan Hajnoczi
        node->pollfds_idx = -1;
208 6b5f8762 Stefan Hajnoczi
        if (!node->deleted && node->pfd.events) {
209 6b5f8762 Stefan Hajnoczi
            GPollFD pfd = {
210 6b5f8762 Stefan Hajnoczi
                .fd = node->pfd.fd,
211 6b5f8762 Stefan Hajnoczi
                .events = node->pfd.events,
212 6b5f8762 Stefan Hajnoczi
            };
213 6b5f8762 Stefan Hajnoczi
            node->pollfds_idx = ctx->pollfds->len;
214 6b5f8762 Stefan Hajnoczi
            g_array_append_val(ctx->pollfds, pfd);
215 9eb0bfca Paolo Bonzini
        }
216 9eb0bfca Paolo Bonzini
    }
217 a76bab49 aliguori
218 a915f4bc Paolo Bonzini
    ctx->walking_handlers--;
219 a76bab49 aliguori
220 9eb0bfca Paolo Bonzini
    /* wait until next event */
221 438e1f47 Alex Bligh
    ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data,
222 438e1f47 Alex Bligh
                         ctx->pollfds->len,
223 438e1f47 Alex Bligh
                         blocking ? timerlistgroup_deadline_ns(&ctx->tlg) : 0);
224 9eb0bfca Paolo Bonzini
225 9eb0bfca Paolo Bonzini
    /* if we have any readable fds, dispatch event */
226 9eb0bfca Paolo Bonzini
    if (ret > 0) {
227 6b5f8762 Stefan Hajnoczi
        QLIST_FOREACH(node, &ctx->aio_handlers, node) {
228 6b5f8762 Stefan Hajnoczi
            if (node->pollfds_idx != -1) {
229 6b5f8762 Stefan Hajnoczi
                GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
230 6b5f8762 Stefan Hajnoczi
                                              node->pollfds_idx);
231 6b5f8762 Stefan Hajnoczi
                node->pfd.revents = pfd->revents;
232 9eb0bfca Paolo Bonzini
            }
233 a76bab49 aliguori
        }
234 438e1f47 Alex Bligh
    }
235 438e1f47 Alex Bligh
236 438e1f47 Alex Bligh
    /* Run dispatch even if there were no readable fds to run timers */
237 438e1f47 Alex Bligh
    if (aio_dispatch(ctx)) {
238 438e1f47 Alex Bligh
        progress = true;
239 9eb0bfca Paolo Bonzini
    }
240 bcdc1857 Paolo Bonzini
241 164a101f Stefan Hajnoczi
    return progress;
242 a76bab49 aliguori
}