quorum: Avoid bdrv_aio_writev() for rewrites
[qemu.git] / io / channel.c
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 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 guint qio_channel_add_watch(QIOChannel *ioc,
158 GIOCondition condition,
159 QIOChannelFunc func,
160 gpointer user_data,
161 GDestroyNotify notify)
162 {
163 GSource *source;
164 guint id;
165
166 source = qio_channel_create_watch(ioc, condition);
167
168 g_source_set_callback(source, (GSourceFunc)func, user_data, notify);
169
170 id = g_source_attach(source, NULL);
171 g_source_unref(source);
172
173 return id;
174 }
175
176
177 int qio_channel_shutdown(QIOChannel *ioc,
178 QIOChannelShutdown how,
179 Error **errp)
180 {
181 QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
182
183 if (!klass->io_shutdown) {
184 error_setg(errp, "Data path shutdown not supported");
185 return -1;
186 }
187
188 return klass->io_shutdown(ioc, how, errp);
189 }
190
191
192 void qio_channel_set_delay(QIOChannel *ioc,
193 bool enabled)
194 {
195 QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
196
197 if (klass->io_set_delay) {
198 klass->io_set_delay(ioc, enabled);
199 }
200 }
201
202
203 void qio_channel_set_cork(QIOChannel *ioc,
204 bool enabled)
205 {
206 QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
207
208 if (klass->io_set_cork) {
209 klass->io_set_cork(ioc, enabled);
210 }
211 }
212
213
214 off_t qio_channel_io_seek(QIOChannel *ioc,
215 off_t offset,
216 int whence,
217 Error **errp)
218 {
219 QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
220
221 if (!klass->io_seek) {
222 error_setg(errp, "Channel does not support random access");
223 return -1;
224 }
225
226 return klass->io_seek(ioc, offset, whence, errp);
227 }
228
229
230 typedef struct QIOChannelYieldData QIOChannelYieldData;
231 struct QIOChannelYieldData {
232 QIOChannel *ioc;
233 Coroutine *co;
234 };
235
236
237 static gboolean qio_channel_yield_enter(QIOChannel *ioc,
238 GIOCondition condition,
239 gpointer opaque)
240 {
241 QIOChannelYieldData *data = opaque;
242 qemu_coroutine_enter(data->co);
243 return FALSE;
244 }
245
246
247 void coroutine_fn qio_channel_yield(QIOChannel *ioc,
248 GIOCondition condition)
249 {
250 QIOChannelYieldData data;
251
252 assert(qemu_in_coroutine());
253 data.ioc = ioc;
254 data.co = qemu_coroutine_self();
255 qio_channel_add_watch(ioc,
256 condition,
257 qio_channel_yield_enter,
258 &data,
259 NULL);
260 qemu_coroutine_yield();
261 }
262
263
264 static gboolean qio_channel_wait_complete(QIOChannel *ioc,
265 GIOCondition condition,
266 gpointer opaque)
267 {
268 GMainLoop *loop = opaque;
269
270 g_main_loop_quit(loop);
271 return FALSE;
272 }
273
274
275 void qio_channel_wait(QIOChannel *ioc,
276 GIOCondition condition)
277 {
278 GMainContext *ctxt = g_main_context_new();
279 GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
280 GSource *source;
281
282 source = qio_channel_create_watch(ioc, condition);
283
284 g_source_set_callback(source,
285 (GSourceFunc)qio_channel_wait_complete,
286 loop,
287 NULL);
288
289 g_source_attach(source, ctxt);
290
291 g_main_loop_run(loop);
292
293 g_source_unref(source);
294 g_main_loop_unref(loop);
295 g_main_context_unref(ctxt);
296 }
297
298
299 static void qio_channel_finalize(Object *obj)
300 {
301 QIOChannel *ioc = QIO_CHANNEL(obj);
302
303 g_free(ioc->name);
304
305 #ifdef _WIN32
306 if (ioc->event) {
307 CloseHandle(ioc->event);
308 }
309 #endif
310 }
311
312 static const TypeInfo qio_channel_info = {
313 .parent = TYPE_OBJECT,
314 .name = TYPE_QIO_CHANNEL,
315 .instance_size = sizeof(QIOChannel),
316 .instance_finalize = qio_channel_finalize,
317 .abstract = true,
318 .class_size = sizeof(QIOChannelClass),
319 };
320
321
322 static void qio_channel_register_types(void)
323 {
324 type_register_static(&qio_channel_info);
325 }
326
327
328 type_init(qio_channel_register_types);