channel-watch.c (8922B)
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.1 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 "qemu/osdep.h" 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 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 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 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; 118 119 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source; 120 WSANETWORKEVENTS ev; 121 fd_set rfds, wfds, xfds; 122 123 if (!ssource->condition) { 124 return 0; 125 } 126 127 WSAEnumNetworkEvents(ssource->socket, ssource->ioc->event, &ev); 128 129 FD_ZERO(&rfds); 130 FD_ZERO(&wfds); 131 FD_ZERO(&xfds); 132 if (ssource->condition & G_IO_IN) { 133 FD_SET((SOCKET)ssource->socket, &rfds); 134 } 135 if (ssource->condition & G_IO_OUT) { 136 FD_SET((SOCKET)ssource->socket, &wfds); 137 } 138 if (ssource->condition & G_IO_PRI) { 139 FD_SET((SOCKET)ssource->socket, &xfds); 140 } 141 ssource->revents = 0; 142 if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) { 143 return 0; 144 } 145 146 if (FD_ISSET(ssource->socket, &rfds)) { 147 ssource->revents |= G_IO_IN; 148 } 149 if (FD_ISSET(ssource->socket, &wfds)) { 150 ssource->revents |= G_IO_OUT; 151 } 152 if (FD_ISSET(ssource->socket, &xfds)) { 153 ssource->revents |= G_IO_PRI; 154 } 155 156 return ssource->revents; 157} 158 159 160static gboolean 161qio_channel_socket_source_dispatch(GSource *source, 162 GSourceFunc callback, 163 gpointer user_data) 164{ 165 QIOChannelFunc func = (QIOChannelFunc)callback; 166 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source; 167 168 return (*func)(ssource->ioc, ssource->revents, user_data); 169} 170 171 172static void 173qio_channel_socket_source_finalize(GSource *source) 174{ 175 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source; 176 177 object_unref(OBJECT(ssource->ioc)); 178} 179 180 181GSourceFuncs qio_channel_socket_source_funcs = { 182 qio_channel_socket_source_prepare, 183 qio_channel_socket_source_check, 184 qio_channel_socket_source_dispatch, 185 qio_channel_socket_source_finalize 186}; 187#endif 188 189 190static gboolean 191qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED, 192 gint *timeout) 193{ 194 *timeout = -1; 195 196 return FALSE; 197} 198 199 200static gboolean 201qio_channel_fd_pair_source_check(GSource *source) 202{ 203 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source; 204 GIOCondition poll_condition = ssource->fdread.revents | 205 ssource->fdwrite.revents; 206 207 return poll_condition & ssource->condition; 208} 209 210 211static gboolean 212qio_channel_fd_pair_source_dispatch(GSource *source, 213 GSourceFunc callback, 214 gpointer user_data) 215{ 216 QIOChannelFunc func = (QIOChannelFunc)callback; 217 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source; 218 GIOCondition poll_condition = ssource->fdread.revents | 219 ssource->fdwrite.revents; 220 221 return (*func)(ssource->ioc, 222 poll_condition & ssource->condition, 223 user_data); 224} 225 226 227static void 228qio_channel_fd_pair_source_finalize(GSource *source) 229{ 230 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source; 231 232 object_unref(OBJECT(ssource->ioc)); 233} 234 235 236GSourceFuncs qio_channel_fd_source_funcs = { 237 qio_channel_fd_source_prepare, 238 qio_channel_fd_source_check, 239 qio_channel_fd_source_dispatch, 240 qio_channel_fd_source_finalize 241}; 242 243 244GSourceFuncs qio_channel_fd_pair_source_funcs = { 245 qio_channel_fd_pair_source_prepare, 246 qio_channel_fd_pair_source_check, 247 qio_channel_fd_pair_source_dispatch, 248 qio_channel_fd_pair_source_finalize 249}; 250 251 252GSource *qio_channel_create_fd_watch(QIOChannel *ioc, 253 int fd, 254 GIOCondition condition) 255{ 256 GSource *source; 257 QIOChannelFDSource *ssource; 258 259 source = g_source_new(&qio_channel_fd_source_funcs, 260 sizeof(QIOChannelFDSource)); 261 ssource = (QIOChannelFDSource *)source; 262 263 ssource->ioc = ioc; 264 object_ref(OBJECT(ioc)); 265 266 ssource->condition = condition; 267 268#ifdef CONFIG_WIN32 269 ssource->fd.fd = (gint64)_get_osfhandle(fd); 270#else 271 ssource->fd.fd = fd; 272#endif 273 ssource->fd.events = condition; 274 275 g_source_add_poll(source, &ssource->fd); 276 277 return source; 278} 279 280#ifdef CONFIG_WIN32 281GSource *qio_channel_create_socket_watch(QIOChannel *ioc, 282 int socket, 283 GIOCondition condition) 284{ 285 GSource *source; 286 QIOChannelSocketSource *ssource; 287 288#ifdef WIN32 289 WSAEventSelect(socket, ioc->event, 290 FD_READ | FD_ACCEPT | FD_CLOSE | 291 FD_CONNECT | FD_WRITE | FD_OOB); 292#endif 293 294 source = g_source_new(&qio_channel_socket_source_funcs, 295 sizeof(QIOChannelSocketSource)); 296 ssource = (QIOChannelSocketSource *)source; 297 298 ssource->ioc = ioc; 299 object_ref(OBJECT(ioc)); 300 301 ssource->condition = condition; 302 ssource->socket = socket; 303 ssource->revents = 0; 304 305 ssource->fd.fd = (gintptr)ioc->event; 306 ssource->fd.events = G_IO_IN; 307 308 g_source_add_poll(source, &ssource->fd); 309 310 return source; 311} 312#else 313GSource *qio_channel_create_socket_watch(QIOChannel *ioc, 314 int socket, 315 GIOCondition condition) 316{ 317 return qio_channel_create_fd_watch(ioc, socket, condition); 318} 319#endif 320 321GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc, 322 int fdread, 323 int fdwrite, 324 GIOCondition condition) 325{ 326 GSource *source; 327 QIOChannelFDPairSource *ssource; 328 329 source = g_source_new(&qio_channel_fd_pair_source_funcs, 330 sizeof(QIOChannelFDPairSource)); 331 ssource = (QIOChannelFDPairSource *)source; 332 333 ssource->ioc = ioc; 334 object_ref(OBJECT(ioc)); 335 336 ssource->condition = condition; 337 338#ifdef CONFIG_WIN32 339 ssource->fdread.fd = (gint64)_get_osfhandle(fdread); 340 ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite); 341#else 342 ssource->fdread.fd = fdread; 343 ssource->fdwrite.fd = fdwrite; 344#endif 345 346 ssource->fdread.events = condition & G_IO_IN; 347 ssource->fdwrite.events = condition & G_IO_OUT; 348 349 g_source_add_poll(source, &ssource->fdread); 350 g_source_add_poll(source, &ssource->fdwrite); 351 352 return source; 353}