xref: /qemu/io/channel-watch.c (revision bf88c1247f80ac6d62710d5d0d0d9ce3a53e99ec)
11c809fa0SDaniel P. Berrange /*
21c809fa0SDaniel P. Berrange  * QEMU I/O channels watch helper APIs
31c809fa0SDaniel P. Berrange  *
41c809fa0SDaniel P. Berrange  * Copyright (c) 2015 Red Hat, Inc.
51c809fa0SDaniel P. Berrange  *
61c809fa0SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
71c809fa0SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
81c809fa0SDaniel P. Berrange  * License as published by the Free Software Foundation; either
91c809fa0SDaniel P. Berrange  * version 2 of the License, or (at your option) any later version.
101c809fa0SDaniel P. Berrange  *
111c809fa0SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
121c809fa0SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
131c809fa0SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
141c809fa0SDaniel P. Berrange  * Lesser General Public License for more details.
151c809fa0SDaniel P. Berrange  *
161c809fa0SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
171c809fa0SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
181c809fa0SDaniel P. Berrange  *
191c809fa0SDaniel P. Berrange  */
201c809fa0SDaniel P. Berrange 
21cae9fc56SPeter Maydell #include "qemu/osdep.h"
221c809fa0SDaniel P. Berrange #include "io/channel-watch.h"
231c809fa0SDaniel P. Berrange 
241c809fa0SDaniel P. Berrange typedef struct QIOChannelFDSource QIOChannelFDSource;
251c809fa0SDaniel P. Berrange struct QIOChannelFDSource {
261c809fa0SDaniel P. Berrange     GSource parent;
271c809fa0SDaniel P. Berrange     GPollFD fd;
281c809fa0SDaniel P. Berrange     QIOChannel *ioc;
291c809fa0SDaniel P. Berrange     GIOCondition condition;
301c809fa0SDaniel P. Berrange };
311c809fa0SDaniel P. Berrange 
321c809fa0SDaniel P. Berrange 
33a5897205SPaolo Bonzini #ifdef CONFIG_WIN32
34a5897205SPaolo Bonzini typedef struct QIOChannelSocketSource QIOChannelSocketSource;
35a5897205SPaolo Bonzini struct QIOChannelSocketSource {
36a5897205SPaolo Bonzini     GSource parent;
37a5897205SPaolo Bonzini     GPollFD fd;
38a5897205SPaolo Bonzini     QIOChannel *ioc;
39a5897205SPaolo Bonzini     SOCKET socket;
40a5897205SPaolo Bonzini     int revents;
41a5897205SPaolo Bonzini     GIOCondition condition;
42a5897205SPaolo Bonzini };
43a5897205SPaolo Bonzini 
44a5897205SPaolo Bonzini #endif
45a5897205SPaolo Bonzini 
46a5897205SPaolo Bonzini 
471c809fa0SDaniel P. Berrange typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
481c809fa0SDaniel P. Berrange struct QIOChannelFDPairSource {
491c809fa0SDaniel P. Berrange     GSource parent;
501c809fa0SDaniel P. Berrange     GPollFD fdread;
511c809fa0SDaniel P. Berrange     GPollFD fdwrite;
521c809fa0SDaniel P. Berrange     QIOChannel *ioc;
531c809fa0SDaniel P. Berrange     GIOCondition condition;
541c809fa0SDaniel P. Berrange };
551c809fa0SDaniel P. Berrange 
561c809fa0SDaniel P. Berrange 
571c809fa0SDaniel P. Berrange static gboolean
581c809fa0SDaniel P. Berrange qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED,
591c809fa0SDaniel P. Berrange                               gint *timeout)
601c809fa0SDaniel P. Berrange {
611c809fa0SDaniel P. Berrange     *timeout = -1;
621c809fa0SDaniel P. Berrange 
631c809fa0SDaniel P. Berrange     return FALSE;
641c809fa0SDaniel P. Berrange }
651c809fa0SDaniel P. Berrange 
661c809fa0SDaniel P. Berrange 
671c809fa0SDaniel P. Berrange static gboolean
681c809fa0SDaniel P. Berrange qio_channel_fd_source_check(GSource *source)
691c809fa0SDaniel P. Berrange {
701c809fa0SDaniel P. Berrange     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
711c809fa0SDaniel P. Berrange 
721c809fa0SDaniel P. Berrange     return ssource->fd.revents & ssource->condition;
731c809fa0SDaniel P. Berrange }
741c809fa0SDaniel P. Berrange 
751c809fa0SDaniel P. Berrange 
761c809fa0SDaniel P. Berrange static gboolean
771c809fa0SDaniel P. Berrange qio_channel_fd_source_dispatch(GSource *source,
781c809fa0SDaniel P. Berrange                                GSourceFunc callback,
791c809fa0SDaniel P. Berrange                                gpointer user_data)
801c809fa0SDaniel P. Berrange {
811c809fa0SDaniel P. Berrange     QIOChannelFunc func = (QIOChannelFunc)callback;
821c809fa0SDaniel P. Berrange     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
831c809fa0SDaniel P. Berrange 
841c809fa0SDaniel P. Berrange     return (*func)(ssource->ioc,
851c809fa0SDaniel P. Berrange                    ssource->fd.revents & ssource->condition,
861c809fa0SDaniel P. Berrange                    user_data);
871c809fa0SDaniel P. Berrange }
881c809fa0SDaniel P. Berrange 
891c809fa0SDaniel P. Berrange 
901c809fa0SDaniel P. Berrange static void
911c809fa0SDaniel P. Berrange qio_channel_fd_source_finalize(GSource *source)
921c809fa0SDaniel P. Berrange {
931c809fa0SDaniel P. Berrange     QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
941c809fa0SDaniel P. Berrange 
951c809fa0SDaniel P. Berrange     object_unref(OBJECT(ssource->ioc));
961c809fa0SDaniel P. Berrange }
971c809fa0SDaniel P. Berrange 
981c809fa0SDaniel P. Berrange 
99a5897205SPaolo Bonzini #ifdef CONFIG_WIN32
100a5897205SPaolo Bonzini static gboolean
101a5897205SPaolo Bonzini qio_channel_socket_source_prepare(GSource *source G_GNUC_UNUSED,
102a5897205SPaolo Bonzini                                   gint *timeout)
103a5897205SPaolo Bonzini {
104a5897205SPaolo Bonzini     *timeout = -1;
105a5897205SPaolo Bonzini 
106a5897205SPaolo Bonzini     return FALSE;
107a5897205SPaolo Bonzini }
108a5897205SPaolo Bonzini 
109a5897205SPaolo Bonzini 
110a5897205SPaolo Bonzini /*
111a5897205SPaolo Bonzini  * NB, this impl only works when the socket is in non-blocking
112a5897205SPaolo Bonzini  * mode on Win32
113a5897205SPaolo Bonzini  */
114a5897205SPaolo Bonzini static gboolean
115a5897205SPaolo Bonzini qio_channel_socket_source_check(GSource *source)
116a5897205SPaolo Bonzini {
117a5897205SPaolo Bonzini     static struct timeval tv0;
118a5897205SPaolo Bonzini 
119a5897205SPaolo Bonzini     QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
120a5897205SPaolo Bonzini     WSANETWORKEVENTS ev;
121a5897205SPaolo Bonzini     fd_set rfds, wfds, xfds;
122a5897205SPaolo Bonzini 
123a5897205SPaolo Bonzini     if (!ssource->condition) {
124a5897205SPaolo Bonzini         return 0;
125a5897205SPaolo Bonzini     }
126a5897205SPaolo Bonzini 
127a5897205SPaolo Bonzini     WSAEnumNetworkEvents(ssource->socket, ssource->ioc->event, &ev);
128a5897205SPaolo Bonzini 
129a5897205SPaolo Bonzini     FD_ZERO(&rfds);
130a5897205SPaolo Bonzini     FD_ZERO(&wfds);
131a5897205SPaolo Bonzini     FD_ZERO(&xfds);
132a5897205SPaolo Bonzini     if (ssource->condition & G_IO_IN) {
133a5897205SPaolo Bonzini         FD_SET((SOCKET)ssource->socket, &rfds);
134a5897205SPaolo Bonzini     }
135a5897205SPaolo Bonzini     if (ssource->condition & G_IO_OUT) {
136a5897205SPaolo Bonzini         FD_SET((SOCKET)ssource->socket, &wfds);
137a5897205SPaolo Bonzini     }
138a5897205SPaolo Bonzini     if (ssource->condition & G_IO_PRI) {
139a5897205SPaolo Bonzini         FD_SET((SOCKET)ssource->socket, &xfds);
140a5897205SPaolo Bonzini     }
141a5897205SPaolo Bonzini     ssource->revents = 0;
142a5897205SPaolo Bonzini     if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) {
143a5897205SPaolo Bonzini         return 0;
144a5897205SPaolo Bonzini     }
145a5897205SPaolo Bonzini 
146a5897205SPaolo Bonzini     if (FD_ISSET(ssource->socket, &rfds)) {
147a5897205SPaolo Bonzini         ssource->revents |= G_IO_IN;
148a5897205SPaolo Bonzini     }
149a5897205SPaolo Bonzini     if (FD_ISSET(ssource->socket, &wfds)) {
150a5897205SPaolo Bonzini         ssource->revents |= G_IO_OUT;
151a5897205SPaolo Bonzini     }
152a5897205SPaolo Bonzini     if (FD_ISSET(ssource->socket, &xfds)) {
153a5897205SPaolo Bonzini         ssource->revents |= G_IO_PRI;
154a5897205SPaolo Bonzini     }
155a5897205SPaolo Bonzini 
156a5897205SPaolo Bonzini     return ssource->revents;
157a5897205SPaolo Bonzini }
158a5897205SPaolo Bonzini 
159a5897205SPaolo Bonzini 
160a5897205SPaolo Bonzini static gboolean
161a5897205SPaolo Bonzini qio_channel_socket_source_dispatch(GSource *source,
162a5897205SPaolo Bonzini                                    GSourceFunc callback,
163a5897205SPaolo Bonzini                                    gpointer user_data)
164a5897205SPaolo Bonzini {
165a5897205SPaolo Bonzini     QIOChannelFunc func = (QIOChannelFunc)callback;
166a5897205SPaolo Bonzini     QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
167a5897205SPaolo Bonzini 
168a5897205SPaolo Bonzini     return (*func)(ssource->ioc, ssource->revents, user_data);
169a5897205SPaolo Bonzini }
170a5897205SPaolo Bonzini 
171a5897205SPaolo Bonzini 
172a5897205SPaolo Bonzini static void
173a5897205SPaolo Bonzini qio_channel_socket_source_finalize(GSource *source)
174a5897205SPaolo Bonzini {
175a5897205SPaolo Bonzini     QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
176a5897205SPaolo Bonzini 
177a5897205SPaolo Bonzini     object_unref(OBJECT(ssource->ioc));
178a5897205SPaolo Bonzini }
179a5897205SPaolo Bonzini 
180a5897205SPaolo Bonzini 
181a5897205SPaolo Bonzini GSourceFuncs qio_channel_socket_source_funcs = {
182a5897205SPaolo Bonzini     qio_channel_socket_source_prepare,
183a5897205SPaolo Bonzini     qio_channel_socket_source_check,
184a5897205SPaolo Bonzini     qio_channel_socket_source_dispatch,
185a5897205SPaolo Bonzini     qio_channel_socket_source_finalize
186a5897205SPaolo Bonzini };
187a5897205SPaolo Bonzini #endif
188a5897205SPaolo Bonzini 
189a5897205SPaolo Bonzini 
1901c809fa0SDaniel P. Berrange static gboolean
1911c809fa0SDaniel P. Berrange qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
1921c809fa0SDaniel P. Berrange                                    gint *timeout)
1931c809fa0SDaniel P. Berrange {
1941c809fa0SDaniel P. Berrange     *timeout = -1;
1951c809fa0SDaniel P. Berrange 
1961c809fa0SDaniel P. Berrange     return FALSE;
1971c809fa0SDaniel P. Berrange }
1981c809fa0SDaniel P. Berrange 
1991c809fa0SDaniel P. Berrange 
2001c809fa0SDaniel P. Berrange static gboolean
2011c809fa0SDaniel P. Berrange qio_channel_fd_pair_source_check(GSource *source)
2021c809fa0SDaniel P. Berrange {
2031c809fa0SDaniel P. Berrange     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
2041c809fa0SDaniel P. Berrange     GIOCondition poll_condition = ssource->fdread.revents |
2051c809fa0SDaniel P. Berrange         ssource->fdwrite.revents;
2061c809fa0SDaniel P. Berrange 
2071c809fa0SDaniel P. Berrange     return poll_condition & ssource->condition;
2081c809fa0SDaniel P. Berrange }
2091c809fa0SDaniel P. Berrange 
2101c809fa0SDaniel P. Berrange 
2111c809fa0SDaniel P. Berrange static gboolean
2121c809fa0SDaniel P. Berrange qio_channel_fd_pair_source_dispatch(GSource *source,
2131c809fa0SDaniel P. Berrange                                     GSourceFunc callback,
2141c809fa0SDaniel P. Berrange                                     gpointer user_data)
2151c809fa0SDaniel P. Berrange {
2161c809fa0SDaniel P. Berrange     QIOChannelFunc func = (QIOChannelFunc)callback;
2171c809fa0SDaniel P. Berrange     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
2181c809fa0SDaniel P. Berrange     GIOCondition poll_condition = ssource->fdread.revents |
2191c809fa0SDaniel P. Berrange         ssource->fdwrite.revents;
2201c809fa0SDaniel P. Berrange 
2211c809fa0SDaniel P. Berrange     return (*func)(ssource->ioc,
2221c809fa0SDaniel P. Berrange                    poll_condition & ssource->condition,
2231c809fa0SDaniel P. Berrange                    user_data);
2241c809fa0SDaniel P. Berrange }
2251c809fa0SDaniel P. Berrange 
2261c809fa0SDaniel P. Berrange 
2271c809fa0SDaniel P. Berrange static void
2281c809fa0SDaniel P. Berrange qio_channel_fd_pair_source_finalize(GSource *source)
2291c809fa0SDaniel P. Berrange {
2301c809fa0SDaniel P. Berrange     QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
2311c809fa0SDaniel P. Berrange 
2321c809fa0SDaniel P. Berrange     object_unref(OBJECT(ssource->ioc));
2331c809fa0SDaniel P. Berrange }
2341c809fa0SDaniel P. Berrange 
2351c809fa0SDaniel P. Berrange 
2361c809fa0SDaniel P. Berrange GSourceFuncs qio_channel_fd_source_funcs = {
2371c809fa0SDaniel P. Berrange     qio_channel_fd_source_prepare,
2381c809fa0SDaniel P. Berrange     qio_channel_fd_source_check,
2391c809fa0SDaniel P. Berrange     qio_channel_fd_source_dispatch,
2401c809fa0SDaniel P. Berrange     qio_channel_fd_source_finalize
2411c809fa0SDaniel P. Berrange };
2421c809fa0SDaniel P. Berrange 
2431c809fa0SDaniel P. Berrange 
2441c809fa0SDaniel P. Berrange GSourceFuncs qio_channel_fd_pair_source_funcs = {
2451c809fa0SDaniel P. Berrange     qio_channel_fd_pair_source_prepare,
2461c809fa0SDaniel P. Berrange     qio_channel_fd_pair_source_check,
2471c809fa0SDaniel P. Berrange     qio_channel_fd_pair_source_dispatch,
2481c809fa0SDaniel P. Berrange     qio_channel_fd_pair_source_finalize
2491c809fa0SDaniel P. Berrange };
2501c809fa0SDaniel P. Berrange 
2511c809fa0SDaniel P. Berrange 
2521c809fa0SDaniel P. Berrange GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
2531c809fa0SDaniel P. Berrange                                      int fd,
2541c809fa0SDaniel P. Berrange                                      GIOCondition condition)
2551c809fa0SDaniel P. Berrange {
2561c809fa0SDaniel P. Berrange     GSource *source;
2571c809fa0SDaniel P. Berrange     QIOChannelFDSource *ssource;
2581c809fa0SDaniel P. Berrange 
2591c809fa0SDaniel P. Berrange     source = g_source_new(&qio_channel_fd_source_funcs,
2601c809fa0SDaniel P. Berrange                           sizeof(QIOChannelFDSource));
2611c809fa0SDaniel P. Berrange     ssource = (QIOChannelFDSource *)source;
2621c809fa0SDaniel P. Berrange 
2631c809fa0SDaniel P. Berrange     ssource->ioc = ioc;
2641c809fa0SDaniel P. Berrange     object_ref(OBJECT(ioc));
2651c809fa0SDaniel P. Berrange 
2661c809fa0SDaniel P. Berrange     ssource->condition = condition;
2671c809fa0SDaniel P. Berrange 
268e560d141SPaolo Bonzini #ifdef CONFIG_WIN32
269e560d141SPaolo Bonzini     ssource->fd.fd = (gint64)_get_osfhandle(fd);
270e560d141SPaolo Bonzini #else
2711c809fa0SDaniel P. Berrange     ssource->fd.fd = fd;
272e560d141SPaolo Bonzini #endif
2731c809fa0SDaniel P. Berrange     ssource->fd.events = condition;
2741c809fa0SDaniel P. Berrange 
2751c809fa0SDaniel P. Berrange     g_source_add_poll(source, &ssource->fd);
2761c809fa0SDaniel P. Berrange 
2771c809fa0SDaniel P. Berrange     return source;
2781c809fa0SDaniel P. Berrange }
2791c809fa0SDaniel P. Berrange 
280b83b68a0SPaolo Bonzini #ifdef CONFIG_WIN32
281b83b68a0SPaolo Bonzini GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
282b83b68a0SPaolo Bonzini                                          int socket,
283b83b68a0SPaolo Bonzini                                          GIOCondition condition)
284b83b68a0SPaolo Bonzini {
285a5897205SPaolo Bonzini     GSource *source;
286a5897205SPaolo Bonzini     QIOChannelSocketSource *ssource;
287a5897205SPaolo Bonzini 
288*bf88c124SPaolo Bonzini #ifdef WIN32
289*bf88c124SPaolo Bonzini     WSAEventSelect(socket, ioc->event,
290*bf88c124SPaolo Bonzini                    FD_READ | FD_ACCEPT | FD_CLOSE |
291*bf88c124SPaolo Bonzini                    FD_CONNECT | FD_WRITE | FD_OOB);
292*bf88c124SPaolo Bonzini #endif
293*bf88c124SPaolo Bonzini 
294a5897205SPaolo Bonzini     source = g_source_new(&qio_channel_socket_source_funcs,
295a5897205SPaolo Bonzini                           sizeof(QIOChannelSocketSource));
296a5897205SPaolo Bonzini     ssource = (QIOChannelSocketSource *)source;
297a5897205SPaolo Bonzini 
298a5897205SPaolo Bonzini     ssource->ioc = ioc;
299a5897205SPaolo Bonzini     object_ref(OBJECT(ioc));
300a5897205SPaolo Bonzini 
301a5897205SPaolo Bonzini     ssource->condition = condition;
302a5897205SPaolo Bonzini     ssource->socket = socket;
303a5897205SPaolo Bonzini     ssource->revents = 0;
304a5897205SPaolo Bonzini 
305a5897205SPaolo Bonzini     ssource->fd.fd = (gintptr)ioc->event;
306a5897205SPaolo Bonzini     ssource->fd.events = G_IO_IN;
307a5897205SPaolo Bonzini 
308a5897205SPaolo Bonzini     g_source_add_poll(source, &ssource->fd);
309a5897205SPaolo Bonzini 
310a5897205SPaolo Bonzini     return source;
311b83b68a0SPaolo Bonzini }
312b83b68a0SPaolo Bonzini #else
313b83b68a0SPaolo Bonzini GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
314b83b68a0SPaolo Bonzini                                          int socket,
315b83b68a0SPaolo Bonzini                                          GIOCondition condition)
316b83b68a0SPaolo Bonzini {
317b83b68a0SPaolo Bonzini     return qio_channel_create_fd_watch(ioc, socket, condition);
318b83b68a0SPaolo Bonzini }
319b83b68a0SPaolo Bonzini #endif
3201c809fa0SDaniel P. Berrange 
3211c809fa0SDaniel P. Berrange GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
3221c809fa0SDaniel P. Berrange                                           int fdread,
3231c809fa0SDaniel P. Berrange                                           int fdwrite,
3241c809fa0SDaniel P. Berrange                                           GIOCondition condition)
3251c809fa0SDaniel P. Berrange {
3261c809fa0SDaniel P. Berrange     GSource *source;
3271c809fa0SDaniel P. Berrange     QIOChannelFDPairSource *ssource;
3281c809fa0SDaniel P. Berrange 
3291c809fa0SDaniel P. Berrange     source = g_source_new(&qio_channel_fd_pair_source_funcs,
3301c809fa0SDaniel P. Berrange                           sizeof(QIOChannelFDPairSource));
3311c809fa0SDaniel P. Berrange     ssource = (QIOChannelFDPairSource *)source;
3321c809fa0SDaniel P. Berrange 
3331c809fa0SDaniel P. Berrange     ssource->ioc = ioc;
3341c809fa0SDaniel P. Berrange     object_ref(OBJECT(ioc));
3351c809fa0SDaniel P. Berrange 
3361c809fa0SDaniel P. Berrange     ssource->condition = condition;
3371c809fa0SDaniel P. Berrange 
338e560d141SPaolo Bonzini #ifdef CONFIG_WIN32
339e560d141SPaolo Bonzini     ssource->fdread.fd = (gint64)_get_osfhandle(fdread);
340e560d141SPaolo Bonzini     ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite);
341e560d141SPaolo Bonzini #else
3421c809fa0SDaniel P. Berrange     ssource->fdread.fd = fdread;
3431c809fa0SDaniel P. Berrange     ssource->fdwrite.fd = fdwrite;
344e560d141SPaolo Bonzini #endif
345e560d141SPaolo Bonzini 
346e560d141SPaolo Bonzini     ssource->fdread.events = condition & G_IO_IN;
3471c809fa0SDaniel P. Berrange     ssource->fdwrite.events = condition & G_IO_OUT;
3481c809fa0SDaniel P. Berrange 
3491c809fa0SDaniel P. Berrange     g_source_add_poll(source, &ssource->fdread);
3501c809fa0SDaniel P. Berrange     g_source_add_poll(source, &ssource->fdwrite);
3511c809fa0SDaniel P. Berrange 
3521c809fa0SDaniel P. Berrange     return source;
3531c809fa0SDaniel P. Berrange }
354