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 "qemu/osdep.h" 22 #include "io/channel-watch.h" 23 24 typedef struct QIOChannelFDSource QIOChannelFDSource; 25 struct QIOChannelFDSource { 26 GSource parent; 27 GPollFD fd; 28 QIOChannel *ioc; 29 GIOCondition condition; 30 }; 31 32 33 #ifdef CONFIG_WIN32 34 typedef struct QIOChannelSocketSource QIOChannelSocketSource; 35 struct 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 47 typedef struct QIOChannelFDPairSource QIOChannelFDPairSource; 48 struct QIOChannelFDPairSource { 49 GSource parent; 50 GPollFD fdread; 51 GPollFD fdwrite; 52 QIOChannel *ioc; 53 GIOCondition condition; 54 }; 55 56 57 static gboolean 58 qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED, 59 gint *timeout) 60 { 61 *timeout = -1; 62 63 return FALSE; 64 } 65 66 67 static gboolean 68 qio_channel_fd_source_check(GSource *source) 69 { 70 QIOChannelFDSource *ssource = (QIOChannelFDSource *)source; 71 72 return ssource->fd.revents & ssource->condition; 73 } 74 75 76 static gboolean 77 qio_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 90 static void 91 qio_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 100 static gboolean 101 qio_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 */ 114 static gboolean 115 qio_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 160 static gboolean 161 qio_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 172 static void 173 qio_channel_socket_source_finalize(GSource *source) 174 { 175 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source; 176 177 object_unref(OBJECT(ssource->ioc)); 178 } 179 180 181 GSourceFuncs 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 190 static gboolean 191 qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED, 192 gint *timeout) 193 { 194 *timeout = -1; 195 196 return FALSE; 197 } 198 199 200 static gboolean 201 qio_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 211 static gboolean 212 qio_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 227 static void 228 qio_channel_fd_pair_source_finalize(GSource *source) 229 { 230 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source; 231 232 object_unref(OBJECT(ssource->ioc)); 233 } 234 235 236 GSourceFuncs 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 244 GSourceFuncs 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 252 GSource *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 281 GSource *qio_channel_create_socket_watch(QIOChannel *ioc, 282 int socket, 283 GIOCondition condition) 284 { 285 GSource *source; 286 QIOChannelSocketSource *ssource; 287 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; 296 ssource->socket = socket; 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; 305 } 306 #else 307 GSource *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 314 315 GSource *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 332 #ifdef CONFIG_WIN32 333 ssource->fdread.fd = (gint64)_get_osfhandle(fdread); 334 ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite); 335 #else 336 ssource->fdread.fd = fdread; 337 ssource->fdwrite.fd = fdwrite; 338 #endif 339 340 ssource->fdread.events = condition & G_IO_IN; 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 } 348