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