xref: /openbmc/qemu/io/channel-watch.c (revision 84a3a53c)
1 /*
2  * QEMU I/O channels watch helper APIs
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 "io/channel-watch.h"
22 
23 typedef struct QIOChannelFDSource QIOChannelFDSource;
24 struct QIOChannelFDSource {
25     GSource parent;
26     GPollFD fd;
27     QIOChannel *ioc;
28     GIOCondition condition;
29 };
30 
31 
32 typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
33 struct QIOChannelFDPairSource {
34     GSource parent;
35     GPollFD fdread;
36     GPollFD fdwrite;
37     QIOChannel *ioc;
38     GIOCondition condition;
39 };
40 
41 
42 static gboolean
43 qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED,
44                               gint *timeout)
45 {
46     *timeout = -1;
47 
48     return FALSE;
49 }
50 
51 
52 static gboolean
53 qio_channel_fd_source_check(GSource *source)
54 {
55     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
56 
57     return ssource->fd.revents & ssource->condition;
58 }
59 
60 
61 static gboolean
62 qio_channel_fd_source_dispatch(GSource *source,
63                                GSourceFunc callback,
64                                gpointer user_data)
65 {
66     QIOChannelFunc func = (QIOChannelFunc)callback;
67     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
68 
69     return (*func)(ssource->ioc,
70                    ssource->fd.revents & ssource->condition,
71                    user_data);
72 }
73 
74 
75 static void
76 qio_channel_fd_source_finalize(GSource *source)
77 {
78     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
79 
80     object_unref(OBJECT(ssource->ioc));
81 }
82 
83 
84 static gboolean
85 qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
86                                    gint *timeout)
87 {
88     *timeout = -1;
89 
90     return FALSE;
91 }
92 
93 
94 static gboolean
95 qio_channel_fd_pair_source_check(GSource *source)
96 {
97     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
98     GIOCondition poll_condition = ssource->fdread.revents |
99         ssource->fdwrite.revents;
100 
101     return poll_condition & ssource->condition;
102 }
103 
104 
105 static gboolean
106 qio_channel_fd_pair_source_dispatch(GSource *source,
107                                     GSourceFunc callback,
108                                     gpointer user_data)
109 {
110     QIOChannelFunc func = (QIOChannelFunc)callback;
111     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
112     GIOCondition poll_condition = ssource->fdread.revents |
113         ssource->fdwrite.revents;
114 
115     return (*func)(ssource->ioc,
116                    poll_condition & ssource->condition,
117                    user_data);
118 }
119 
120 
121 static void
122 qio_channel_fd_pair_source_finalize(GSource *source)
123 {
124     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
125 
126     object_unref(OBJECT(ssource->ioc));
127 }
128 
129 
130 GSourceFuncs qio_channel_fd_source_funcs = {
131     qio_channel_fd_source_prepare,
132     qio_channel_fd_source_check,
133     qio_channel_fd_source_dispatch,
134     qio_channel_fd_source_finalize
135 };
136 
137 
138 GSourceFuncs qio_channel_fd_pair_source_funcs = {
139     qio_channel_fd_pair_source_prepare,
140     qio_channel_fd_pair_source_check,
141     qio_channel_fd_pair_source_dispatch,
142     qio_channel_fd_pair_source_finalize
143 };
144 
145 
146 GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
147                                      int fd,
148                                      GIOCondition condition)
149 {
150     GSource *source;
151     QIOChannelFDSource *ssource;
152 
153     source = g_source_new(&qio_channel_fd_source_funcs,
154                           sizeof(QIOChannelFDSource));
155     ssource = (QIOChannelFDSource *)source;
156 
157     ssource->ioc = ioc;
158     object_ref(OBJECT(ioc));
159 
160     ssource->condition = condition;
161 
162     ssource->fd.fd = fd;
163     ssource->fd.events = condition;
164 
165     g_source_add_poll(source, &ssource->fd);
166 
167     return source;
168 }
169 
170 
171 GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
172                                           int fdread,
173                                           int fdwrite,
174                                           GIOCondition condition)
175 {
176     GSource *source;
177     QIOChannelFDPairSource *ssource;
178 
179     source = g_source_new(&qio_channel_fd_pair_source_funcs,
180                           sizeof(QIOChannelFDPairSource));
181     ssource = (QIOChannelFDPairSource *)source;
182 
183     ssource->ioc = ioc;
184     object_ref(OBJECT(ioc));
185 
186     ssource->condition = condition;
187 
188     ssource->fdread.fd = fdread;
189     ssource->fdread.events = condition & G_IO_IN;
190 
191     ssource->fdwrite.fd = fdwrite;
192     ssource->fdwrite.events = condition & G_IO_OUT;
193 
194     g_source_add_poll(source, &ssource->fdread);
195     g_source_add_poll(source, &ssource->fdwrite);
196 
197     return source;
198 }
199