]> git.proxmox.com Git - mirror_qemu.git/blame - io/channel-watch.c
Merge tag 'pull-request-2023-12-20' of https://gitlab.com/thuth/qemu into staging
[mirror_qemu.git] / io / channel-watch.c
CommitLineData
1c809fa0
DB
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
c8198bd5 9 * version 2.1 of the License, or (at your option) any later version.
1c809fa0
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"
1c809fa0
DB
22#include "io/channel-watch.h"
23
24typedef struct QIOChannelFDSource QIOChannelFDSource;
25struct QIOChannelFDSource {
26 GSource parent;
27 GPollFD fd;
28 QIOChannel *ioc;
29 GIOCondition condition;
30};
31
32
a5897205
PB
33#ifdef CONFIG_WIN32
34typedef struct QIOChannelSocketSource QIOChannelSocketSource;
35struct QIOChannelSocketSource {
36 GSource parent;
37 GPollFD fd;
38 QIOChannel *ioc;
39 SOCKET socket;
40 int revents;
41 GIOCondition condition;
42};
43
44#endif
45
46
1c809fa0
DB
47typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
48struct QIOChannelFDPairSource {
49 GSource parent;
50 GPollFD fdread;
51 GPollFD fdwrite;
52 QIOChannel *ioc;
53 GIOCondition condition;
54};
55
56
57static gboolean
58qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED,
59 gint *timeout)
60{
61 *timeout = -1;
62
63 return FALSE;
64}
65
66
67static gboolean
68qio_channel_fd_source_check(GSource *source)
69{
70 QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
71
72 return ssource->fd.revents & ssource->condition;
73}
74
75
76static gboolean
77qio_channel_fd_source_dispatch(GSource *source,
78 GSourceFunc callback,
79 gpointer user_data)
80{
81 QIOChannelFunc func = (QIOChannelFunc)callback;
82 QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
83
84 return (*func)(ssource->ioc,
85 ssource->fd.revents & ssource->condition,
86 user_data);
87}
88
89
90static void
91qio_channel_fd_source_finalize(GSource *source)
92{
93 QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
94
95 object_unref(OBJECT(ssource->ioc));
96}
97
98
a5897205
PB
99#ifdef CONFIG_WIN32
100static gboolean
101qio_channel_socket_source_prepare(GSource *source G_GNUC_UNUSED,
102 gint *timeout)
103{
104 *timeout = -1;
105
106 return FALSE;
107}
108
109
110/*
111 * NB, this impl only works when the socket is in non-blocking
112 * mode on Win32
113 */
114static gboolean
115qio_channel_socket_source_check(GSource *source)
116{
117 static struct timeval tv0;
a5897205 118 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
a5897205
PB
119 fd_set rfds, wfds, xfds;
120
121 if (!ssource->condition) {
122 return 0;
123 }
124
a5897205
PB
125 FD_ZERO(&rfds);
126 FD_ZERO(&wfds);
127 FD_ZERO(&xfds);
128 if (ssource->condition & G_IO_IN) {
6c822a03 129 FD_SET(ssource->socket, &rfds);
a5897205
PB
130 }
131 if (ssource->condition & G_IO_OUT) {
6c822a03 132 FD_SET(ssource->socket, &wfds);
a5897205
PB
133 }
134 if (ssource->condition & G_IO_PRI) {
6c822a03 135 FD_SET(ssource->socket, &xfds);
a5897205
PB
136 }
137 ssource->revents = 0;
138 if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) {
139 return 0;
140 }
141
142 if (FD_ISSET(ssource->socket, &rfds)) {
143 ssource->revents |= G_IO_IN;
144 }
145 if (FD_ISSET(ssource->socket, &wfds)) {
146 ssource->revents |= G_IO_OUT;
147 }
148 if (FD_ISSET(ssource->socket, &xfds)) {
149 ssource->revents |= G_IO_PRI;
150 }
151
152 return ssource->revents;
153}
154
155
156static gboolean
157qio_channel_socket_source_dispatch(GSource *source,
158 GSourceFunc callback,
159 gpointer user_data)
160{
161 QIOChannelFunc func = (QIOChannelFunc)callback;
162 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
163
164 return (*func)(ssource->ioc, ssource->revents, user_data);
165}
166
167
168static void
169qio_channel_socket_source_finalize(GSource *source)
170{
171 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
172
173 object_unref(OBJECT(ssource->ioc));
174}
175
176
177GSourceFuncs qio_channel_socket_source_funcs = {
178 qio_channel_socket_source_prepare,
179 qio_channel_socket_source_check,
180 qio_channel_socket_source_dispatch,
181 qio_channel_socket_source_finalize
182};
183#endif
184
185
1c809fa0
DB
186static gboolean
187qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
188 gint *timeout)
189{
190 *timeout = -1;
191
192 return FALSE;
193}
194
195
196static gboolean
197qio_channel_fd_pair_source_check(GSource *source)
198{
199 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
200 GIOCondition poll_condition = ssource->fdread.revents |
201 ssource->fdwrite.revents;
202
203 return poll_condition & ssource->condition;
204}
205
206
207static gboolean
208qio_channel_fd_pair_source_dispatch(GSource *source,
209 GSourceFunc callback,
210 gpointer user_data)
211{
212 QIOChannelFunc func = (QIOChannelFunc)callback;
213 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
214 GIOCondition poll_condition = ssource->fdread.revents |
215 ssource->fdwrite.revents;
216
217 return (*func)(ssource->ioc,
218 poll_condition & ssource->condition,
219 user_data);
220}
221
222
223static void
224qio_channel_fd_pair_source_finalize(GSource *source)
225{
226 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
227
228 object_unref(OBJECT(ssource->ioc));
229}
230
231
232GSourceFuncs qio_channel_fd_source_funcs = {
233 qio_channel_fd_source_prepare,
234 qio_channel_fd_source_check,
235 qio_channel_fd_source_dispatch,
236 qio_channel_fd_source_finalize
237};
238
239
240GSourceFuncs qio_channel_fd_pair_source_funcs = {
241 qio_channel_fd_pair_source_prepare,
242 qio_channel_fd_pair_source_check,
243 qio_channel_fd_pair_source_dispatch,
244 qio_channel_fd_pair_source_finalize
245};
246
247
248GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
249 int fd,
250 GIOCondition condition)
251{
252 GSource *source;
253 QIOChannelFDSource *ssource;
254
255 source = g_source_new(&qio_channel_fd_source_funcs,
256 sizeof(QIOChannelFDSource));
257 ssource = (QIOChannelFDSource *)source;
258
259 ssource->ioc = ioc;
260 object_ref(OBJECT(ioc));
261
262 ssource->condition = condition;
263
e560d141
PB
264#ifdef CONFIG_WIN32
265 ssource->fd.fd = (gint64)_get_osfhandle(fd);
266#else
1c809fa0 267 ssource->fd.fd = fd;
e560d141 268#endif
1c809fa0
DB
269 ssource->fd.events = condition;
270
271 g_source_add_poll(source, &ssource->fd);
272
273 return source;
274}
275
b83b68a0
PB
276#ifdef CONFIG_WIN32
277GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
abe34282 278 int sockfd,
b83b68a0
PB
279 GIOCondition condition)
280{
a5897205
PB
281 GSource *source;
282 QIOChannelSocketSource *ssource;
283
abe34282 284 qemu_socket_select(sockfd, ioc->event,
f5fd677a
MAL
285 FD_READ | FD_ACCEPT | FD_CLOSE |
286 FD_CONNECT | FD_WRITE | FD_OOB, NULL);
bf88c124 287
a5897205
PB
288 source = g_source_new(&qio_channel_socket_source_funcs,
289 sizeof(QIOChannelSocketSource));
290 ssource = (QIOChannelSocketSource *)source;
291
292 ssource->ioc = ioc;
293 object_ref(OBJECT(ioc));
294
295 ssource->condition = condition;
abe34282 296 ssource->socket = _get_osfhandle(sockfd);
a5897205
PB
297 ssource->revents = 0;
298
299 ssource->fd.fd = (gintptr)ioc->event;
300 ssource->fd.events = G_IO_IN;
301
302 g_source_add_poll(source, &ssource->fd);
303
304 return source;
b83b68a0
PB
305}
306#else
307GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
308 int socket,
309 GIOCondition condition)
310{
311 return qio_channel_create_fd_watch(ioc, socket, condition);
312}
313#endif
1c809fa0
DB
314
315GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
316 int fdread,
317 int fdwrite,
318 GIOCondition condition)
319{
320 GSource *source;
321 QIOChannelFDPairSource *ssource;
322
323 source = g_source_new(&qio_channel_fd_pair_source_funcs,
324 sizeof(QIOChannelFDPairSource));
325 ssource = (QIOChannelFDPairSource *)source;
326
327 ssource->ioc = ioc;
328 object_ref(OBJECT(ioc));
329
330 ssource->condition = condition;
331
e560d141
PB
332#ifdef CONFIG_WIN32
333 ssource->fdread.fd = (gint64)_get_osfhandle(fdread);
334 ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite);
335#else
1c809fa0 336 ssource->fdread.fd = fdread;
1c809fa0 337 ssource->fdwrite.fd = fdwrite;
e560d141
PB
338#endif
339
340 ssource->fdread.events = condition & G_IO_IN;
1c809fa0
DB
341 ssource->fdwrite.events = condition & G_IO_OUT;
342
343 g_source_add_poll(source, &ssource->fdread);
344 g_source_add_poll(source, &ssource->fdwrite);
345
346 return source;
347}