]>
Commit | Line | Data |
---|---|---|
666a3af9 DB |
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 | |
c8198bd5 | 9 | * version 2.1 of the License, or (at your option) any later version. |
666a3af9 DB |
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 | ||
cae9fc56 | 21 | #include "qemu/osdep.h" |
666a3af9 | 22 | #include "io/channel.h" |
da34e65c | 23 | #include "qapi/error.h" |
c4c497d2 | 24 | #include "qemu/main-loop.h" |
0b8fa32f | 25 | #include "qemu/module.h" |
d4622e55 | 26 | #include "qemu/iov.h" |
666a3af9 DB |
27 | |
28 | bool qio_channel_has_feature(QIOChannel *ioc, | |
29 | QIOChannelFeature feature) | |
30 | { | |
31 | return ioc->features & (1 << feature); | |
32 | } | |
33 | ||
34 | ||
d8d3c7cc FF |
35 | void qio_channel_set_feature(QIOChannel *ioc, |
36 | QIOChannelFeature feature) | |
37 | { | |
38 | ioc->features |= (1 << feature); | |
39 | } | |
40 | ||
41 | ||
20f4aa26 DB |
42 | void qio_channel_set_name(QIOChannel *ioc, |
43 | const char *name) | |
44 | { | |
45 | g_free(ioc->name); | |
46 | ioc->name = g_strdup(name); | |
47 | } | |
48 | ||
49 | ||
666a3af9 DB |
50 | ssize_t qio_channel_readv_full(QIOChannel *ioc, |
51 | const struct iovec *iov, | |
52 | size_t niov, | |
53 | int **fds, | |
54 | size_t *nfds, | |
55 | Error **errp) | |
56 | { | |
57 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
58 | ||
59 | if ((fds || nfds) && | |
e413ae0c | 60 | !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { |
666a3af9 DB |
61 | error_setg_errno(errp, EINVAL, |
62 | "Channel does not support file descriptor passing"); | |
63 | return -1; | |
64 | } | |
65 | ||
66 | return klass->io_readv(ioc, iov, niov, fds, nfds, errp); | |
67 | } | |
68 | ||
69 | ||
70 | ssize_t qio_channel_writev_full(QIOChannel *ioc, | |
71 | const struct iovec *iov, | |
72 | size_t niov, | |
73 | int *fds, | |
74 | size_t nfds, | |
b88651cb | 75 | int flags, |
666a3af9 DB |
76 | Error **errp) |
77 | { | |
78 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
79 | ||
b88651cb LB |
80 | if (fds || nfds) { |
81 | if (!qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) { | |
82 | error_setg_errno(errp, EINVAL, | |
83 | "Channel does not support file descriptor passing"); | |
84 | return -1; | |
85 | } | |
86 | if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) { | |
87 | error_setg_errno(errp, EINVAL, | |
88 | "Zero Copy does not support file descriptor passing"); | |
89 | return -1; | |
90 | } | |
91 | } | |
92 | ||
93 | if ((flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) && | |
94 | !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { | |
666a3af9 | 95 | error_setg_errno(errp, EINVAL, |
b88651cb | 96 | "Requested Zero Copy feature is not available"); |
666a3af9 DB |
97 | return -1; |
98 | } | |
99 | ||
b88651cb | 100 | return klass->io_writev(ioc, iov, niov, fds, nfds, flags, errp); |
666a3af9 DB |
101 | } |
102 | ||
103 | ||
e8ffaa31 EB |
104 | int qio_channel_readv_all_eof(QIOChannel *ioc, |
105 | const struct iovec *iov, | |
106 | size_t niov, | |
107 | Error **errp) | |
bebab91e EU |
108 | { |
109 | return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp); | |
110 | } | |
111 | ||
112 | int qio_channel_readv_all(QIOChannel *ioc, | |
113 | const struct iovec *iov, | |
114 | size_t niov, | |
115 | Error **errp) | |
116 | { | |
117 | return qio_channel_readv_full_all(ioc, iov, niov, NULL, NULL, errp); | |
118 | } | |
119 | ||
120 | int qio_channel_readv_full_all_eof(QIOChannel *ioc, | |
121 | const struct iovec *iov, | |
122 | size_t niov, | |
123 | int **fds, size_t *nfds, | |
124 | Error **errp) | |
d4622e55 DB |
125 | { |
126 | int ret = -1; | |
127 | struct iovec *local_iov = g_new(struct iovec, niov); | |
128 | struct iovec *local_iov_head = local_iov; | |
129 | unsigned int nlocal_iov = niov; | |
bebab91e EU |
130 | int **local_fds = fds; |
131 | size_t *local_nfds = nfds; | |
e8ffaa31 | 132 | bool partial = false; |
d4622e55 | 133 | |
bebab91e EU |
134 | if (nfds) { |
135 | *nfds = 0; | |
136 | } | |
137 | ||
138 | if (fds) { | |
139 | *fds = NULL; | |
140 | } | |
141 | ||
d4622e55 DB |
142 | nlocal_iov = iov_copy(local_iov, nlocal_iov, |
143 | iov, niov, | |
144 | 0, iov_size(iov, niov)); | |
145 | ||
bebab91e | 146 | while ((nlocal_iov > 0) || local_fds) { |
d4622e55 | 147 | ssize_t len; |
bebab91e EU |
148 | len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds, |
149 | local_nfds, errp); | |
d4622e55 | 150 | if (len == QIO_CHANNEL_ERR_BLOCK) { |
9ffb8270 EB |
151 | if (qemu_in_coroutine()) { |
152 | qio_channel_yield(ioc, G_IO_IN); | |
153 | } else { | |
154 | qio_channel_wait(ioc, G_IO_IN); | |
155 | } | |
d4622e55 | 156 | continue; |
bebab91e EU |
157 | } |
158 | ||
159 | if (len == 0) { | |
160 | if (local_nfds && *local_nfds) { | |
161 | /* | |
162 | * Got some FDs, but no data yet. This isn't an EOF | |
163 | * scenario (yet), so carry on to try to read data | |
164 | * on next loop iteration | |
165 | */ | |
166 | goto next_iter; | |
167 | } else if (!partial) { | |
168 | /* No fds and no data - EOF before any data read */ | |
e8ffaa31 | 169 | ret = 0; |
bebab91e EU |
170 | goto cleanup; |
171 | } else { | |
172 | len = -1; | |
173 | error_setg(errp, | |
174 | "Unexpected end-of-file before all data were read"); | |
175 | /* Fallthrough into len < 0 handling */ | |
176 | } | |
177 | } | |
178 | ||
179 | if (len < 0) { | |
180 | /* Close any FDs we previously received */ | |
181 | if (nfds && fds) { | |
182 | size_t i; | |
183 | for (i = 0; i < (*nfds); i++) { | |
184 | close((*fds)[i]); | |
185 | } | |
186 | g_free(*fds); | |
187 | *fds = NULL; | |
188 | *nfds = 0; | |
e8ffaa31 | 189 | } |
d4622e55 DB |
190 | goto cleanup; |
191 | } | |
192 | ||
bebab91e EU |
193 | if (nlocal_iov) { |
194 | iov_discard_front(&local_iov, &nlocal_iov, len); | |
195 | } | |
196 | ||
197 | next_iter: | |
e8ffaa31 | 198 | partial = true; |
bebab91e EU |
199 | local_fds = NULL; |
200 | local_nfds = NULL; | |
d4622e55 DB |
201 | } |
202 | ||
e8ffaa31 | 203 | ret = 1; |
d4622e55 DB |
204 | |
205 | cleanup: | |
206 | g_free(local_iov_head); | |
207 | return ret; | |
208 | } | |
209 | ||
bebab91e EU |
210 | int qio_channel_readv_full_all(QIOChannel *ioc, |
211 | const struct iovec *iov, | |
212 | size_t niov, | |
213 | int **fds, size_t *nfds, | |
214 | Error **errp) | |
e8ffaa31 | 215 | { |
bebab91e | 216 | int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp); |
e8ffaa31 EB |
217 | |
218 | if (ret == 0) { | |
c90e3512 | 219 | error_setg(errp, "Unexpected end-of-file before all data were read"); |
bebab91e | 220 | return -1; |
e8ffaa31 | 221 | } |
bebab91e EU |
222 | if (ret == 1) { |
223 | return 0; | |
224 | } | |
225 | ||
e8ffaa31 EB |
226 | return ret; |
227 | } | |
228 | ||
d4622e55 DB |
229 | int qio_channel_writev_all(QIOChannel *ioc, |
230 | const struct iovec *iov, | |
231 | size_t niov, | |
232 | Error **errp) | |
bfa42387 | 233 | { |
b88651cb | 234 | return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, 0, errp); |
bfa42387 EU |
235 | } |
236 | ||
237 | int qio_channel_writev_full_all(QIOChannel *ioc, | |
238 | const struct iovec *iov, | |
239 | size_t niov, | |
240 | int *fds, size_t nfds, | |
b88651cb | 241 | int flags, Error **errp) |
d4622e55 DB |
242 | { |
243 | int ret = -1; | |
244 | struct iovec *local_iov = g_new(struct iovec, niov); | |
245 | struct iovec *local_iov_head = local_iov; | |
246 | unsigned int nlocal_iov = niov; | |
247 | ||
248 | nlocal_iov = iov_copy(local_iov, nlocal_iov, | |
249 | iov, niov, | |
250 | 0, iov_size(iov, niov)); | |
251 | ||
252 | while (nlocal_iov > 0) { | |
253 | ssize_t len; | |
b88651cb LB |
254 | |
255 | len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, | |
256 | nfds, flags, errp); | |
257 | ||
d4622e55 | 258 | if (len == QIO_CHANNEL_ERR_BLOCK) { |
9ffb8270 EB |
259 | if (qemu_in_coroutine()) { |
260 | qio_channel_yield(ioc, G_IO_OUT); | |
261 | } else { | |
262 | qio_channel_wait(ioc, G_IO_OUT); | |
263 | } | |
d4622e55 DB |
264 | continue; |
265 | } | |
266 | if (len < 0) { | |
267 | goto cleanup; | |
268 | } | |
269 | ||
270 | iov_discard_front(&local_iov, &nlocal_iov, len); | |
bfa42387 EU |
271 | |
272 | fds = NULL; | |
273 | nfds = 0; | |
d4622e55 DB |
274 | } |
275 | ||
276 | ret = 0; | |
277 | cleanup: | |
278 | g_free(local_iov_head); | |
279 | return ret; | |
280 | } | |
281 | ||
666a3af9 DB |
282 | ssize_t qio_channel_readv(QIOChannel *ioc, |
283 | const struct iovec *iov, | |
284 | size_t niov, | |
285 | Error **errp) | |
286 | { | |
287 | return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, errp); | |
288 | } | |
289 | ||
290 | ||
291 | ssize_t qio_channel_writev(QIOChannel *ioc, | |
292 | const struct iovec *iov, | |
293 | size_t niov, | |
294 | Error **errp) | |
295 | { | |
b88651cb | 296 | return qio_channel_writev_full(ioc, iov, niov, NULL, 0, 0, errp); |
666a3af9 DB |
297 | } |
298 | ||
299 | ||
300 | ssize_t qio_channel_read(QIOChannel *ioc, | |
301 | char *buf, | |
302 | size_t buflen, | |
303 | Error **errp) | |
304 | { | |
305 | struct iovec iov = { .iov_base = buf, .iov_len = buflen }; | |
306 | return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, errp); | |
307 | } | |
308 | ||
309 | ||
310 | ssize_t qio_channel_write(QIOChannel *ioc, | |
311 | const char *buf, | |
312 | size_t buflen, | |
313 | Error **errp) | |
314 | { | |
315 | struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; | |
b88651cb | 316 | return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, 0, errp); |
666a3af9 DB |
317 | } |
318 | ||
319 | ||
e8ffaa31 EB |
320 | int qio_channel_read_all_eof(QIOChannel *ioc, |
321 | char *buf, | |
322 | size_t buflen, | |
323 | Error **errp) | |
324 | { | |
325 | struct iovec iov = { .iov_base = buf, .iov_len = buflen }; | |
326 | return qio_channel_readv_all_eof(ioc, &iov, 1, errp); | |
327 | } | |
328 | ||
329 | ||
d4622e55 DB |
330 | int qio_channel_read_all(QIOChannel *ioc, |
331 | char *buf, | |
332 | size_t buflen, | |
333 | Error **errp) | |
334 | { | |
335 | struct iovec iov = { .iov_base = buf, .iov_len = buflen }; | |
336 | return qio_channel_readv_all(ioc, &iov, 1, errp); | |
337 | } | |
338 | ||
339 | ||
340 | int qio_channel_write_all(QIOChannel *ioc, | |
341 | const char *buf, | |
342 | size_t buflen, | |
343 | Error **errp) | |
344 | { | |
345 | struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; | |
346 | return qio_channel_writev_all(ioc, &iov, 1, errp); | |
347 | } | |
348 | ||
349 | ||
666a3af9 DB |
350 | int qio_channel_set_blocking(QIOChannel *ioc, |
351 | bool enabled, | |
352 | Error **errp) | |
353 | { | |
354 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
355 | return klass->io_set_blocking(ioc, enabled, errp); | |
356 | } | |
357 | ||
358 | ||
359 | int qio_channel_close(QIOChannel *ioc, | |
360 | Error **errp) | |
361 | { | |
362 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
363 | return klass->io_close(ioc, errp); | |
364 | } | |
365 | ||
366 | ||
367 | GSource *qio_channel_create_watch(QIOChannel *ioc, | |
368 | GIOCondition condition) | |
369 | { | |
370 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
20f4aa26 DB |
371 | GSource *ret = klass->io_create_watch(ioc, condition); |
372 | ||
373 | if (ioc->name) { | |
374 | g_source_set_name(ret, ioc->name); | |
375 | } | |
376 | ||
377 | return ret; | |
666a3af9 DB |
378 | } |
379 | ||
380 | ||
bf88c124 PB |
381 | void qio_channel_set_aio_fd_handler(QIOChannel *ioc, |
382 | AioContext *ctx, | |
383 | IOHandler *io_read, | |
384 | IOHandler *io_write, | |
385 | void *opaque) | |
386 | { | |
387 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
388 | ||
389 | klass->io_set_aio_fd_handler(ioc, ctx, io_read, io_write, opaque); | |
390 | } | |
391 | ||
315409c7 PX |
392 | guint qio_channel_add_watch_full(QIOChannel *ioc, |
393 | GIOCondition condition, | |
394 | QIOChannelFunc func, | |
395 | gpointer user_data, | |
396 | GDestroyNotify notify, | |
397 | GMainContext *context) | |
666a3af9 DB |
398 | { |
399 | GSource *source; | |
400 | guint id; | |
401 | ||
402 | source = qio_channel_create_watch(ioc, condition); | |
403 | ||
404 | g_source_set_callback(source, (GSourceFunc)func, user_data, notify); | |
405 | ||
315409c7 | 406 | id = g_source_attach(source, context); |
666a3af9 DB |
407 | g_source_unref(source); |
408 | ||
409 | return id; | |
410 | } | |
411 | ||
315409c7 PX |
412 | guint qio_channel_add_watch(QIOChannel *ioc, |
413 | GIOCondition condition, | |
414 | QIOChannelFunc func, | |
415 | gpointer user_data, | |
416 | GDestroyNotify notify) | |
417 | { | |
418 | return qio_channel_add_watch_full(ioc, condition, func, | |
419 | user_data, notify, NULL); | |
420 | } | |
421 | ||
422 | GSource *qio_channel_add_watch_source(QIOChannel *ioc, | |
423 | GIOCondition condition, | |
424 | QIOChannelFunc func, | |
425 | gpointer user_data, | |
426 | GDestroyNotify notify, | |
427 | GMainContext *context) | |
428 | { | |
429 | GSource *source; | |
430 | guint id; | |
431 | ||
432 | id = qio_channel_add_watch_full(ioc, condition, func, | |
433 | user_data, notify, context); | |
434 | source = g_main_context_find_source_by_id(context, id); | |
435 | g_source_ref(source); | |
436 | return source; | |
437 | } | |
438 | ||
666a3af9 DB |
439 | |
440 | int qio_channel_shutdown(QIOChannel *ioc, | |
441 | QIOChannelShutdown how, | |
442 | Error **errp) | |
443 | { | |
444 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
445 | ||
446 | if (!klass->io_shutdown) { | |
447 | error_setg(errp, "Data path shutdown not supported"); | |
448 | return -1; | |
449 | } | |
450 | ||
451 | return klass->io_shutdown(ioc, how, errp); | |
452 | } | |
453 | ||
454 | ||
455 | void qio_channel_set_delay(QIOChannel *ioc, | |
456 | bool enabled) | |
457 | { | |
458 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
459 | ||
460 | if (klass->io_set_delay) { | |
461 | klass->io_set_delay(ioc, enabled); | |
462 | } | |
463 | } | |
464 | ||
465 | ||
466 | void qio_channel_set_cork(QIOChannel *ioc, | |
467 | bool enabled) | |
468 | { | |
469 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
470 | ||
471 | if (klass->io_set_cork) { | |
472 | klass->io_set_cork(ioc, enabled); | |
473 | } | |
474 | } | |
475 | ||
476 | ||
477 | off_t qio_channel_io_seek(QIOChannel *ioc, | |
478 | off_t offset, | |
479 | int whence, | |
480 | Error **errp) | |
481 | { | |
482 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
483 | ||
484 | if (!klass->io_seek) { | |
485 | error_setg(errp, "Channel does not support random access"); | |
486 | return -1; | |
487 | } | |
488 | ||
489 | return klass->io_seek(ioc, offset, whence, errp); | |
490 | } | |
491 | ||
b88651cb LB |
492 | int qio_channel_flush(QIOChannel *ioc, |
493 | Error **errp) | |
494 | { | |
495 | QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc); | |
496 | ||
497 | if (!klass->io_flush || | |
498 | !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { | |
499 | return 0; | |
500 | } | |
501 | ||
502 | return klass->io_flush(ioc, errp); | |
503 | } | |
504 | ||
666a3af9 | 505 | |
c4c497d2 PB |
506 | static void qio_channel_restart_read(void *opaque) |
507 | { | |
508 | QIOChannel *ioc = opaque; | |
509 | Coroutine *co = ioc->read_coroutine; | |
510 | ||
2a239e6e KW |
511 | /* Assert that aio_co_wake() reenters the coroutine directly */ |
512 | assert(qemu_get_current_aio_context() == | |
513 | qemu_coroutine_get_aio_context(co)); | |
c4c497d2 PB |
514 | aio_co_wake(co); |
515 | } | |
666a3af9 | 516 | |
c4c497d2 | 517 | static void qio_channel_restart_write(void *opaque) |
666a3af9 | 518 | { |
c4c497d2 PB |
519 | QIOChannel *ioc = opaque; |
520 | Coroutine *co = ioc->write_coroutine; | |
521 | ||
2a239e6e KW |
522 | /* Assert that aio_co_wake() reenters the coroutine directly */ |
523 | assert(qemu_get_current_aio_context() == | |
524 | qemu_coroutine_get_aio_context(co)); | |
c4c497d2 | 525 | aio_co_wake(co); |
666a3af9 DB |
526 | } |
527 | ||
c4c497d2 PB |
528 | static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc) |
529 | { | |
530 | IOHandler *rd_handler = NULL, *wr_handler = NULL; | |
531 | AioContext *ctx; | |
532 | ||
533 | if (ioc->read_coroutine) { | |
534 | rd_handler = qio_channel_restart_read; | |
535 | } | |
536 | if (ioc->write_coroutine) { | |
537 | wr_handler = qio_channel_restart_write; | |
538 | } | |
539 | ||
540 | ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context(); | |
541 | qio_channel_set_aio_fd_handler(ioc, ctx, rd_handler, wr_handler, ioc); | |
542 | } | |
543 | ||
544 | void qio_channel_attach_aio_context(QIOChannel *ioc, | |
545 | AioContext *ctx) | |
546 | { | |
8f7168b3 PB |
547 | assert(!ioc->read_coroutine); |
548 | assert(!ioc->write_coroutine); | |
c4c497d2 | 549 | ioc->ctx = ctx; |
c4c497d2 PB |
550 | } |
551 | ||
552 | void qio_channel_detach_aio_context(QIOChannel *ioc) | |
553 | { | |
554 | ioc->read_coroutine = NULL; | |
555 | ioc->write_coroutine = NULL; | |
556 | qio_channel_set_aio_fd_handlers(ioc); | |
557 | ioc->ctx = NULL; | |
558 | } | |
666a3af9 DB |
559 | |
560 | void coroutine_fn qio_channel_yield(QIOChannel *ioc, | |
561 | GIOCondition condition) | |
562 | { | |
666a3af9 | 563 | assert(qemu_in_coroutine()); |
c4c497d2 PB |
564 | if (condition == G_IO_IN) { |
565 | assert(!ioc->read_coroutine); | |
566 | ioc->read_coroutine = qemu_coroutine_self(); | |
567 | } else if (condition == G_IO_OUT) { | |
568 | assert(!ioc->write_coroutine); | |
569 | ioc->write_coroutine = qemu_coroutine_self(); | |
570 | } else { | |
571 | abort(); | |
572 | } | |
573 | qio_channel_set_aio_fd_handlers(ioc); | |
666a3af9 | 574 | qemu_coroutine_yield(); |
6886ceaf KW |
575 | |
576 | /* Allow interrupting the operation by reentering the coroutine other than | |
577 | * through the aio_fd_handlers. */ | |
578 | if (condition == G_IO_IN && ioc->read_coroutine) { | |
579 | ioc->read_coroutine = NULL; | |
580 | qio_channel_set_aio_fd_handlers(ioc); | |
581 | } else if (condition == G_IO_OUT && ioc->write_coroutine) { | |
582 | ioc->write_coroutine = NULL; | |
583 | qio_channel_set_aio_fd_handlers(ioc); | |
584 | } | |
666a3af9 DB |
585 | } |
586 | ||
587 | ||
588 | static gboolean qio_channel_wait_complete(QIOChannel *ioc, | |
589 | GIOCondition condition, | |
590 | gpointer opaque) | |
591 | { | |
592 | GMainLoop *loop = opaque; | |
593 | ||
594 | g_main_loop_quit(loop); | |
595 | return FALSE; | |
596 | } | |
597 | ||
598 | ||
599 | void qio_channel_wait(QIOChannel *ioc, | |
600 | GIOCondition condition) | |
601 | { | |
602 | GMainContext *ctxt = g_main_context_new(); | |
603 | GMainLoop *loop = g_main_loop_new(ctxt, TRUE); | |
604 | GSource *source; | |
605 | ||
606 | source = qio_channel_create_watch(ioc, condition); | |
607 | ||
608 | g_source_set_callback(source, | |
609 | (GSourceFunc)qio_channel_wait_complete, | |
610 | loop, | |
611 | NULL); | |
612 | ||
613 | g_source_attach(source, ctxt); | |
614 | ||
615 | g_main_loop_run(loop); | |
616 | ||
617 | g_source_unref(source); | |
618 | g_main_loop_unref(loop); | |
619 | g_main_context_unref(ctxt); | |
620 | } | |
621 | ||
622 | ||
a5897205 PB |
623 | static void qio_channel_finalize(Object *obj) |
624 | { | |
625 | QIOChannel *ioc = QIO_CHANNEL(obj); | |
626 | ||
20f4aa26 DB |
627 | g_free(ioc->name); |
628 | ||
629 | #ifdef _WIN32 | |
a5897205 PB |
630 | if (ioc->event) { |
631 | CloseHandle(ioc->event); | |
632 | } | |
a5897205 | 633 | #endif |
20f4aa26 | 634 | } |
a5897205 | 635 | |
666a3af9 DB |
636 | static const TypeInfo qio_channel_info = { |
637 | .parent = TYPE_OBJECT, | |
638 | .name = TYPE_QIO_CHANNEL, | |
639 | .instance_size = sizeof(QIOChannel), | |
a5897205 | 640 | .instance_finalize = qio_channel_finalize, |
666a3af9 DB |
641 | .abstract = true, |
642 | .class_size = sizeof(QIOChannelClass), | |
643 | }; | |
644 | ||
645 | ||
646 | static void qio_channel_register_types(void) | |
647 | { | |
648 | type_register_static(&qio_channel_info); | |
649 | } | |
650 | ||
651 | ||
652 | type_init(qio_channel_register_types); |