summaryrefslogtreecommitdiffstats
path: root/qemu/io/channel-watch.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/io/channel-watch.c')
-rw-r--r--qemu/io/channel-watch.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/qemu/io/channel-watch.c b/qemu/io/channel-watch.c
new file mode 100644
index 000000000..cf1cdff89
--- /dev/null
+++ b/qemu/io/channel-watch.c
@@ -0,0 +1,347 @@
+/*
+ * QEMU I/O channels watch helper APIs
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "io/channel-watch.h"
+
+typedef struct QIOChannelFDSource QIOChannelFDSource;
+struct QIOChannelFDSource {
+ GSource parent;
+ GPollFD fd;
+ QIOChannel *ioc;
+ GIOCondition condition;
+};
+
+
+#ifdef CONFIG_WIN32
+typedef struct QIOChannelSocketSource QIOChannelSocketSource;
+struct QIOChannelSocketSource {
+ GSource parent;
+ GPollFD fd;
+ QIOChannel *ioc;
+ SOCKET socket;
+ int revents;
+ GIOCondition condition;
+};
+
+#endif
+
+
+typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
+struct QIOChannelFDPairSource {
+ GSource parent;
+ GPollFD fdread;
+ GPollFD fdwrite;
+ QIOChannel *ioc;
+ GIOCondition condition;
+};
+
+
+static gboolean
+qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED,
+ gint *timeout)
+{
+ *timeout = -1;
+
+ return FALSE;
+}
+
+
+static gboolean
+qio_channel_fd_source_check(GSource *source)
+{
+ QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
+
+ return ssource->fd.revents & ssource->condition;
+}
+
+
+static gboolean
+qio_channel_fd_source_dispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ QIOChannelFunc func = (QIOChannelFunc)callback;
+ QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
+
+ return (*func)(ssource->ioc,
+ ssource->fd.revents & ssource->condition,
+ user_data);
+}
+
+
+static void
+qio_channel_fd_source_finalize(GSource *source)
+{
+ QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
+
+ object_unref(OBJECT(ssource->ioc));
+}
+
+
+#ifdef CONFIG_WIN32
+static gboolean
+qio_channel_socket_source_prepare(GSource *source G_GNUC_UNUSED,
+ gint *timeout)
+{
+ *timeout = -1;
+
+ return FALSE;
+}
+
+
+/*
+ * NB, this impl only works when the socket is in non-blocking
+ * mode on Win32
+ */
+static gboolean
+qio_channel_socket_source_check(GSource *source)
+{
+ static struct timeval tv0;
+
+ QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
+ WSANETWORKEVENTS ev;
+ fd_set rfds, wfds, xfds;
+
+ if (!ssource->condition) {
+ return 0;
+ }
+
+ WSAEnumNetworkEvents(ssource->socket, ssource->ioc->event, &ev);
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+ if (ssource->condition & G_IO_IN) {
+ FD_SET((SOCKET)ssource->socket, &rfds);
+ }
+ if (ssource->condition & G_IO_OUT) {
+ FD_SET((SOCKET)ssource->socket, &wfds);
+ }
+ if (ssource->condition & G_IO_PRI) {
+ FD_SET((SOCKET)ssource->socket, &xfds);
+ }
+ ssource->revents = 0;
+ if (select(0, &rfds, &wfds, &xfds, &tv0) == 0) {
+ return 0;
+ }
+
+ if (FD_ISSET(ssource->socket, &rfds)) {
+ ssource->revents |= G_IO_IN;
+ }
+ if (FD_ISSET(ssource->socket, &wfds)) {
+ ssource->revents |= G_IO_OUT;
+ }
+ if (FD_ISSET(ssource->socket, &xfds)) {
+ ssource->revents |= G_IO_PRI;
+ }
+
+ return ssource->revents;
+}
+
+
+static gboolean
+qio_channel_socket_source_dispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ QIOChannelFunc func = (QIOChannelFunc)callback;
+ QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
+
+ return (*func)(ssource->ioc, ssource->revents, user_data);
+}
+
+
+static void
+qio_channel_socket_source_finalize(GSource *source)
+{
+ QIOChannelSocketSource *ssource = (QIOChannelSocketSource *)source;
+
+ object_unref(OBJECT(ssource->ioc));
+}
+
+
+GSourceFuncs qio_channel_socket_source_funcs = {
+ qio_channel_socket_source_prepare,
+ qio_channel_socket_source_check,
+ qio_channel_socket_source_dispatch,
+ qio_channel_socket_source_finalize
+};
+#endif
+
+
+static gboolean
+qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
+ gint *timeout)
+{
+ *timeout = -1;
+
+ return FALSE;
+}
+
+
+static gboolean
+qio_channel_fd_pair_source_check(GSource *source)
+{
+ QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
+ GIOCondition poll_condition = ssource->fdread.revents |
+ ssource->fdwrite.revents;
+
+ return poll_condition & ssource->condition;
+}
+
+
+static gboolean
+qio_channel_fd_pair_source_dispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ QIOChannelFunc func = (QIOChannelFunc)callback;
+ QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
+ GIOCondition poll_condition = ssource->fdread.revents |
+ ssource->fdwrite.revents;
+
+ return (*func)(ssource->ioc,
+ poll_condition & ssource->condition,
+ user_data);
+}
+
+
+static void
+qio_channel_fd_pair_source_finalize(GSource *source)
+{
+ QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
+
+ object_unref(OBJECT(ssource->ioc));
+}
+
+
+GSourceFuncs qio_channel_fd_source_funcs = {
+ qio_channel_fd_source_prepare,
+ qio_channel_fd_source_check,
+ qio_channel_fd_source_dispatch,
+ qio_channel_fd_source_finalize
+};
+
+
+GSourceFuncs qio_channel_fd_pair_source_funcs = {
+ qio_channel_fd_pair_source_prepare,
+ qio_channel_fd_pair_source_check,
+ qio_channel_fd_pair_source_dispatch,
+ qio_channel_fd_pair_source_finalize
+};
+
+
+GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
+ int fd,
+ GIOCondition condition)
+{
+ GSource *source;
+ QIOChannelFDSource *ssource;
+
+ source = g_source_new(&qio_channel_fd_source_funcs,
+ sizeof(QIOChannelFDSource));
+ ssource = (QIOChannelFDSource *)source;
+
+ ssource->ioc = ioc;
+ object_ref(OBJECT(ioc));
+
+ ssource->condition = condition;
+
+#ifdef CONFIG_WIN32
+ ssource->fd.fd = (gint64)_get_osfhandle(fd);
+#else
+ ssource->fd.fd = fd;
+#endif
+ ssource->fd.events = condition;
+
+ g_source_add_poll(source, &ssource->fd);
+
+ return source;
+}
+
+#ifdef CONFIG_WIN32
+GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
+ int socket,
+ GIOCondition condition)
+{
+ GSource *source;
+ QIOChannelSocketSource *ssource;
+
+ source = g_source_new(&qio_channel_socket_source_funcs,
+ sizeof(QIOChannelSocketSource));
+ ssource = (QIOChannelSocketSource *)source;
+
+ ssource->ioc = ioc;
+ object_ref(OBJECT(ioc));
+
+ ssource->condition = condition;
+ ssource->socket = socket;
+ ssource->revents = 0;
+
+ ssource->fd.fd = (gintptr)ioc->event;
+ ssource->fd.events = G_IO_IN;
+
+ g_source_add_poll(source, &ssource->fd);
+
+ return source;
+}
+#else
+GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
+ int socket,
+ GIOCondition condition)
+{
+ return qio_channel_create_fd_watch(ioc, socket, condition);
+}
+#endif
+
+GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
+ int fdread,
+ int fdwrite,
+ GIOCondition condition)
+{
+ GSource *source;
+ QIOChannelFDPairSource *ssource;
+
+ source = g_source_new(&qio_channel_fd_pair_source_funcs,
+ sizeof(QIOChannelFDPairSource));
+ ssource = (QIOChannelFDPairSource *)source;
+
+ ssource->ioc = ioc;
+ object_ref(OBJECT(ioc));
+
+ ssource->condition = condition;
+
+#ifdef CONFIG_WIN32
+ ssource->fdread.fd = (gint64)_get_osfhandle(fdread);
+ ssource->fdwrite.fd = (gint64)_get_osfhandle(fdwrite);
+#else
+ ssource->fdread.fd = fdread;
+ ssource->fdwrite.fd = fdwrite;
+#endif
+
+ ssource->fdread.events = condition & G_IO_IN;
+ ssource->fdwrite.events = condition & G_IO_OUT;
+
+ g_source_add_poll(source, &ssource->fdread);
+ g_source_add_poll(source, &ssource->fdwrite);
+
+ return source;
+}