1666a3af9SDaniel P. Berrange /*
2666a3af9SDaniel P. Berrange * QEMU I/O channels
3666a3af9SDaniel P. Berrange *
4666a3af9SDaniel P. Berrange * Copyright (c) 2015 Red Hat, Inc.
5666a3af9SDaniel P. Berrange *
6666a3af9SDaniel P. Berrange * This library is free software; you can redistribute it and/or
7666a3af9SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public
8666a3af9SDaniel P. Berrange * License as published by the Free Software Foundation; either
9c8198bd5SChetan Pant * version 2.1 of the License, or (at your option) any later version.
10666a3af9SDaniel P. Berrange *
11666a3af9SDaniel P. Berrange * This library is distributed in the hope that it will be useful,
12666a3af9SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
13666a3af9SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14666a3af9SDaniel P. Berrange * Lesser General Public License for more details.
15666a3af9SDaniel P. Berrange *
16666a3af9SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public
17666a3af9SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18666a3af9SDaniel P. Berrange *
19666a3af9SDaniel P. Berrange */
20666a3af9SDaniel P. Berrange
21cae9fc56SPeter Maydell #include "qemu/osdep.h"
227c1f51bfSKevin Wolf #include "block/aio-wait.h"
23666a3af9SDaniel P. Berrange #include "io/channel.h"
24da34e65cSMarkus Armbruster #include "qapi/error.h"
25c4c497d2SPaolo Bonzini #include "qemu/main-loop.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
27d4622e55SDaniel P. Berrange #include "qemu/iov.h"
28666a3af9SDaniel P. Berrange
qio_channel_has_feature(QIOChannel * ioc,QIOChannelFeature feature)29666a3af9SDaniel P. Berrange bool qio_channel_has_feature(QIOChannel *ioc,
30666a3af9SDaniel P. Berrange QIOChannelFeature feature)
31666a3af9SDaniel P. Berrange {
32666a3af9SDaniel P. Berrange return ioc->features & (1 << feature);
33666a3af9SDaniel P. Berrange }
34666a3af9SDaniel P. Berrange
35666a3af9SDaniel P. Berrange
qio_channel_set_feature(QIOChannel * ioc,QIOChannelFeature feature)36d8d3c7ccSFelipe Franciosi void qio_channel_set_feature(QIOChannel *ioc,
37d8d3c7ccSFelipe Franciosi QIOChannelFeature feature)
38d8d3c7ccSFelipe Franciosi {
39d8d3c7ccSFelipe Franciosi ioc->features |= (1 << feature);
40d8d3c7ccSFelipe Franciosi }
41d8d3c7ccSFelipe Franciosi
42d8d3c7ccSFelipe Franciosi
qio_channel_set_name(QIOChannel * ioc,const char * name)4320f4aa26SDaniel P. Berrange void qio_channel_set_name(QIOChannel *ioc,
4420f4aa26SDaniel P. Berrange const char *name)
4520f4aa26SDaniel P. Berrange {
4620f4aa26SDaniel P. Berrange g_free(ioc->name);
4720f4aa26SDaniel P. Berrange ioc->name = g_strdup(name);
4820f4aa26SDaniel P. Berrange }
4920f4aa26SDaniel P. Berrange
5020f4aa26SDaniel P. Berrange
qio_channel_readv_full(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,int flags,Error ** errp)51666a3af9SDaniel P. Berrange ssize_t qio_channel_readv_full(QIOChannel *ioc,
52666a3af9SDaniel P. Berrange const struct iovec *iov,
53666a3af9SDaniel P. Berrange size_t niov,
54666a3af9SDaniel P. Berrange int **fds,
55666a3af9SDaniel P. Berrange size_t *nfds,
5684615a19Smanish.mishra int flags,
57666a3af9SDaniel P. Berrange Error **errp)
58666a3af9SDaniel P. Berrange {
59666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
60666a3af9SDaniel P. Berrange
61666a3af9SDaniel P. Berrange if ((fds || nfds) &&
62e413ae0cSFelipe Franciosi !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
63666a3af9SDaniel P. Berrange error_setg_errno(errp, EINVAL,
64666a3af9SDaniel P. Berrange "Channel does not support file descriptor passing");
65666a3af9SDaniel P. Berrange return -1;
66666a3af9SDaniel P. Berrange }
67666a3af9SDaniel P. Berrange
6884615a19Smanish.mishra if ((flags & QIO_CHANNEL_READ_FLAG_MSG_PEEK) &&
6984615a19Smanish.mishra !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) {
7084615a19Smanish.mishra error_setg_errno(errp, EINVAL,
7184615a19Smanish.mishra "Channel does not support peek read");
7284615a19Smanish.mishra return -1;
7384615a19Smanish.mishra }
7484615a19Smanish.mishra
7584615a19Smanish.mishra return klass->io_readv(ioc, iov, niov, fds, nfds, flags, errp);
76666a3af9SDaniel P. Berrange }
77666a3af9SDaniel P. Berrange
78666a3af9SDaniel P. Berrange
qio_channel_writev_full(QIOChannel * ioc,const struct iovec * iov,size_t niov,int * fds,size_t nfds,int flags,Error ** errp)79666a3af9SDaniel P. Berrange ssize_t qio_channel_writev_full(QIOChannel *ioc,
80666a3af9SDaniel P. Berrange const struct iovec *iov,
81666a3af9SDaniel P. Berrange size_t niov,
82666a3af9SDaniel P. Berrange int *fds,
83666a3af9SDaniel P. Berrange size_t nfds,
84b88651cbSLeonardo Bras int flags,
85666a3af9SDaniel P. Berrange Error **errp)
86666a3af9SDaniel P. Berrange {
87666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
88666a3af9SDaniel P. Berrange
89b88651cbSLeonardo Bras if (fds || nfds) {
90b88651cbSLeonardo Bras if (!qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
91666a3af9SDaniel P. Berrange error_setg_errno(errp, EINVAL,
92666a3af9SDaniel P. Berrange "Channel does not support file descriptor passing");
93666a3af9SDaniel P. Berrange return -1;
94666a3af9SDaniel P. Berrange }
95b88651cbSLeonardo Bras if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) {
96b88651cbSLeonardo Bras error_setg_errno(errp, EINVAL,
97b88651cbSLeonardo Bras "Zero Copy does not support file descriptor passing");
98b88651cbSLeonardo Bras return -1;
99b88651cbSLeonardo Bras }
100b88651cbSLeonardo Bras }
101666a3af9SDaniel P. Berrange
102b88651cbSLeonardo Bras if ((flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) &&
103b88651cbSLeonardo Bras !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
104b88651cbSLeonardo Bras error_setg_errno(errp, EINVAL,
105b88651cbSLeonardo Bras "Requested Zero Copy feature is not available");
106b88651cbSLeonardo Bras return -1;
107b88651cbSLeonardo Bras }
108b88651cbSLeonardo Bras
109b88651cbSLeonardo Bras return klass->io_writev(ioc, iov, niov, fds, nfds, flags, errp);
110666a3af9SDaniel P. Berrange }
111666a3af9SDaniel P. Berrange
112666a3af9SDaniel P. Berrange
qio_channel_readv_all_eof(QIOChannel * ioc,const struct iovec * iov,size_t niov,Error ** errp)1131dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_readv_all_eof(QIOChannel *ioc,
114d4622e55SDaniel P. Berrange const struct iovec *iov,
115d4622e55SDaniel P. Berrange size_t niov,
116d4622e55SDaniel P. Berrange Error **errp)
117d4622e55SDaniel P. Berrange {
118bebab91eSElena Ufimtseva return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp);
119bebab91eSElena Ufimtseva }
120bebab91eSElena Ufimtseva
qio_channel_readv_all(QIOChannel * ioc,const struct iovec * iov,size_t niov,Error ** errp)1211dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_readv_all(QIOChannel *ioc,
122bebab91eSElena Ufimtseva const struct iovec *iov,
123bebab91eSElena Ufimtseva size_t niov,
124bebab91eSElena Ufimtseva Error **errp)
125bebab91eSElena Ufimtseva {
126bebab91eSElena Ufimtseva return qio_channel_readv_full_all(ioc, iov, niov, NULL, NULL, errp);
127bebab91eSElena Ufimtseva }
128bebab91eSElena Ufimtseva
qio_channel_readv_full_all_eof(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,Error ** errp)1291dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_readv_full_all_eof(QIOChannel *ioc,
130bebab91eSElena Ufimtseva const struct iovec *iov,
131bebab91eSElena Ufimtseva size_t niov,
132bebab91eSElena Ufimtseva int **fds, size_t *nfds,
133bebab91eSElena Ufimtseva Error **errp)
134bebab91eSElena Ufimtseva {
135d4622e55SDaniel P. Berrange int ret = -1;
136d4622e55SDaniel P. Berrange struct iovec *local_iov = g_new(struct iovec, niov);
137d4622e55SDaniel P. Berrange struct iovec *local_iov_head = local_iov;
138d4622e55SDaniel P. Berrange unsigned int nlocal_iov = niov;
139bebab91eSElena Ufimtseva int **local_fds = fds;
140bebab91eSElena Ufimtseva size_t *local_nfds = nfds;
141e8ffaa31SEric Blake bool partial = false;
142d4622e55SDaniel P. Berrange
143bebab91eSElena Ufimtseva if (nfds) {
144bebab91eSElena Ufimtseva *nfds = 0;
145bebab91eSElena Ufimtseva }
146bebab91eSElena Ufimtseva
147bebab91eSElena Ufimtseva if (fds) {
148bebab91eSElena Ufimtseva *fds = NULL;
149bebab91eSElena Ufimtseva }
150bebab91eSElena Ufimtseva
151d4622e55SDaniel P. Berrange nlocal_iov = iov_copy(local_iov, nlocal_iov,
152d4622e55SDaniel P. Berrange iov, niov,
153d4622e55SDaniel P. Berrange 0, iov_size(iov, niov));
154d4622e55SDaniel P. Berrange
155bebab91eSElena Ufimtseva while ((nlocal_iov > 0) || local_fds) {
156d4622e55SDaniel P. Berrange ssize_t len;
157bebab91eSElena Ufimtseva len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds,
15884615a19Smanish.mishra local_nfds, 0, errp);
159d4622e55SDaniel P. Berrange if (len == QIO_CHANNEL_ERR_BLOCK) {
1609ffb8270SEric Blake if (qemu_in_coroutine()) {
1619ffb8270SEric Blake qio_channel_yield(ioc, G_IO_IN);
1629ffb8270SEric Blake } else {
163d4622e55SDaniel P. Berrange qio_channel_wait(ioc, G_IO_IN);
1649ffb8270SEric Blake }
165d4622e55SDaniel P. Berrange continue;
166bebab91eSElena Ufimtseva }
167bebab91eSElena Ufimtseva
168bebab91eSElena Ufimtseva if (len == 0) {
169bebab91eSElena Ufimtseva if (local_nfds && *local_nfds) {
170bebab91eSElena Ufimtseva /*
171bebab91eSElena Ufimtseva * Got some FDs, but no data yet. This isn't an EOF
172bebab91eSElena Ufimtseva * scenario (yet), so carry on to try to read data
173bebab91eSElena Ufimtseva * on next loop iteration
174bebab91eSElena Ufimtseva */
175bebab91eSElena Ufimtseva goto next_iter;
176bebab91eSElena Ufimtseva } else if (!partial) {
177bebab91eSElena Ufimtseva /* No fds and no data - EOF before any data read */
178e8ffaa31SEric Blake ret = 0;
179bebab91eSElena Ufimtseva goto cleanup;
180bebab91eSElena Ufimtseva } else {
181bebab91eSElena Ufimtseva len = -1;
182bebab91eSElena Ufimtseva error_setg(errp,
183bebab91eSElena Ufimtseva "Unexpected end-of-file before all data were read");
184bebab91eSElena Ufimtseva /* Fallthrough into len < 0 handling */
185bebab91eSElena Ufimtseva }
186bebab91eSElena Ufimtseva }
187bebab91eSElena Ufimtseva
188bebab91eSElena Ufimtseva if (len < 0) {
189bebab91eSElena Ufimtseva /* Close any FDs we previously received */
190bebab91eSElena Ufimtseva if (nfds && fds) {
191bebab91eSElena Ufimtseva size_t i;
192bebab91eSElena Ufimtseva for (i = 0; i < (*nfds); i++) {
193bebab91eSElena Ufimtseva close((*fds)[i]);
194bebab91eSElena Ufimtseva }
195bebab91eSElena Ufimtseva g_free(*fds);
196bebab91eSElena Ufimtseva *fds = NULL;
197bebab91eSElena Ufimtseva *nfds = 0;
198e8ffaa31SEric Blake }
199d4622e55SDaniel P. Berrange goto cleanup;
200d4622e55SDaniel P. Berrange }
201d4622e55SDaniel P. Berrange
202bebab91eSElena Ufimtseva if (nlocal_iov) {
203d4622e55SDaniel P. Berrange iov_discard_front(&local_iov, &nlocal_iov, len);
204d4622e55SDaniel P. Berrange }
205d4622e55SDaniel P. Berrange
206bebab91eSElena Ufimtseva next_iter:
207bebab91eSElena Ufimtseva partial = true;
208bebab91eSElena Ufimtseva local_fds = NULL;
209bebab91eSElena Ufimtseva local_nfds = NULL;
210bebab91eSElena Ufimtseva }
211bebab91eSElena Ufimtseva
212e8ffaa31SEric Blake ret = 1;
213d4622e55SDaniel P. Berrange
214d4622e55SDaniel P. Berrange cleanup:
215d4622e55SDaniel P. Berrange g_free(local_iov_head);
216d4622e55SDaniel P. Berrange return ret;
217d4622e55SDaniel P. Berrange }
218d4622e55SDaniel P. Berrange
qio_channel_readv_full_all(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,Error ** errp)2191dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_readv_full_all(QIOChannel *ioc,
220e8ffaa31SEric Blake const struct iovec *iov,
221e8ffaa31SEric Blake size_t niov,
222bebab91eSElena Ufimtseva int **fds, size_t *nfds,
223e8ffaa31SEric Blake Error **errp)
224e8ffaa31SEric Blake {
225bebab91eSElena Ufimtseva int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
226e8ffaa31SEric Blake
227e8ffaa31SEric Blake if (ret == 0) {
228c90e3512SJagannathan Raman error_setg(errp, "Unexpected end-of-file before all data were read");
229bebab91eSElena Ufimtseva return -1;
230e8ffaa31SEric Blake }
231bebab91eSElena Ufimtseva if (ret == 1) {
232bebab91eSElena Ufimtseva return 0;
233bebab91eSElena Ufimtseva }
234bebab91eSElena Ufimtseva
235e8ffaa31SEric Blake return ret;
236e8ffaa31SEric Blake }
237e8ffaa31SEric Blake
qio_channel_writev_all(QIOChannel * ioc,const struct iovec * iov,size_t niov,Error ** errp)2381dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_writev_all(QIOChannel *ioc,
239d4622e55SDaniel P. Berrange const struct iovec *iov,
240d4622e55SDaniel P. Berrange size_t niov,
241d4622e55SDaniel P. Berrange Error **errp)
242d4622e55SDaniel P. Berrange {
243b88651cbSLeonardo Bras return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, 0, errp);
244bfa42387SElena Ufimtseva }
245bfa42387SElena Ufimtseva
qio_channel_writev_full_all(QIOChannel * ioc,const struct iovec * iov,size_t niov,int * fds,size_t nfds,int flags,Error ** errp)2461dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_writev_full_all(QIOChannel *ioc,
247bfa42387SElena Ufimtseva const struct iovec *iov,
248bfa42387SElena Ufimtseva size_t niov,
249bfa42387SElena Ufimtseva int *fds, size_t nfds,
250b88651cbSLeonardo Bras int flags, Error **errp)
251bfa42387SElena Ufimtseva {
252d4622e55SDaniel P. Berrange int ret = -1;
253d4622e55SDaniel P. Berrange struct iovec *local_iov = g_new(struct iovec, niov);
254d4622e55SDaniel P. Berrange struct iovec *local_iov_head = local_iov;
255d4622e55SDaniel P. Berrange unsigned int nlocal_iov = niov;
256d4622e55SDaniel P. Berrange
257d4622e55SDaniel P. Berrange nlocal_iov = iov_copy(local_iov, nlocal_iov,
258d4622e55SDaniel P. Berrange iov, niov,
259d4622e55SDaniel P. Berrange 0, iov_size(iov, niov));
260d4622e55SDaniel P. Berrange
261d4622e55SDaniel P. Berrange while (nlocal_iov > 0) {
262d4622e55SDaniel P. Berrange ssize_t len;
263b88651cbSLeonardo Bras
264b88651cbSLeonardo Bras len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds,
265b88651cbSLeonardo Bras nfds, flags, errp);
266b88651cbSLeonardo Bras
267d4622e55SDaniel P. Berrange if (len == QIO_CHANNEL_ERR_BLOCK) {
2689ffb8270SEric Blake if (qemu_in_coroutine()) {
2699ffb8270SEric Blake qio_channel_yield(ioc, G_IO_OUT);
2709ffb8270SEric Blake } else {
271d4622e55SDaniel P. Berrange qio_channel_wait(ioc, G_IO_OUT);
2729ffb8270SEric Blake }
273d4622e55SDaniel P. Berrange continue;
274d4622e55SDaniel P. Berrange }
275d4622e55SDaniel P. Berrange if (len < 0) {
276d4622e55SDaniel P. Berrange goto cleanup;
277d4622e55SDaniel P. Berrange }
278d4622e55SDaniel P. Berrange
279d4622e55SDaniel P. Berrange iov_discard_front(&local_iov, &nlocal_iov, len);
280bfa42387SElena Ufimtseva
281bfa42387SElena Ufimtseva fds = NULL;
282bfa42387SElena Ufimtseva nfds = 0;
283d4622e55SDaniel P. Berrange }
284d4622e55SDaniel P. Berrange
285d4622e55SDaniel P. Berrange ret = 0;
286d4622e55SDaniel P. Berrange cleanup:
287d4622e55SDaniel P. Berrange g_free(local_iov_head);
288d4622e55SDaniel P. Berrange return ret;
289d4622e55SDaniel P. Berrange }
290d4622e55SDaniel P. Berrange
qio_channel_readv(QIOChannel * ioc,const struct iovec * iov,size_t niov,Error ** errp)291666a3af9SDaniel P. Berrange ssize_t qio_channel_readv(QIOChannel *ioc,
292666a3af9SDaniel P. Berrange const struct iovec *iov,
293666a3af9SDaniel P. Berrange size_t niov,
294666a3af9SDaniel P. Berrange Error **errp)
295666a3af9SDaniel P. Berrange {
29684615a19Smanish.mishra return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, 0, errp);
297666a3af9SDaniel P. Berrange }
298666a3af9SDaniel P. Berrange
299666a3af9SDaniel P. Berrange
qio_channel_writev(QIOChannel * ioc,const struct iovec * iov,size_t niov,Error ** errp)300666a3af9SDaniel P. Berrange ssize_t qio_channel_writev(QIOChannel *ioc,
301666a3af9SDaniel P. Berrange const struct iovec *iov,
302666a3af9SDaniel P. Berrange size_t niov,
303666a3af9SDaniel P. Berrange Error **errp)
304666a3af9SDaniel P. Berrange {
305b88651cbSLeonardo Bras return qio_channel_writev_full(ioc, iov, niov, NULL, 0, 0, errp);
306666a3af9SDaniel P. Berrange }
307666a3af9SDaniel P. Berrange
308666a3af9SDaniel P. Berrange
qio_channel_read(QIOChannel * ioc,char * buf,size_t buflen,Error ** errp)309666a3af9SDaniel P. Berrange ssize_t qio_channel_read(QIOChannel *ioc,
310666a3af9SDaniel P. Berrange char *buf,
311666a3af9SDaniel P. Berrange size_t buflen,
312666a3af9SDaniel P. Berrange Error **errp)
313666a3af9SDaniel P. Berrange {
314666a3af9SDaniel P. Berrange struct iovec iov = { .iov_base = buf, .iov_len = buflen };
31584615a19Smanish.mishra return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, 0, errp);
316666a3af9SDaniel P. Berrange }
317666a3af9SDaniel P. Berrange
318666a3af9SDaniel P. Berrange
qio_channel_write(QIOChannel * ioc,const char * buf,size_t buflen,Error ** errp)319666a3af9SDaniel P. Berrange ssize_t qio_channel_write(QIOChannel *ioc,
320666a3af9SDaniel P. Berrange const char *buf,
321666a3af9SDaniel P. Berrange size_t buflen,
322666a3af9SDaniel P. Berrange Error **errp)
323666a3af9SDaniel P. Berrange {
324666a3af9SDaniel P. Berrange struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
325b88651cbSLeonardo Bras return qio_channel_writev_full(ioc, &iov, 1, NULL, 0, 0, errp);
326666a3af9SDaniel P. Berrange }
327666a3af9SDaniel P. Berrange
328666a3af9SDaniel P. Berrange
qio_channel_read_all_eof(QIOChannel * ioc,char * buf,size_t buflen,Error ** errp)3291dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
330e8ffaa31SEric Blake char *buf,
331e8ffaa31SEric Blake size_t buflen,
332e8ffaa31SEric Blake Error **errp)
333e8ffaa31SEric Blake {
334e8ffaa31SEric Blake struct iovec iov = { .iov_base = buf, .iov_len = buflen };
335e8ffaa31SEric Blake return qio_channel_readv_all_eof(ioc, &iov, 1, errp);
336e8ffaa31SEric Blake }
337e8ffaa31SEric Blake
338e8ffaa31SEric Blake
qio_channel_read_all(QIOChannel * ioc,char * buf,size_t buflen,Error ** errp)3391dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_read_all(QIOChannel *ioc,
340d4622e55SDaniel P. Berrange char *buf,
341d4622e55SDaniel P. Berrange size_t buflen,
342d4622e55SDaniel P. Berrange Error **errp)
343d4622e55SDaniel P. Berrange {
344d4622e55SDaniel P. Berrange struct iovec iov = { .iov_base = buf, .iov_len = buflen };
345d4622e55SDaniel P. Berrange return qio_channel_readv_all(ioc, &iov, 1, errp);
346d4622e55SDaniel P. Berrange }
347d4622e55SDaniel P. Berrange
348d4622e55SDaniel P. Berrange
qio_channel_write_all(QIOChannel * ioc,const char * buf,size_t buflen,Error ** errp)3491dd91b22SPaolo Bonzini int coroutine_mixed_fn qio_channel_write_all(QIOChannel *ioc,
350d4622e55SDaniel P. Berrange const char *buf,
351d4622e55SDaniel P. Berrange size_t buflen,
352d4622e55SDaniel P. Berrange Error **errp)
353d4622e55SDaniel P. Berrange {
354d4622e55SDaniel P. Berrange struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
355d4622e55SDaniel P. Berrange return qio_channel_writev_all(ioc, &iov, 1, errp);
356d4622e55SDaniel P. Berrange }
357d4622e55SDaniel P. Berrange
358d4622e55SDaniel P. Berrange
qio_channel_set_blocking(QIOChannel * ioc,bool enabled,Error ** errp)359666a3af9SDaniel P. Berrange int qio_channel_set_blocking(QIOChannel *ioc,
360666a3af9SDaniel P. Berrange bool enabled,
361666a3af9SDaniel P. Berrange Error **errp)
362666a3af9SDaniel P. Berrange {
363666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
364666a3af9SDaniel P. Berrange return klass->io_set_blocking(ioc, enabled, errp);
365666a3af9SDaniel P. Berrange }
366666a3af9SDaniel P. Berrange
367666a3af9SDaniel P. Berrange
qio_channel_set_follow_coroutine_ctx(QIOChannel * ioc,bool enabled)36806e0f098SStefan Hajnoczi void qio_channel_set_follow_coroutine_ctx(QIOChannel *ioc, bool enabled)
36906e0f098SStefan Hajnoczi {
37006e0f098SStefan Hajnoczi ioc->follow_coroutine_ctx = enabled;
37106e0f098SStefan Hajnoczi }
37206e0f098SStefan Hajnoczi
37306e0f098SStefan Hajnoczi
qio_channel_close(QIOChannel * ioc,Error ** errp)374666a3af9SDaniel P. Berrange int qio_channel_close(QIOChannel *ioc,
375666a3af9SDaniel P. Berrange Error **errp)
376666a3af9SDaniel P. Berrange {
377666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
378666a3af9SDaniel P. Berrange return klass->io_close(ioc, errp);
379666a3af9SDaniel P. Berrange }
380666a3af9SDaniel P. Berrange
381666a3af9SDaniel P. Berrange
qio_channel_create_watch(QIOChannel * ioc,GIOCondition condition)382666a3af9SDaniel P. Berrange GSource *qio_channel_create_watch(QIOChannel *ioc,
383666a3af9SDaniel P. Berrange GIOCondition condition)
384666a3af9SDaniel P. Berrange {
385666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
38620f4aa26SDaniel P. Berrange GSource *ret = klass->io_create_watch(ioc, condition);
38720f4aa26SDaniel P. Berrange
38820f4aa26SDaniel P. Berrange if (ioc->name) {
38920f4aa26SDaniel P. Berrange g_source_set_name(ret, ioc->name);
39020f4aa26SDaniel P. Berrange }
39120f4aa26SDaniel P. Berrange
39220f4aa26SDaniel P. Berrange return ret;
393666a3af9SDaniel P. Berrange }
394666a3af9SDaniel P. Berrange
395666a3af9SDaniel P. Berrange
qio_channel_set_aio_fd_handler(QIOChannel * ioc,AioContext * read_ctx,IOHandler * io_read,AioContext * write_ctx,IOHandler * io_write,void * opaque)396bf88c124SPaolo Bonzini void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
39706e0f098SStefan Hajnoczi AioContext *read_ctx,
398bf88c124SPaolo Bonzini IOHandler *io_read,
39906e0f098SStefan Hajnoczi AioContext *write_ctx,
400bf88c124SPaolo Bonzini IOHandler *io_write,
401bf88c124SPaolo Bonzini void *opaque)
402bf88c124SPaolo Bonzini {
403bf88c124SPaolo Bonzini QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
404bf88c124SPaolo Bonzini
40506e0f098SStefan Hajnoczi klass->io_set_aio_fd_handler(ioc, read_ctx, io_read, write_ctx, io_write,
40606e0f098SStefan Hajnoczi opaque);
407bf88c124SPaolo Bonzini }
408bf88c124SPaolo Bonzini
qio_channel_add_watch_full(QIOChannel * ioc,GIOCondition condition,QIOChannelFunc func,gpointer user_data,GDestroyNotify notify,GMainContext * context)409315409c7SPeter Xu guint qio_channel_add_watch_full(QIOChannel *ioc,
410666a3af9SDaniel P. Berrange GIOCondition condition,
411666a3af9SDaniel P. Berrange QIOChannelFunc func,
412666a3af9SDaniel P. Berrange gpointer user_data,
413315409c7SPeter Xu GDestroyNotify notify,
414315409c7SPeter Xu GMainContext *context)
415666a3af9SDaniel P. Berrange {
416666a3af9SDaniel P. Berrange GSource *source;
417666a3af9SDaniel P. Berrange guint id;
418666a3af9SDaniel P. Berrange
419666a3af9SDaniel P. Berrange source = qio_channel_create_watch(ioc, condition);
420666a3af9SDaniel P. Berrange
421666a3af9SDaniel P. Berrange g_source_set_callback(source, (GSourceFunc)func, user_data, notify);
422666a3af9SDaniel P. Berrange
423315409c7SPeter Xu id = g_source_attach(source, context);
424666a3af9SDaniel P. Berrange g_source_unref(source);
425666a3af9SDaniel P. Berrange
426666a3af9SDaniel P. Berrange return id;
427666a3af9SDaniel P. Berrange }
428666a3af9SDaniel P. Berrange
qio_channel_add_watch(QIOChannel * ioc,GIOCondition condition,QIOChannelFunc func,gpointer user_data,GDestroyNotify notify)429315409c7SPeter Xu guint qio_channel_add_watch(QIOChannel *ioc,
430315409c7SPeter Xu GIOCondition condition,
431315409c7SPeter Xu QIOChannelFunc func,
432315409c7SPeter Xu gpointer user_data,
433315409c7SPeter Xu GDestroyNotify notify)
434315409c7SPeter Xu {
435315409c7SPeter Xu return qio_channel_add_watch_full(ioc, condition, func,
436315409c7SPeter Xu user_data, notify, NULL);
437315409c7SPeter Xu }
438315409c7SPeter Xu
qio_channel_add_watch_source(QIOChannel * ioc,GIOCondition condition,QIOChannelFunc func,gpointer user_data,GDestroyNotify notify,GMainContext * context)439315409c7SPeter Xu GSource *qio_channel_add_watch_source(QIOChannel *ioc,
440315409c7SPeter Xu GIOCondition condition,
441315409c7SPeter Xu QIOChannelFunc func,
442315409c7SPeter Xu gpointer user_data,
443315409c7SPeter Xu GDestroyNotify notify,
444315409c7SPeter Xu GMainContext *context)
445315409c7SPeter Xu {
446315409c7SPeter Xu GSource *source;
447315409c7SPeter Xu guint id;
448315409c7SPeter Xu
449315409c7SPeter Xu id = qio_channel_add_watch_full(ioc, condition, func,
450315409c7SPeter Xu user_data, notify, context);
451315409c7SPeter Xu source = g_main_context_find_source_by_id(context, id);
452315409c7SPeter Xu g_source_ref(source);
453315409c7SPeter Xu return source;
454315409c7SPeter Xu }
455315409c7SPeter Xu
456666a3af9SDaniel P. Berrange
qio_channel_pwritev(QIOChannel * ioc,const struct iovec * iov,size_t niov,off_t offset,Error ** errp)457f1cfe394SNikolay Borisov ssize_t qio_channel_pwritev(QIOChannel *ioc, const struct iovec *iov,
458f1cfe394SNikolay Borisov size_t niov, off_t offset, Error **errp)
459f1cfe394SNikolay Borisov {
460f1cfe394SNikolay Borisov QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
461f1cfe394SNikolay Borisov
462f1cfe394SNikolay Borisov if (!klass->io_pwritev) {
463f1cfe394SNikolay Borisov error_setg(errp, "Channel does not support pwritev");
464f1cfe394SNikolay Borisov return -1;
465f1cfe394SNikolay Borisov }
466f1cfe394SNikolay Borisov
467f1cfe394SNikolay Borisov if (!qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_SEEKABLE)) {
468f1cfe394SNikolay Borisov error_setg_errno(errp, EINVAL, "Requested channel is not seekable");
469f1cfe394SNikolay Borisov return -1;
470f1cfe394SNikolay Borisov }
471f1cfe394SNikolay Borisov
472f1cfe394SNikolay Borisov return klass->io_pwritev(ioc, iov, niov, offset, errp);
473f1cfe394SNikolay Borisov }
474f1cfe394SNikolay Borisov
qio_channel_pwrite(QIOChannel * ioc,char * buf,size_t buflen,off_t offset,Error ** errp)475f1cfe394SNikolay Borisov ssize_t qio_channel_pwrite(QIOChannel *ioc, char *buf, size_t buflen,
476f1cfe394SNikolay Borisov off_t offset, Error **errp)
477f1cfe394SNikolay Borisov {
478f1cfe394SNikolay Borisov struct iovec iov = {
479f1cfe394SNikolay Borisov .iov_base = buf,
480f1cfe394SNikolay Borisov .iov_len = buflen
481f1cfe394SNikolay Borisov };
482f1cfe394SNikolay Borisov
483f1cfe394SNikolay Borisov return qio_channel_pwritev(ioc, &iov, 1, offset, errp);
484f1cfe394SNikolay Borisov }
485f1cfe394SNikolay Borisov
qio_channel_preadv(QIOChannel * ioc,const struct iovec * iov,size_t niov,off_t offset,Error ** errp)486f1cfe394SNikolay Borisov ssize_t qio_channel_preadv(QIOChannel *ioc, const struct iovec *iov,
487f1cfe394SNikolay Borisov size_t niov, off_t offset, Error **errp)
488f1cfe394SNikolay Borisov {
489f1cfe394SNikolay Borisov QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
490f1cfe394SNikolay Borisov
491f1cfe394SNikolay Borisov if (!klass->io_preadv) {
492f1cfe394SNikolay Borisov error_setg(errp, "Channel does not support preadv");
493f1cfe394SNikolay Borisov return -1;
494f1cfe394SNikolay Borisov }
495f1cfe394SNikolay Borisov
496f1cfe394SNikolay Borisov if (!qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_SEEKABLE)) {
497f1cfe394SNikolay Borisov error_setg_errno(errp, EINVAL, "Requested channel is not seekable");
498f1cfe394SNikolay Borisov return -1;
499f1cfe394SNikolay Borisov }
500f1cfe394SNikolay Borisov
501f1cfe394SNikolay Borisov return klass->io_preadv(ioc, iov, niov, offset, errp);
502f1cfe394SNikolay Borisov }
503f1cfe394SNikolay Borisov
qio_channel_pread(QIOChannel * ioc,char * buf,size_t buflen,off_t offset,Error ** errp)504f1cfe394SNikolay Borisov ssize_t qio_channel_pread(QIOChannel *ioc, char *buf, size_t buflen,
505f1cfe394SNikolay Borisov off_t offset, Error **errp)
506f1cfe394SNikolay Borisov {
507f1cfe394SNikolay Borisov struct iovec iov = {
508f1cfe394SNikolay Borisov .iov_base = buf,
509f1cfe394SNikolay Borisov .iov_len = buflen
510f1cfe394SNikolay Borisov };
511f1cfe394SNikolay Borisov
512f1cfe394SNikolay Borisov return qio_channel_preadv(ioc, &iov, 1, offset, errp);
513f1cfe394SNikolay Borisov }
514f1cfe394SNikolay Borisov
qio_channel_shutdown(QIOChannel * ioc,QIOChannelShutdown how,Error ** errp)515666a3af9SDaniel P. Berrange int qio_channel_shutdown(QIOChannel *ioc,
516666a3af9SDaniel P. Berrange QIOChannelShutdown how,
517666a3af9SDaniel P. Berrange Error **errp)
518666a3af9SDaniel P. Berrange {
519666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
520666a3af9SDaniel P. Berrange
521666a3af9SDaniel P. Berrange if (!klass->io_shutdown) {
522666a3af9SDaniel P. Berrange error_setg(errp, "Data path shutdown not supported");
523666a3af9SDaniel P. Berrange return -1;
524666a3af9SDaniel P. Berrange }
525666a3af9SDaniel P. Berrange
526666a3af9SDaniel P. Berrange return klass->io_shutdown(ioc, how, errp);
527666a3af9SDaniel P. Berrange }
528666a3af9SDaniel P. Berrange
529666a3af9SDaniel P. Berrange
qio_channel_set_delay(QIOChannel * ioc,bool enabled)530666a3af9SDaniel P. Berrange void qio_channel_set_delay(QIOChannel *ioc,
531666a3af9SDaniel P. Berrange bool enabled)
532666a3af9SDaniel P. Berrange {
533666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
534666a3af9SDaniel P. Berrange
535666a3af9SDaniel P. Berrange if (klass->io_set_delay) {
536666a3af9SDaniel P. Berrange klass->io_set_delay(ioc, enabled);
537666a3af9SDaniel P. Berrange }
538666a3af9SDaniel P. Berrange }
539666a3af9SDaniel P. Berrange
540666a3af9SDaniel P. Berrange
qio_channel_set_cork(QIOChannel * ioc,bool enabled)541666a3af9SDaniel P. Berrange void qio_channel_set_cork(QIOChannel *ioc,
542666a3af9SDaniel P. Berrange bool enabled)
543666a3af9SDaniel P. Berrange {
544666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
545666a3af9SDaniel P. Berrange
546666a3af9SDaniel P. Berrange if (klass->io_set_cork) {
547666a3af9SDaniel P. Berrange klass->io_set_cork(ioc, enabled);
548666a3af9SDaniel P. Berrange }
549666a3af9SDaniel P. Berrange }
550666a3af9SDaniel P. Berrange
qio_channel_get_peerpid(QIOChannel * ioc,unsigned int * pid,Error ** errp)551*95fa0c79SAnthony Harivel int qio_channel_get_peerpid(QIOChannel *ioc,
552*95fa0c79SAnthony Harivel unsigned int *pid,
553*95fa0c79SAnthony Harivel Error **errp)
554*95fa0c79SAnthony Harivel {
555*95fa0c79SAnthony Harivel QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
556*95fa0c79SAnthony Harivel
557*95fa0c79SAnthony Harivel if (!klass->io_peerpid) {
558*95fa0c79SAnthony Harivel error_setg(errp, "Channel does not support peer pid");
559*95fa0c79SAnthony Harivel return -1;
560*95fa0c79SAnthony Harivel }
561*95fa0c79SAnthony Harivel klass->io_peerpid(ioc, pid, errp);
562*95fa0c79SAnthony Harivel return 0;
563*95fa0c79SAnthony Harivel }
564666a3af9SDaniel P. Berrange
qio_channel_io_seek(QIOChannel * ioc,off_t offset,int whence,Error ** errp)565666a3af9SDaniel P. Berrange off_t qio_channel_io_seek(QIOChannel *ioc,
566666a3af9SDaniel P. Berrange off_t offset,
567666a3af9SDaniel P. Berrange int whence,
568666a3af9SDaniel P. Berrange Error **errp)
569666a3af9SDaniel P. Berrange {
570666a3af9SDaniel P. Berrange QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
571666a3af9SDaniel P. Berrange
572666a3af9SDaniel P. Berrange if (!klass->io_seek) {
573666a3af9SDaniel P. Berrange error_setg(errp, "Channel does not support random access");
574666a3af9SDaniel P. Berrange return -1;
575666a3af9SDaniel P. Berrange }
576666a3af9SDaniel P. Berrange
577666a3af9SDaniel P. Berrange return klass->io_seek(ioc, offset, whence, errp);
578666a3af9SDaniel P. Berrange }
579666a3af9SDaniel P. Berrange
qio_channel_flush(QIOChannel * ioc,Error ** errp)580b88651cbSLeonardo Bras int qio_channel_flush(QIOChannel *ioc,
581b88651cbSLeonardo Bras Error **errp)
582b88651cbSLeonardo Bras {
583b88651cbSLeonardo Bras QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
584b88651cbSLeonardo Bras
585b88651cbSLeonardo Bras if (!klass->io_flush ||
586b88651cbSLeonardo Bras !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
587b88651cbSLeonardo Bras return 0;
588b88651cbSLeonardo Bras }
589b88651cbSLeonardo Bras
590b88651cbSLeonardo Bras return klass->io_flush(ioc, errp);
591b88651cbSLeonardo Bras }
592b88651cbSLeonardo Bras
593666a3af9SDaniel P. Berrange
qio_channel_restart_read(void * opaque)594c4c497d2SPaolo Bonzini static void qio_channel_restart_read(void *opaque)
595666a3af9SDaniel P. Berrange {
596c4c497d2SPaolo Bonzini QIOChannel *ioc = opaque;
5977c1f51bfSKevin Wolf Coroutine *co = qatomic_xchg(&ioc->read_coroutine, NULL);
5987c1f51bfSKevin Wolf
5997c1f51bfSKevin Wolf if (!co) {
6007c1f51bfSKevin Wolf return;
6017c1f51bfSKevin Wolf }
602c4c497d2SPaolo Bonzini
6032a239e6eSKevin Wolf /* Assert that aio_co_wake() reenters the coroutine directly */
6042a239e6eSKevin Wolf assert(qemu_get_current_aio_context() ==
6052a239e6eSKevin Wolf qemu_coroutine_get_aio_context(co));
606c4c497d2SPaolo Bonzini aio_co_wake(co);
607666a3af9SDaniel P. Berrange }
608666a3af9SDaniel P. Berrange
qio_channel_restart_write(void * opaque)609c4c497d2SPaolo Bonzini static void qio_channel_restart_write(void *opaque)
610c4c497d2SPaolo Bonzini {
611c4c497d2SPaolo Bonzini QIOChannel *ioc = opaque;
6127c1f51bfSKevin Wolf Coroutine *co = qatomic_xchg(&ioc->write_coroutine, NULL);
6137c1f51bfSKevin Wolf
6147c1f51bfSKevin Wolf if (!co) {
6157c1f51bfSKevin Wolf return;
6167c1f51bfSKevin Wolf }
617c4c497d2SPaolo Bonzini
6182a239e6eSKevin Wolf /* Assert that aio_co_wake() reenters the coroutine directly */
6192a239e6eSKevin Wolf assert(qemu_get_current_aio_context() ==
6202a239e6eSKevin Wolf qemu_coroutine_get_aio_context(co));
621c4c497d2SPaolo Bonzini aio_co_wake(co);
622c4c497d2SPaolo Bonzini }
623c4c497d2SPaolo Bonzini
62406e0f098SStefan Hajnoczi static void coroutine_fn
qio_channel_set_fd_handlers(QIOChannel * ioc,GIOCondition condition)62506e0f098SStefan Hajnoczi qio_channel_set_fd_handlers(QIOChannel *ioc, GIOCondition condition)
626c4c497d2SPaolo Bonzini {
62706e0f098SStefan Hajnoczi AioContext *ctx = ioc->follow_coroutine_ctx ?
62806e0f098SStefan Hajnoczi qemu_coroutine_get_aio_context(qemu_coroutine_self()) :
62906e0f098SStefan Hajnoczi iohandler_get_aio_context();
63006e0f098SStefan Hajnoczi AioContext *read_ctx = NULL;
63106e0f098SStefan Hajnoczi IOHandler *io_read = NULL;
63206e0f098SStefan Hajnoczi AioContext *write_ctx = NULL;
63306e0f098SStefan Hajnoczi IOHandler *io_write = NULL;
63406e0f098SStefan Hajnoczi
63506e0f098SStefan Hajnoczi if (condition == G_IO_IN) {
63606e0f098SStefan Hajnoczi ioc->read_coroutine = qemu_coroutine_self();
63706e0f098SStefan Hajnoczi ioc->read_ctx = ctx;
63806e0f098SStefan Hajnoczi read_ctx = ctx;
63906e0f098SStefan Hajnoczi io_read = qio_channel_restart_read;
64006e0f098SStefan Hajnoczi
64106e0f098SStefan Hajnoczi /*
64206e0f098SStefan Hajnoczi * Thread safety: if the other coroutine is set and its AioContext
64306e0f098SStefan Hajnoczi * matches ours, then there is mutual exclusion between read and write
64406e0f098SStefan Hajnoczi * because they share a single thread and it's safe to set both read
64506e0f098SStefan Hajnoczi * and write fd handlers here. If the AioContext does not match ours,
64606e0f098SStefan Hajnoczi * then both threads may run in parallel but there is no shared state
64706e0f098SStefan Hajnoczi * to worry about.
64806e0f098SStefan Hajnoczi */
64906e0f098SStefan Hajnoczi if (ioc->write_coroutine && ioc->write_ctx == ctx) {
65006e0f098SStefan Hajnoczi write_ctx = ctx;
65106e0f098SStefan Hajnoczi io_write = qio_channel_restart_write;
65206e0f098SStefan Hajnoczi }
65306e0f098SStefan Hajnoczi } else if (condition == G_IO_OUT) {
65406e0f098SStefan Hajnoczi ioc->write_coroutine = qemu_coroutine_self();
65506e0f098SStefan Hajnoczi ioc->write_ctx = ctx;
65606e0f098SStefan Hajnoczi write_ctx = ctx;
65706e0f098SStefan Hajnoczi io_write = qio_channel_restart_write;
65806e0f098SStefan Hajnoczi if (ioc->read_coroutine && ioc->read_ctx == ctx) {
65906e0f098SStefan Hajnoczi read_ctx = ctx;
66006e0f098SStefan Hajnoczi io_read = qio_channel_restart_read;
66106e0f098SStefan Hajnoczi }
66206e0f098SStefan Hajnoczi } else {
66306e0f098SStefan Hajnoczi abort();
66406e0f098SStefan Hajnoczi }
66506e0f098SStefan Hajnoczi
66606e0f098SStefan Hajnoczi qio_channel_set_aio_fd_handler(ioc, read_ctx, io_read,
66706e0f098SStefan Hajnoczi write_ctx, io_write, ioc);
66806e0f098SStefan Hajnoczi }
66906e0f098SStefan Hajnoczi
67006e0f098SStefan Hajnoczi static void coroutine_fn
qio_channel_clear_fd_handlers(QIOChannel * ioc,GIOCondition condition)67106e0f098SStefan Hajnoczi qio_channel_clear_fd_handlers(QIOChannel *ioc, GIOCondition condition)
67206e0f098SStefan Hajnoczi {
67306e0f098SStefan Hajnoczi AioContext *read_ctx = NULL;
67406e0f098SStefan Hajnoczi IOHandler *io_read = NULL;
67506e0f098SStefan Hajnoczi AioContext *write_ctx = NULL;
67606e0f098SStefan Hajnoczi IOHandler *io_write = NULL;
677c4c497d2SPaolo Bonzini AioContext *ctx;
678c4c497d2SPaolo Bonzini
67906e0f098SStefan Hajnoczi if (condition == G_IO_IN) {
68006e0f098SStefan Hajnoczi ctx = ioc->read_ctx;
68106e0f098SStefan Hajnoczi read_ctx = ctx;
68206e0f098SStefan Hajnoczi io_read = NULL;
68306e0f098SStefan Hajnoczi if (ioc->write_coroutine && ioc->write_ctx == ctx) {
68406e0f098SStefan Hajnoczi write_ctx = ctx;
68506e0f098SStefan Hajnoczi io_write = qio_channel_restart_write;
686c4c497d2SPaolo Bonzini }
68706e0f098SStefan Hajnoczi } else if (condition == G_IO_OUT) {
68806e0f098SStefan Hajnoczi ctx = ioc->write_ctx;
68906e0f098SStefan Hajnoczi write_ctx = ctx;
69006e0f098SStefan Hajnoczi io_write = NULL;
69106e0f098SStefan Hajnoczi if (ioc->read_coroutine && ioc->read_ctx == ctx) {
69206e0f098SStefan Hajnoczi read_ctx = ctx;
69306e0f098SStefan Hajnoczi io_read = qio_channel_restart_read;
69406e0f098SStefan Hajnoczi }
69506e0f098SStefan Hajnoczi } else {
69606e0f098SStefan Hajnoczi abort();
697c4c497d2SPaolo Bonzini }
698c4c497d2SPaolo Bonzini
69906e0f098SStefan Hajnoczi qio_channel_set_aio_fd_handler(ioc, read_ctx, io_read,
70006e0f098SStefan Hajnoczi write_ctx, io_write, ioc);
701c4c497d2SPaolo Bonzini }
702666a3af9SDaniel P. Berrange
qio_channel_yield(QIOChannel * ioc,GIOCondition condition)703666a3af9SDaniel P. Berrange void coroutine_fn qio_channel_yield(QIOChannel *ioc,
704666a3af9SDaniel P. Berrange GIOCondition condition)
705666a3af9SDaniel P. Berrange {
70606e0f098SStefan Hajnoczi AioContext *ioc_ctx;
7077c1f51bfSKevin Wolf
708666a3af9SDaniel P. Berrange assert(qemu_in_coroutine());
70906e0f098SStefan Hajnoczi ioc_ctx = qemu_coroutine_get_aio_context(qemu_coroutine_self());
7107c1f51bfSKevin Wolf
711c4c497d2SPaolo Bonzini if (condition == G_IO_IN) {
712c4c497d2SPaolo Bonzini assert(!ioc->read_coroutine);
713c4c497d2SPaolo Bonzini } else if (condition == G_IO_OUT) {
714c4c497d2SPaolo Bonzini assert(!ioc->write_coroutine);
715c4c497d2SPaolo Bonzini } else {
716c4c497d2SPaolo Bonzini abort();
717c4c497d2SPaolo Bonzini }
71806e0f098SStefan Hajnoczi qio_channel_set_fd_handlers(ioc, condition);
719666a3af9SDaniel P. Berrange qemu_coroutine_yield();
7207c1f51bfSKevin Wolf assert(in_aio_context_home_thread(ioc_ctx));
7216886ceafSKevin Wolf
7226886ceafSKevin Wolf /* Allow interrupting the operation by reentering the coroutine other than
7236886ceafSKevin Wolf * through the aio_fd_handlers. */
7247c1f51bfSKevin Wolf if (condition == G_IO_IN) {
7257c1f51bfSKevin Wolf assert(ioc->read_coroutine == NULL);
7267c1f51bfSKevin Wolf } else if (condition == G_IO_OUT) {
7277c1f51bfSKevin Wolf assert(ioc->write_coroutine == NULL);
7286886ceafSKevin Wolf }
72906e0f098SStefan Hajnoczi qio_channel_clear_fd_handlers(ioc, condition);
730666a3af9SDaniel P. Berrange }
731666a3af9SDaniel P. Berrange
qio_channel_wake_read(QIOChannel * ioc)7327c1f51bfSKevin Wolf void qio_channel_wake_read(QIOChannel *ioc)
7337c1f51bfSKevin Wolf {
7347c1f51bfSKevin Wolf Coroutine *co = qatomic_xchg(&ioc->read_coroutine, NULL);
7357c1f51bfSKevin Wolf if (co) {
7367c1f51bfSKevin Wolf aio_co_wake(co);
7377c1f51bfSKevin Wolf }
7387c1f51bfSKevin Wolf }
739666a3af9SDaniel P. Berrange
qio_channel_wait_complete(QIOChannel * ioc,GIOCondition condition,gpointer opaque)740666a3af9SDaniel P. Berrange static gboolean qio_channel_wait_complete(QIOChannel *ioc,
741666a3af9SDaniel P. Berrange GIOCondition condition,
742666a3af9SDaniel P. Berrange gpointer opaque)
743666a3af9SDaniel P. Berrange {
744666a3af9SDaniel P. Berrange GMainLoop *loop = opaque;
745666a3af9SDaniel P. Berrange
746666a3af9SDaniel P. Berrange g_main_loop_quit(loop);
747666a3af9SDaniel P. Berrange return FALSE;
748666a3af9SDaniel P. Berrange }
749666a3af9SDaniel P. Berrange
750666a3af9SDaniel P. Berrange
qio_channel_wait(QIOChannel * ioc,GIOCondition condition)751666a3af9SDaniel P. Berrange void qio_channel_wait(QIOChannel *ioc,
752666a3af9SDaniel P. Berrange GIOCondition condition)
753666a3af9SDaniel P. Berrange {
754666a3af9SDaniel P. Berrange GMainContext *ctxt = g_main_context_new();
755666a3af9SDaniel P. Berrange GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
756666a3af9SDaniel P. Berrange GSource *source;
757666a3af9SDaniel P. Berrange
758666a3af9SDaniel P. Berrange source = qio_channel_create_watch(ioc, condition);
759666a3af9SDaniel P. Berrange
760666a3af9SDaniel P. Berrange g_source_set_callback(source,
761666a3af9SDaniel P. Berrange (GSourceFunc)qio_channel_wait_complete,
762666a3af9SDaniel P. Berrange loop,
763666a3af9SDaniel P. Berrange NULL);
764666a3af9SDaniel P. Berrange
765666a3af9SDaniel P. Berrange g_source_attach(source, ctxt);
766666a3af9SDaniel P. Berrange
767666a3af9SDaniel P. Berrange g_main_loop_run(loop);
768666a3af9SDaniel P. Berrange
769666a3af9SDaniel P. Berrange g_source_unref(source);
770666a3af9SDaniel P. Berrange g_main_loop_unref(loop);
771666a3af9SDaniel P. Berrange g_main_context_unref(ctxt);
772666a3af9SDaniel P. Berrange }
773666a3af9SDaniel P. Berrange
774666a3af9SDaniel P. Berrange
qio_channel_finalize(Object * obj)775a5897205SPaolo Bonzini static void qio_channel_finalize(Object *obj)
776a5897205SPaolo Bonzini {
777a5897205SPaolo Bonzini QIOChannel *ioc = QIO_CHANNEL(obj);
778a5897205SPaolo Bonzini
779acd4be64SStefan Hajnoczi /* Must not have coroutines in qio_channel_yield() */
780acd4be64SStefan Hajnoczi assert(!ioc->read_coroutine);
781acd4be64SStefan Hajnoczi assert(!ioc->write_coroutine);
782acd4be64SStefan Hajnoczi
78320f4aa26SDaniel P. Berrange g_free(ioc->name);
78420f4aa26SDaniel P. Berrange
78520f4aa26SDaniel P. Berrange #ifdef _WIN32
786a5897205SPaolo Bonzini if (ioc->event) {
787a5897205SPaolo Bonzini CloseHandle(ioc->event);
788a5897205SPaolo Bonzini }
789a5897205SPaolo Bonzini #endif
79020f4aa26SDaniel P. Berrange }
791a5897205SPaolo Bonzini
792666a3af9SDaniel P. Berrange static const TypeInfo qio_channel_info = {
793666a3af9SDaniel P. Berrange .parent = TYPE_OBJECT,
794666a3af9SDaniel P. Berrange .name = TYPE_QIO_CHANNEL,
795666a3af9SDaniel P. Berrange .instance_size = sizeof(QIOChannel),
796a5897205SPaolo Bonzini .instance_finalize = qio_channel_finalize,
797666a3af9SDaniel P. Berrange .abstract = true,
798666a3af9SDaniel P. Berrange .class_size = sizeof(QIOChannelClass),
799666a3af9SDaniel P. Berrange };
800666a3af9SDaniel P. Berrange
801666a3af9SDaniel P. Berrange
qio_channel_register_types(void)802666a3af9SDaniel P. Berrange static void qio_channel_register_types(void)
803666a3af9SDaniel P. Berrange {
804666a3af9SDaniel P. Berrange type_register_static(&qio_channel_info);
805666a3af9SDaniel P. Berrange }
806666a3af9SDaniel P. Berrange
807666a3af9SDaniel P. Berrange
808666a3af9SDaniel P. Berrange type_init(qio_channel_register_types);
809