[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using
From: |
Daniel P. Berrange |
Subject: |
[Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select |
Date: |
Wed, 9 Mar 2016 17:28:15 +0000 |
From: Paolo Bonzini <address@hidden>
On Win32 we cannot directly poll on socket handles. Instead we
create a Win32 event object and associate the socket handle with
the event. When the event signals readyness we then have to
use select to determine which events are ready. Creating Win32
events is moderately heavyweight, so we don't want todo it
every time we create a GSource, so this associates a single
event with a QIOChannel.
Signed-off-by: Daniel P. Berrange <address@hidden>
---
include/io/channel.h | 3 ++
io/channel-socket.c | 9 ++++
io/channel-watch.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++-
io/channel.c | 14 ++++++
4 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/include/io/channel.h b/include/io/channel.h
index 0a1f1ce..20b973a 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -78,6 +78,9 @@ typedef gboolean (*QIOChannelFunc)(QIOChannel *ioc,
struct QIOChannel {
Object parent;
unsigned int features; /* bitmask of QIOChannelFeatures */
+#ifdef _WIN32
+ HANDLE event; /* For use with GSource on Win23 */
+#endif
};
/**
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 6f7f594..ff49853 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -55,6 +55,10 @@ qio_channel_socket_new(void)
ioc = QIO_CHANNEL(sioc);
ioc->features |= (1 << QIO_CHANNEL_FEATURE_SHUTDOWN);
+#ifdef WIN32
+ ioc->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+#endif
+
trace_qio_channel_socket_new(sioc);
return sioc;
@@ -341,6 +345,11 @@ qio_channel_socket_accept(QIOChannelSocket *ioc,
cioc->remoteAddrLen = sizeof(ioc->remoteAddr);
cioc->localAddrLen = sizeof(ioc->localAddr);
+#ifdef WIN32
+ ((QIOChannel *)cioc)->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+#endif
+
+
retry:
trace_qio_channel_socket_accept(ioc);
cioc->fd = accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr,
diff --git a/io/channel-watch.c b/io/channel-watch.c
index dfac8f8..c5ee69f 100644
--- a/io/channel-watch.c
+++ b/io/channel-watch.c
@@ -30,6 +30,20 @@ struct QIOChannelFDSource {
};
+#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;
@@ -82,6 +96,104 @@ qio_channel_fd_source_finalize(GSource *source)
}
+#ifdef CONFIG_WIN32
+static gboolean
+qio_channel_socket_source_prepare(GSource *source G_GNUC_UNUSED,
+ gint *timeout)
+{
+ *timeout = -1;
+
+ return FALSE;
+}
+
+
+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);
+
+ /* WSAEnumNetworkEvents is edge-triggered, so we need a separate
+ * call to select to find which events are actually available.
+ * However, if there were no reported events at the time of the last
+ * call, and no new events since then, we know that the socket is
+ * quiescent.
+ */
+ if (!ssource->revents && !ev.lNetworkEvents) {
+ return 0;
+ }
+
+ 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;
+
+ WSAEventSelect(ssource->socket, NULL, 0);
+ 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)
@@ -177,7 +289,29 @@ GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
int socket,
GIOCondition condition)
{
- abort();
+ 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);
+ WSAEventSelect(ssource->socket, ioc->event,
+ FD_READ | FD_ACCEPT | FD_CLOSE |
+ FD_CONNECT | FD_WRITE | FD_OOB);
+
+ return source;
}
#else
GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
diff --git a/io/channel.c b/io/channel.c
index 3fc09f8..dd6fc0e 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -274,10 +274,24 @@ void qio_channel_wait(QIOChannel *ioc,
}
+#ifdef _WIN32
+static void qio_channel_finalize(Object *obj)
+{
+ QIOChannel *ioc = QIO_CHANNEL(obj);
+
+ if (ioc->event) {
+ CloseHandle(ioc->event);
+ }
+}
+#endif
+
static const TypeInfo qio_channel_info = {
.parent = TYPE_OBJECT,
.name = TYPE_QIO_CHANNEL,
.instance_size = sizeof(QIOChannel),
+#ifdef _WIN32
+ .instance_finalize = qio_channel_finalize,
+#endif
.abstract = true,
.class_size = sizeof(QIOChannelClass),
};
--
2.5.0
- Re: [Qemu-devel] [PATCH v1 01/21] osdep: fix socket_error() to work with Mingw64, (continued)
- [Qemu-devel] [PATCH v1 04/21] io: bind to socket before creating QIOChannelSocket, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 05/21] io: wait for incoming client in socket test, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 06/21] io: set correct error object in background reader test thread, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 07/21] io: assert errors before asserting content in I/O test, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 08/21] io: fix copy+paste mistake in socket error message, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 09/21] io: add missing EWOULDBLOCK checks in Win32 I/O code paths, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 10/21] io: pass HANDLE to g_source_add_poll on Win32, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 11/21] io: introduce qio_channel_create_socket_watch, Daniel P. Berrange, 2016/03/09
- [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select,
Daniel P. Berrange <=
- Re: [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select, Paolo Bonzini, 2016/03/09
- Re: [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select, Eric Blake, 2016/03/09
- Re: [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select, Paolo Bonzini, 2016/03/09
- Re: [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select, Daniel P. Berrange, 2016/03/10
- Re: [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select, Paolo Bonzini, 2016/03/10
- Re: [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select, Eric Blake, 2016/03/10
- Re: [Qemu-devel] [PATCH v1 12/21] io: implement socket watch for win32 using WSAEventSelect+select, Daniel P. Berrange, 2016/03/10
[Qemu-devel] [PATCH v1 14/21] char: remove qemu_chr_finish_socket_connection method, Daniel P. Berrange, 2016/03/09