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