1a6da7ffaSMarc-André Lureau /*
2a6da7ffaSMarc-André Lureau * QEMU System Emulator
3a6da7ffaSMarc-André Lureau *
4a6da7ffaSMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard
5a6da7ffaSMarc-André Lureau *
6a6da7ffaSMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy
7a6da7ffaSMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal
8a6da7ffaSMarc-André Lureau * in the Software without restriction, including without limitation the rights
9a6da7ffaSMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10a6da7ffaSMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is
11a6da7ffaSMarc-André Lureau * furnished to do so, subject to the following conditions:
12a6da7ffaSMarc-André Lureau *
13a6da7ffaSMarc-André Lureau * The above copyright notice and this permission notice shall be included in
14a6da7ffaSMarc-André Lureau * all copies or substantial portions of the Software.
15a6da7ffaSMarc-André Lureau *
16a6da7ffaSMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17a6da7ffaSMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18a6da7ffaSMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19a6da7ffaSMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20a6da7ffaSMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21a6da7ffaSMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22a6da7ffaSMarc-André Lureau * THE SOFTWARE.
23a6da7ffaSMarc-André Lureau */
24a6da7ffaSMarc-André Lureau #include "qemu/osdep.h"
258228e353SMarc-André Lureau #include "chardev/char-io.h"
26a6da7ffaSMarc-André Lureau
27a6da7ffaSMarc-André Lureau typedef struct IOWatchPoll {
28a6da7ffaSMarc-André Lureau GSource parent;
29a6da7ffaSMarc-André Lureau
30a6da7ffaSMarc-André Lureau QIOChannel *ioc;
31a6da7ffaSMarc-André Lureau GSource *src;
32a6da7ffaSMarc-André Lureau
33a6da7ffaSMarc-André Lureau IOCanReadHandler *fd_can_read;
34a6da7ffaSMarc-André Lureau GSourceFunc fd_read;
35a6da7ffaSMarc-André Lureau void *opaque;
36038b4217SDaniel P. Berrangé GMainContext *context;
37a6da7ffaSMarc-André Lureau } IOWatchPoll;
38a6da7ffaSMarc-André Lureau
io_watch_poll_from_source(GSource * source)39a6da7ffaSMarc-André Lureau static IOWatchPoll *io_watch_poll_from_source(GSource *source)
40a6da7ffaSMarc-André Lureau {
41a6da7ffaSMarc-André Lureau return container_of(source, IOWatchPoll, parent);
42a6da7ffaSMarc-André Lureau }
43a6da7ffaSMarc-André Lureau
io_watch_poll_prepare(GSource * source,gint * timeout)44a6da7ffaSMarc-André Lureau static gboolean io_watch_poll_prepare(GSource *source,
45a6da7ffaSMarc-André Lureau gint *timeout)
46a6da7ffaSMarc-André Lureau {
47a6da7ffaSMarc-André Lureau IOWatchPoll *iwp = io_watch_poll_from_source(source);
48a6da7ffaSMarc-André Lureau bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
49a6da7ffaSMarc-André Lureau bool was_active = iwp->src != NULL;
50a6da7ffaSMarc-André Lureau if (was_active == now_active) {
51a6da7ffaSMarc-André Lureau return FALSE;
52a6da7ffaSMarc-André Lureau }
53a6da7ffaSMarc-André Lureau
54038b4217SDaniel P. Berrangé /*
55038b4217SDaniel P. Berrangé * We do not register the QIOChannel watch as a child GSource.
56038b4217SDaniel P. Berrangé * The 'prepare' function on the parent GSource will be
57038b4217SDaniel P. Berrangé * skipped if a child GSource's 'prepare' function indicates
58038b4217SDaniel P. Berrangé * readiness. We need this prepare function be guaranteed
59038b4217SDaniel P. Berrangé * to run on *every* iteration of the main loop, because
60038b4217SDaniel P. Berrangé * it is critical to ensure we remove the QIOChannel watch
61038b4217SDaniel P. Berrangé * if 'fd_can_read' indicates the frontend cannot receive
62038b4217SDaniel P. Berrangé * more data.
63038b4217SDaniel P. Berrangé */
64a6da7ffaSMarc-André Lureau if (now_active) {
65a6da7ffaSMarc-André Lureau iwp->src = qio_channel_create_watch(
66a6da7ffaSMarc-André Lureau iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
67a6da7ffaSMarc-André Lureau g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
68038b4217SDaniel P. Berrangé g_source_attach(iwp->src, iwp->context);
69a7077b8eSMarc-André Lureau } else {
70038b4217SDaniel P. Berrangé g_source_destroy(iwp->src);
71038b4217SDaniel P. Berrangé g_source_unref(iwp->src);
72a6da7ffaSMarc-André Lureau iwp->src = NULL;
73a6da7ffaSMarc-André Lureau }
74a6da7ffaSMarc-André Lureau return FALSE;
75a6da7ffaSMarc-André Lureau }
76a6da7ffaSMarc-André Lureau
io_watch_poll_check(GSource * source)77038b4217SDaniel P. Berrangé static gboolean io_watch_poll_check(GSource *source)
78038b4217SDaniel P. Berrangé {
79038b4217SDaniel P. Berrangé return FALSE;
80038b4217SDaniel P. Berrangé }
81038b4217SDaniel P. Berrangé
io_watch_poll_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)82a6da7ffaSMarc-André Lureau static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
83a6da7ffaSMarc-André Lureau gpointer user_data)
84a6da7ffaSMarc-André Lureau {
85038b4217SDaniel P. Berrangé abort();
86038b4217SDaniel P. Berrangé }
87038b4217SDaniel P. Berrangé
io_watch_poll_finalize(GSource * source)88038b4217SDaniel P. Berrangé static void io_watch_poll_finalize(GSource *source)
89038b4217SDaniel P. Berrangé {
90038b4217SDaniel P. Berrangé IOWatchPoll *iwp = io_watch_poll_from_source(source);
91*e0bf9544SSergey Dyasli if (iwp->src) {
92*e0bf9544SSergey Dyasli g_source_destroy(iwp->src);
93*e0bf9544SSergey Dyasli g_source_unref(iwp->src);
94*e0bf9544SSergey Dyasli iwp->src = NULL;
95*e0bf9544SSergey Dyasli }
96a6da7ffaSMarc-André Lureau }
97a6da7ffaSMarc-André Lureau
98a6da7ffaSMarc-André Lureau static GSourceFuncs io_watch_poll_funcs = {
99a6da7ffaSMarc-André Lureau .prepare = io_watch_poll_prepare,
100038b4217SDaniel P. Berrangé .check = io_watch_poll_check,
101a6da7ffaSMarc-André Lureau .dispatch = io_watch_poll_dispatch,
102038b4217SDaniel P. Berrangé .finalize = io_watch_poll_finalize,
103a6da7ffaSMarc-André Lureau };
104a6da7ffaSMarc-André Lureau
io_add_watch_poll(Chardev * chr,QIOChannel * ioc,IOCanReadHandler * fd_can_read,QIOChannelFunc fd_read,gpointer user_data,GMainContext * context)105b19456ddSzhanghailiang GSource *io_add_watch_poll(Chardev *chr,
106a6da7ffaSMarc-André Lureau QIOChannel *ioc,
107a6da7ffaSMarc-André Lureau IOCanReadHandler *fd_can_read,
108a6da7ffaSMarc-André Lureau QIOChannelFunc fd_read,
109a6da7ffaSMarc-André Lureau gpointer user_data,
110a6da7ffaSMarc-André Lureau GMainContext *context)
111a6da7ffaSMarc-André Lureau {
112a6da7ffaSMarc-André Lureau IOWatchPoll *iwp;
113a6da7ffaSMarc-André Lureau char *name;
114a6da7ffaSMarc-André Lureau
115a6da7ffaSMarc-André Lureau iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
116a6da7ffaSMarc-André Lureau sizeof(IOWatchPoll));
117a6da7ffaSMarc-André Lureau iwp->fd_can_read = fd_can_read;
118a6da7ffaSMarc-André Lureau iwp->opaque = user_data;
119a6da7ffaSMarc-André Lureau iwp->ioc = ioc;
120a6da7ffaSMarc-André Lureau iwp->fd_read = (GSourceFunc) fd_read;
121a6da7ffaSMarc-André Lureau iwp->src = NULL;
122038b4217SDaniel P. Berrangé iwp->context = context;
123a6da7ffaSMarc-André Lureau
124a6da7ffaSMarc-André Lureau name = g_strdup_printf("chardev-iowatch-%s", chr->label);
125a6da7ffaSMarc-André Lureau g_source_set_name((GSource *)iwp, name);
126a6da7ffaSMarc-André Lureau g_free(name);
127a6da7ffaSMarc-André Lureau
128b19456ddSzhanghailiang g_source_attach(&iwp->parent, context);
129a6da7ffaSMarc-André Lureau g_source_unref(&iwp->parent);
130b19456ddSzhanghailiang return (GSource *)iwp;
131a6da7ffaSMarc-André Lureau }
132a6da7ffaSMarc-André Lureau
io_remove_watch_poll(GSource * source)133038b4217SDaniel P. Berrangé static void io_remove_watch_poll(GSource *source)
134038b4217SDaniel P. Berrangé {
135038b4217SDaniel P. Berrangé IOWatchPoll *iwp;
136038b4217SDaniel P. Berrangé
137038b4217SDaniel P. Berrangé iwp = io_watch_poll_from_source(source);
138038b4217SDaniel P. Berrangé g_source_destroy(&iwp->parent);
139038b4217SDaniel P. Berrangé }
140038b4217SDaniel P. Berrangé
remove_fd_in_watch(Chardev * chr)141b19456ddSzhanghailiang void remove_fd_in_watch(Chardev *chr)
142a6da7ffaSMarc-André Lureau {
143b19456ddSzhanghailiang if (chr->gsource) {
144038b4217SDaniel P. Berrangé io_remove_watch_poll(chr->gsource);
145b19456ddSzhanghailiang chr->gsource = NULL;
146a6da7ffaSMarc-André Lureau }
147a6da7ffaSMarc-André Lureau }
148a6da7ffaSMarc-André Lureau
io_channel_send_full(QIOChannel * ioc,const void * buf,size_t len,int * fds,size_t nfds)149a6da7ffaSMarc-André Lureau int io_channel_send_full(QIOChannel *ioc,
150a6da7ffaSMarc-André Lureau const void *buf, size_t len,
151a6da7ffaSMarc-André Lureau int *fds, size_t nfds)
152a6da7ffaSMarc-André Lureau {
153a6da7ffaSMarc-André Lureau size_t offset = 0;
154a6da7ffaSMarc-André Lureau
155a6da7ffaSMarc-André Lureau while (offset < len) {
156a6da7ffaSMarc-André Lureau ssize_t ret = 0;
157a6da7ffaSMarc-André Lureau struct iovec iov = { .iov_base = (char *)buf + offset,
158a6da7ffaSMarc-André Lureau .iov_len = len - offset };
159a6da7ffaSMarc-André Lureau
160a6da7ffaSMarc-André Lureau ret = qio_channel_writev_full(
161a6da7ffaSMarc-André Lureau ioc, &iov, 1,
162b88651cbSLeonardo Bras fds, nfds, 0, NULL);
163a6da7ffaSMarc-André Lureau if (ret == QIO_CHANNEL_ERR_BLOCK) {
164a6da7ffaSMarc-André Lureau if (offset) {
165a6da7ffaSMarc-André Lureau return offset;
166a6da7ffaSMarc-André Lureau }
167a6da7ffaSMarc-André Lureau
168a6da7ffaSMarc-André Lureau errno = EAGAIN;
169a6da7ffaSMarc-André Lureau return -1;
170a6da7ffaSMarc-André Lureau } else if (ret < 0) {
171a6da7ffaSMarc-André Lureau errno = EINVAL;
172a6da7ffaSMarc-André Lureau return -1;
173a6da7ffaSMarc-André Lureau }
174a6da7ffaSMarc-André Lureau
175a6da7ffaSMarc-André Lureau offset += ret;
176a6da7ffaSMarc-André Lureau }
177a6da7ffaSMarc-André Lureau
178a6da7ffaSMarc-André Lureau return offset;
179a6da7ffaSMarc-André Lureau }
180a6da7ffaSMarc-André Lureau
io_channel_send(QIOChannel * ioc,const void * buf,size_t len)181a6da7ffaSMarc-André Lureau int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
182a6da7ffaSMarc-André Lureau {
183a6da7ffaSMarc-André Lureau return io_channel_send_full(ioc, buf, len, NULL, 0);
184a6da7ffaSMarc-André Lureau }
185