xref: /openbmc/qemu/io/channel.c (revision b917da4c)
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 "qemu/coroutine.h"
24 
25 bool qio_channel_has_feature(QIOChannel *ioc,
26                              QIOChannelFeature feature)
27 {
28     return ioc->features & (1 << feature);
29 }
30 
31 
32 ssize_t qio_channel_readv_full(QIOChannel *ioc,
33                                const struct iovec *iov,
34                                size_t niov,
35                                int **fds,
36                                size_t *nfds,
37                                Error **errp)
38 {
39     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
40 
41     if ((fds || nfds) &&
42         !(ioc->features & (1 << QIO_CHANNEL_FEATURE_FD_PASS))) {
43         error_setg_errno(errp, EINVAL,
44                          "Channel does not support file descriptor passing");
45         return -1;
46     }
47 
48     return klass->io_readv(ioc, iov, niov, fds, nfds, errp);
49 }
50 
51 
52 ssize_t qio_channel_writev_full(QIOChannel *ioc,
53                                 const struct iovec *iov,
54                                 size_t niov,
55                                 int *fds,
56                                 size_t nfds,
57                                 Error **errp)
58 {
59     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
60 
61     if ((fds || nfds) &&
62         !(ioc->features & (1 << QIO_CHANNEL_FEATURE_FD_PASS))) {
63         error_setg_errno(errp, EINVAL,
64                          "Channel does not support file descriptor passing");
65         return -1;
66     }
67 
68     return klass->io_writev(ioc, iov, niov, fds, nfds, errp);
69 }
70 
71 
72 ssize_t qio_channel_readv(QIOChannel *ioc,
73                           const struct iovec *iov,
74                           size_t niov,
75                           Error **errp)
76 {
77     return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, errp);
78 }
79 
80 
81 ssize_t qio_channel_writev(QIOChannel *ioc,
82                            const struct iovec *iov,
83                            size_t niov,
84                            Error **errp)
85 {
86     return qio_channel_writev_full(ioc, iov, niov, NULL, 0, errp);
87 }
88 
89 
90 ssize_t qio_channel_read(QIOChannel *ioc,
91                          char *buf,
92                          size_t buflen,
93                          Error **errp)
94 {
95     struct iovec iov = { .iov_base = buf, .iov_len = buflen };
96     return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, errp);
97 }
98 
99 
100 ssize_t qio_channel_write(QIOChannel *ioc,
101                           const char *buf,
102                           size_t buflen,
103                           Error **errp)
104 {
105     struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
106     return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, errp);
107 }
108 
109 
110 int qio_channel_set_blocking(QIOChannel *ioc,
111                               bool enabled,
112                               Error **errp)
113 {
114     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
115     return klass->io_set_blocking(ioc, enabled, errp);
116 }
117 
118 
119 int qio_channel_close(QIOChannel *ioc,
120                       Error **errp)
121 {
122     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
123     return klass->io_close(ioc, errp);
124 }
125 
126 
127 GSource *qio_channel_create_watch(QIOChannel *ioc,
128                                   GIOCondition condition)
129 {
130     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
131     return klass->io_create_watch(ioc, condition);
132 }
133 
134 
135 guint qio_channel_add_watch(QIOChannel *ioc,
136                             GIOCondition condition,
137                             QIOChannelFunc func,
138                             gpointer user_data,
139                             GDestroyNotify notify)
140 {
141     GSource *source;
142     guint id;
143 
144     source = qio_channel_create_watch(ioc, condition);
145 
146     g_source_set_callback(source, (GSourceFunc)func, user_data, notify);
147 
148     id = g_source_attach(source, NULL);
149     g_source_unref(source);
150 
151     return id;
152 }
153 
154 
155 int qio_channel_shutdown(QIOChannel *ioc,
156                          QIOChannelShutdown how,
157                          Error **errp)
158 {
159     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
160 
161     if (!klass->io_shutdown) {
162         error_setg(errp, "Data path shutdown not supported");
163         return -1;
164     }
165 
166     return klass->io_shutdown(ioc, how, errp);
167 }
168 
169 
170 void qio_channel_set_delay(QIOChannel *ioc,
171                            bool enabled)
172 {
173     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
174 
175     if (klass->io_set_delay) {
176         klass->io_set_delay(ioc, enabled);
177     }
178 }
179 
180 
181 void qio_channel_set_cork(QIOChannel *ioc,
182                           bool enabled)
183 {
184     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
185 
186     if (klass->io_set_cork) {
187         klass->io_set_cork(ioc, enabled);
188     }
189 }
190 
191 
192 off_t qio_channel_io_seek(QIOChannel *ioc,
193                           off_t offset,
194                           int whence,
195                           Error **errp)
196 {
197     QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
198 
199     if (!klass->io_seek) {
200         error_setg(errp, "Channel does not support random access");
201         return -1;
202     }
203 
204     return klass->io_seek(ioc, offset, whence, errp);
205 }
206 
207 
208 typedef struct QIOChannelYieldData QIOChannelYieldData;
209 struct QIOChannelYieldData {
210     QIOChannel *ioc;
211     Coroutine *co;
212 };
213 
214 
215 static gboolean qio_channel_yield_enter(QIOChannel *ioc,
216                                         GIOCondition condition,
217                                         gpointer opaque)
218 {
219     QIOChannelYieldData *data = opaque;
220     qemu_coroutine_enter(data->co, NULL);
221     return FALSE;
222 }
223 
224 
225 void coroutine_fn qio_channel_yield(QIOChannel *ioc,
226                                     GIOCondition condition)
227 {
228     QIOChannelYieldData data;
229 
230     assert(qemu_in_coroutine());
231     data.ioc = ioc;
232     data.co = qemu_coroutine_self();
233     qio_channel_add_watch(ioc,
234                           condition,
235                           qio_channel_yield_enter,
236                           &data,
237                           NULL);
238     qemu_coroutine_yield();
239 }
240 
241 
242 static gboolean qio_channel_wait_complete(QIOChannel *ioc,
243                                           GIOCondition condition,
244                                           gpointer opaque)
245 {
246     GMainLoop *loop = opaque;
247 
248     g_main_loop_quit(loop);
249     return FALSE;
250 }
251 
252 
253 void qio_channel_wait(QIOChannel *ioc,
254                       GIOCondition condition)
255 {
256     GMainContext *ctxt = g_main_context_new();
257     GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
258     GSource *source;
259 
260     source = qio_channel_create_watch(ioc, condition);
261 
262     g_source_set_callback(source,
263                           (GSourceFunc)qio_channel_wait_complete,
264                           loop,
265                           NULL);
266 
267     g_source_attach(source, ctxt);
268 
269     g_main_loop_run(loop);
270 
271     g_source_unref(source);
272     g_main_loop_unref(loop);
273     g_main_context_unref(ctxt);
274 }
275 
276 
277 #ifdef _WIN32
278 static void qio_channel_finalize(Object *obj)
279 {
280     QIOChannel *ioc = QIO_CHANNEL(obj);
281 
282     if (ioc->event) {
283         CloseHandle(ioc->event);
284     }
285 }
286 #endif
287 
288 static const TypeInfo qio_channel_info = {
289     .parent = TYPE_OBJECT,
290     .name = TYPE_QIO_CHANNEL,
291     .instance_size = sizeof(QIOChannel),
292 #ifdef _WIN32
293     .instance_finalize = qio_channel_finalize,
294 #endif
295     .abstract = true,
296     .class_size = sizeof(QIOChannelClass),
297 };
298 
299 
300 static void qio_channel_register_types(void)
301 {
302     type_register_static(&qio_channel_info);
303 }
304 
305 
306 type_init(qio_channel_register_types);
307