diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk
index 46f546615f855a0ee36aa29d87f29d24ec9b8b43..d43fa501aa34c4bab6810abcbe1e2d0e05564c5f 100644
--- a/build-aux/syntax-check.mk
+++ b/build-aux/syntax-check.mk
@@ -2339,3 +2339,6 @@ exclude_file_name_regexp--sc_prohibit_backslash_alignment = \
exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \
^src/util/(virfile|virnetdev|virnetdevip)\.[c,h]|$$
+
+exclude_file_name_regexp--sc_prohibit_select = \
+ ^build-aux/syntax-check\.mk|src/util/vireventglibwatch\.c$$
diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am
index 2abdca548cd7f419fb4db0068cec7561c26a1a8f..a51cba736bc9db497f183bb27876f44e23a75da1 100644
--- a/src/util/Makefile.inc.am
+++ b/src/util/Makefile.inc.am
@@ -61,6 +61,8 @@ UTIL_SOURCES = \
util/virerrorpriv.h \
util/virevent.c \
util/virevent.h \
+ util/vireventglibwatch.c \
+ util/vireventglibwatch.h \
util/vireventpoll.c \
util/vireventpoll.h \
util/virfcp.c \
diff --git a/src/util/vireventglibwatch.c b/src/util/vireventglibwatch.c
new file mode 100644
index 0000000000000000000000000000000000000000..7694e74f238a3427757a51c7880062b185946e63
--- /dev/null
+++ b/src/util/vireventglibwatch.c
@@ -0,0 +1,249 @@
+/*
+ * vireventglibwatch.c: GSource impl for sockets
+ *
+ * Copyright (C) 2015-2020 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.1 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
+ * .
+ */
+
+#include
+
+#include "vireventglibwatch.h"
+
+#ifndef WIN32
+typedef struct virEventGLibFDSource virEventGLibFDSource;
+struct virEventGLibFDSource {
+ GSource parent;
+ GPollFD pollfd;
+ int fd;
+ GIOCondition condition;
+};
+
+
+static gboolean
+virEventGLibFDSourcePrepare(GSource *source G_GNUC_UNUSED,
+ gint *timeout)
+{
+ *timeout = -1;
+
+ return FALSE;
+}
+
+
+static gboolean
+virEventGLibFDSourceCheck(GSource *source)
+{
+ virEventGLibFDSource *ssource = (virEventGLibFDSource *)source;
+
+ return ssource->pollfd.revents & ssource->condition;
+}
+
+
+static gboolean
+virEventGLibFDSourceDispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ virEventGLibSocketFunc func = (virEventGLibSocketFunc)callback;
+ virEventGLibFDSource *ssource = (virEventGLibFDSource *)source;
+
+ return (*func)(ssource->fd,
+ ssource->pollfd.revents & ssource->condition,
+ user_data);
+}
+
+
+static void
+virEventGLibFDSourceFinalize(GSource *source G_GNUC_UNUSED)
+{
+}
+
+
+GSourceFuncs virEventGLibFDSourceFuncs = {
+ .prepare = virEventGLibFDSourcePrepare,
+ .check = virEventGLibFDSourceCheck,
+ .dispatch = virEventGLibFDSourceDispatch,
+ .finalize = virEventGLibFDSourceFinalize
+};
+
+
+GSource *virEventGLibCreateSocketWatch(int fd,
+ GIOCondition condition)
+{
+ GSource *source;
+ virEventGLibFDSource *ssource;
+
+ source = g_source_new(&virEventGLibFDSourceFuncs,
+ sizeof(virEventGLibFDSource));
+ ssource = (virEventGLibFDSource *)source;
+
+ ssource->condition = condition;
+ ssource->fd = fd;
+
+ ssource->pollfd.fd = fd;
+ ssource->pollfd.events = condition;
+
+ g_source_add_poll(source, &ssource->pollfd);
+
+ return source;
+}
+
+#else /* WIN32 */
+
+# define WIN32_LEAN_AND_MEAN
+# include
+
+typedef struct virEventGLibSocketSource virEventGLibSocketSource;
+struct virEventGLibSocketSource {
+ GSource parent;
+ GPollFD pollfd;
+ int fd;
+ SOCKET socket;
+ HANDLE event;
+ int revents;
+ GIOCondition condition;
+};
+
+
+static gboolean
+virEventGLibSocketSourcePrepare(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
+virEventGLibSocketSourceCheck(GSource *source)
+{
+ static struct timeval tv0;
+
+ virEventGLibSocketSource *ssource = (virEventGLibSocketSource *)source;
+ WSANETWORKEVENTS ev;
+ fd_set rfds, wfds, xfds;
+
+ if (!ssource->condition)
+ return 0;
+
+ WSAEnumNetworkEvents(ssource->socket, ssource->event, &ev);
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+ if (ssource->condition & G_IO_IN)
+ FD_SET(ssource->socket, &rfds);
+ if (ssource->condition & G_IO_OUT)
+ FD_SET(ssource->socket, &wfds);
+ if (ssource->condition & G_IO_PRI)
+ FD_SET(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
+virEventGLibSocketSourceDispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ virEventGLibSocketFunc func = (virEventGLibSocketFunc)callback;
+ virEventGLibSocketSource *ssource = (virEventGLibSocketSource *)source;
+
+ return (*func)(ssource->fd, ssource->revents, user_data);
+}
+
+
+static void
+virEventGLibSocketSourceFinalize(GSource *source)
+{
+ virEventGLibSocketSource *ssource = (virEventGLibSocketSource *)source;
+
+ WSAEventSelect(ssource->socket, NULL, 0);
+ CloseHandle(ssource->event);
+}
+
+
+GSourceFuncs virEventGLibSocketSourceFuncs = {
+ .prepare = virEventGLibSocketSourcePrepare,
+ .check = virEventGLibSocketSourceCheck,
+ .dispatch = virEventGLibSocketSourceDispatch,
+ .finalize = virEventGLibSocketSourceFinalize
+};
+
+
+GSource *virEventGLibCreateSocketWatch(int fd,
+ GIOCondition condition)
+{
+ GSource *source;
+ virEventGLibSocketSource *ssource;
+
+ source = g_source_new(&virEventGLibSocketSourceFuncs,
+ sizeof(virEventGLibSocketSource));
+ ssource = (virEventGLibSocketSource *)source;
+
+ ssource->condition = condition;
+ ssource->fd = fd;
+ ssource->socket = _get_osfhandle(fd);
+ ssource->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ssource->revents = 0;
+
+ ssource->pollfd.fd = (gintptr)ssource->event;
+ ssource->pollfd.events = G_IO_IN;
+
+ WSAEventSelect(ssource->socket, ssource->event,
+ FD_READ | FD_ACCEPT | FD_CLOSE |
+ FD_CONNECT | FD_WRITE | FD_OOB);
+
+ g_source_add_poll(source, &ssource->pollfd);
+
+ return source;
+}
+
+#endif /* WIN32 */
+
+
+guint virEventGLibAddSocketWatch(int fd,
+ GIOCondition condition,
+ GMainContext *context,
+ virEventGLibSocketFunc func,
+ gpointer opaque,
+ GDestroyNotify notify)
+{
+ g_autoptr(GSource) source = NULL;
+
+ source = virEventGLibCreateSocketWatch(fd, condition);
+ g_source_set_callback(source, (GSourceFunc)func, opaque, notify);
+
+ return g_source_attach(source, context);
+}
diff --git a/src/util/vireventglibwatch.h b/src/util/vireventglibwatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f7e61cfbaac75132c0be62abbd1d277ee5808cc
--- /dev/null
+++ b/src/util/vireventglibwatch.h
@@ -0,0 +1,48 @@
+/*
+ * vireventglibwatch.h: GSource impl for sockets
+ *
+ * Copyright (C) 2015-2020 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.1 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
+ * .
+ */
+
+#pragma once
+
+#include "internal.h"
+
+/**
+ * virEventGLibCreateSocketWatch:
+ * @fd: the file descriptor
+ * @condition: the I/O condition
+ *
+ * Create a new main loop source that is able to
+ * monitor the file descriptor @fd for the
+ * I/O conditions in @condition.
+ *
+ * Returns: the new main loop source
+ */
+GSource *virEventGLibCreateSocketWatch(int fd,
+ GIOCondition condition);
+
+typedef gboolean (*virEventGLibSocketFunc)(int fd,
+ GIOCondition condition,
+ gpointer data);
+
+guint virEventGLibAddSocketWatch(int fd,
+ GIOCondition condition,
+ GMainContext *context,
+ virEventGLibSocketFunc func,
+ gpointer opaque,
+ GDestroyNotify notify);