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 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 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source; 119 fd_set rfds, wfds, xfds; 120 121 if (!ssource->condition) { 122 return 0; 123 } 124 125 FD_ZERO(&rfds); 126 FD_ZERO(&wfds); 127 FD_ZERO(&xfds); 128 if (ssource->condition & G_IO_IN) { 129 FD_SET(ssource->socket, &rfds); 130 } 131 if (ssource->condition & G_IO_OUT) { 132 FD_SET(ssource->socket, &wfds); 133 } 134 if (ssource->condition & G_IO_PRI) { 135 FD_SET(ssource->socket, &xfds); 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 156 static gboolean 157 qio_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 168 static void 169 qio_channel_socket_source_finalize(GSource *source) 170 { 171 QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source; 172 173 object_unref(OBJECT(ssource->ioc)); 174 } 175 176 177 GSourceFuncs 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 186 static gboolean 187 qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED, 188 gint *timeout) 189 { 190 *timeout = -1; 191 192 return FALSE; 193 } 194 195 196 static gboolean 197 qio_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 207 static gboolean 208 qio_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 223 static void 224 qio_channel_fd_pair_source_finalize(GSource *source) 225 { 226 QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source; 227 228 object_unref(OBJECT(ssource->ioc)); 229 } 230 231 232 GSourceFuncs 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 240 GSourceFuncs 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 248 GSource *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 264 #ifdef CONFIG_WIN32 265 ssource->fd.fd = (gint64)_get_osfhandle(fd); 266 #else 267 ssource->fd.fd = fd; 268 #endif 269 ssource->fd.events = condition; 270 271 g_source_add_poll(source, &ssource->fd); 272 273 return source; 274 } 275 276 #ifdef CONFIG_WIN32 277 GSource *qio_channel_create_socket_watch(QIOChannel *ioc, 278 int sockfd, 279 GIOCondition condition) 280 { 281 GSource *source; 282 QIOChannelSocketSource *ssource; 283 284 qemu_socket_select(sockfd, ioc->event, 285 FD_READ | FD_ACCEPT | FD_CLOSE | 286 FD_CONNECT | FD_WRITE | FD_OOB, NULL); 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 = _get_osfhandle(sockfd); 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