xref: /openbmc/qemu/io/channel.c (revision 7562f907)
1 /*
2  * QEMU I/O channels
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "qemu/osdep.h"
22 #include "io/channel.h"
23 #include "qapi/error.h"
24 #include "qemu/main-loop.h"
25 
26 bool qio_channel_has_feature(QIOChannel *ioc,
27                              QIOChannelFeature feature)
28 {
29     return ioc->features & (1 << feature);
30 }
31 
32 
33 void qio_channel_set_feature(QIOChannel *ioc,
34                              QIOChannelFeature feature)
35 {
36     ioc->features |= (1 << feature);
37 }
38 
39 
40 void qio_channel_set_name(QIOChannel *ioc,
41                           const char *name)
42 {
43     g_free(ioc->name);
44     ioc->name = g_strdup(name);
45 }
46 
47 
48 ssize_t qio_channel_readv_full(QIOChannel *ioc,
49                                const struct iovec *iov,
50                                size_t niov,
51                                int **fds,
52                                size_t *nfds,
53                                Error **errp)
54 {
55     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
56 
57     if ((fds || nfds) &&
58         !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
59         error_setg_errno(errp, EINVAL,
60                          "Channel does not support file descriptor passing");
61         return -1;
62     }
63 
64     return klass->io_readv(ioc, iov, niov, fds, nfds, errp);
65 }
66 
67 
68 ssize_t qio_channel_writev_full(QIOChannel *ioc,
69                                 const struct iovec *iov,
70                                 size_t niov,
71                                 int *fds,
72                                 size_t nfds,
73                                 Error **errp)
74 {
75     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
76 
77     if ((fds || nfds) &&
78         !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
79         error_setg_errno(errp, EINVAL,
80                          "Channel does not support file descriptor passing");
81         return -1;
82     }
83 
84     return klass->io_writev(ioc, iov, niov, fds, nfds, errp);
85 }
86 
87 
88 ssize_t qio_channel_readv(QIOChannel *ioc,
89                           const struct iovec *iov,
90                           size_t niov,
91                           Error **errp)
92 {
93     return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, errp);
94 }
95 
96 
97 ssize_t qio_channel_writev(QIOChannel *ioc,
98                            const struct iovec *iov,
99                            size_t niov,
100                            Error **errp)
101 {
102     return qio_channel_writev_full(ioc, iov, niov, NULL, 0, errp);
103 }
104 
105 
106 ssize_t qio_channel_read(QIOChannel *ioc,
107                          char *buf,
108                          size_t buflen,
109                          Error **errp)
110 {
111     struct iovec iov = { .iov_base = buf, .iov_len = buflen };
112     return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, errp);
113 }
114 
115 
116 ssize_t qio_channel_write(QIOChannel *ioc,
117                           const char *buf,
118                           size_t buflen,
119                           Error **errp)
120 {
121     struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
122     return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, errp);
123 }
124 
125 
126 int qio_channel_set_blocking(QIOChannel *ioc,
127                               bool enabled,
128                               Error **errp)
129 {
130     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
131     return klass->io_set_blocking(ioc, enabled, errp);
132 }
133 
134 
135 int qio_channel_close(QIOChannel *ioc,
136                       Error **errp)
137 {
138     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
139     return klass->io_close(ioc, errp);
140 }
141 
142 
143 GSource *qio_channel_create_watch(QIOChannel *ioc,
144                                   GIOCondition condition)
145 {
146     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
147     GSource *ret = klass->io_create_watch(ioc, condition);
148 
149     if (ioc->name) {
150         g_source_set_name(ret, ioc->name);
151     }
152 
153     return ret;
154 }
155 
156 
157 void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
158                                     AioContext *ctx,
159                                     IOHandler *io_read,
160                                     IOHandler *io_write,
161                                     void *opaque)
162 {
163     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
164 
165     klass->io_set_aio_fd_handler(ioc, ctx, io_read, io_write, opaque);
166 }
167 
168 guint qio_channel_add_watch(QIOChannel *ioc,
169                             GIOCondition condition,
170                             QIOChannelFunc func,
171                             gpointer user_data,
172                             GDestroyNotify notify)
173 {
174     GSource *source;
175     guint id;
176 
177     source = qio_channel_create_watch(ioc, condition);
178 
179     g_source_set_callback(source, (GSourceFunc)func, user_data, notify);
180 
181     id = g_source_attach(source, NULL);
182     g_source_unref(source);
183 
184     return id;
185 }
186 
187 
188 int qio_channel_shutdown(QIOChannel *ioc,
189                          QIOChannelShutdown how,
190                          Error **errp)
191 {
192     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
193 
194     if (!klass->io_shutdown) {
195         error_setg(errp, "Data path shutdown not supported");
196         return -1;
197     }
198 
199     return klass->io_shutdown(ioc, how, errp);
200 }
201 
202 
203 void qio_channel_set_delay(QIOChannel *ioc,
204                            bool enabled)
205 {
206     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
207 
208     if (klass->io_set_delay) {
209         klass->io_set_delay(ioc, enabled);
210     }
211 }
212 
213 
214 void qio_channel_set_cork(QIOChannel *ioc,
215                           bool enabled)
216 {
217     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
218 
219     if (klass->io_set_cork) {
220         klass->io_set_cork(ioc, enabled);
221     }
222 }
223 
224 
225 off_t qio_channel_io_seek(QIOChannel *ioc,
226                           off_t offset,
227                           int whence,
228                           Error **errp)
229 {
230     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
231 
232     if (!klass->io_seek) {
233         error_setg(errp, "Channel does not support random access");
234         return -1;
235     }
236 
237     return klass->io_seek(ioc, offset, whence, errp);
238 }
239 
240 
241 static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc);
242 
243 static void qio_channel_restart_read(void *opaque)
244 {
245     QIOChannel *ioc = opaque;
246     Coroutine *co = ioc->read_coroutine;
247 
248     ioc->read_coroutine = NULL;
249     qio_channel_set_aio_fd_handlers(ioc);
250     aio_co_wake(co);
251 }
252 
253 static void qio_channel_restart_write(void *opaque)
254 {
255     QIOChannel *ioc = opaque;
256     Coroutine *co = ioc->write_coroutine;
257 
258     ioc->write_coroutine = NULL;
259     qio_channel_set_aio_fd_handlers(ioc);
260     aio_co_wake(co);
261 }
262 
263 static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc)
264 {
265     IOHandler *rd_handler = NULL, *wr_handler = NULL;
266     AioContext *ctx;
267 
268     if (ioc->read_coroutine) {
269         rd_handler = qio_channel_restart_read;
270     }
271     if (ioc->write_coroutine) {
272         wr_handler = qio_channel_restart_write;
273     }
274 
275     ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context();
276     qio_channel_set_aio_fd_handler(ioc, ctx, rd_handler, wr_handler, ioc);
277 }
278 
279 void qio_channel_attach_aio_context(QIOChannel *ioc,
280                                     AioContext *ctx)
281 {
282     AioContext *old_ctx;
283     if (ioc->ctx == ctx) {
284         return;
285     }
286 
287     old_ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context();
288     qio_channel_set_aio_fd_handler(ioc, old_ctx, NULL, NULL, NULL);
289     ioc->ctx = ctx;
290     qio_channel_set_aio_fd_handlers(ioc);
291 }
292 
293 void qio_channel_detach_aio_context(QIOChannel *ioc)
294 {
295     ioc->read_coroutine = NULL;
296     ioc->write_coroutine = NULL;
297     qio_channel_set_aio_fd_handlers(ioc);
298     ioc->ctx = NULL;
299 }
300 
301 void coroutine_fn qio_channel_yield(QIOChannel *ioc,
302                                     GIOCondition condition)
303 {
304     assert(qemu_in_coroutine());
305     if (condition == G_IO_IN) {
306         assert(!ioc->read_coroutine);
307         ioc->read_coroutine = qemu_coroutine_self();
308     } else if (condition == G_IO_OUT) {
309         assert(!ioc->write_coroutine);
310         ioc->write_coroutine = qemu_coroutine_self();
311     } else {
312         abort();
313     }
314     qio_channel_set_aio_fd_handlers(ioc);
315     qemu_coroutine_yield();
316 }
317 
318 
319 static gboolean qio_channel_wait_complete(QIOChannel *ioc,
320                                           GIOCondition condition,
321                                           gpointer opaque)
322 {
323     GMainLoop *loop = opaque;
324 
325     g_main_loop_quit(loop);
326     return FALSE;
327 }
328 
329 
330 void qio_channel_wait(QIOChannel *ioc,
331                       GIOCondition condition)
332 {
333     GMainContext *ctxt = g_main_context_new();
334     GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
335     GSource *source;
336 
337     source = qio_channel_create_watch(ioc, condition);
338 
339     g_source_set_callback(source,
340                           (GSourceFunc)qio_channel_wait_complete,
341                           loop,
342                           NULL);
343 
344     g_source_attach(source, ctxt);
345 
346     g_main_loop_run(loop);
347 
348     g_source_unref(source);
349     g_main_loop_unref(loop);
350     g_main_context_unref(ctxt);
351 }
352 
353 
354 static void qio_channel_finalize(Object *obj)
355 {
356     QIOChannel *ioc = QIO_CHANNEL(obj);
357 
358     g_free(ioc->name);
359 
360 #ifdef _WIN32
361     if (ioc->event) {
362         CloseHandle(ioc->event);
363     }
364 #endif
365 }
366 
367 static const TypeInfo qio_channel_info = {
368     .parent = TYPE_OBJECT,
369     .name = TYPE_QIO_CHANNEL,
370     .instance_size = sizeof(QIOChannel),
371     .instance_finalize = qio_channel_finalize,
372     .abstract = true,
373     .class_size = sizeof(QIOChannelClass),
374 };
375 
376 
377 static void qio_channel_register_types(void)
378 {
379     type_register_static(&qio_channel_info);
380 }
381 
382 
383 type_init(qio_channel_register_types);
384