xref: /openbmc/qemu/chardev/char-io.c (revision 58ee924b97d1c0898555647a31820c5a20d55a73)
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