+typedef struct
+{
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ GPollFD *handle_to_fd[MAXIMUM_WAIT_OBJECTS];
+ GPollFD *msg_fd;
+ GPollFD *stop_fd;
+ gint nhandles;
+ DWORD timeout_ms;
+} GWin32PollThreadData;
+
+static gint
+poll_single_thread (GWin32PollThreadData *data)
+{
+ int retval;
+
+ /* Polling for several things? */
+ if (data->nhandles > 1 || (data->nhandles > 0 && data->msg_fd != NULL))
+ {
+ /* First check if one or several of them are immediately
+ * available
+ */
+ retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, 0);
+
+ /* If not, and we have a significant timeout, poll again with
+ * timeout then. Note that this will return indication for only
+ * one event, or only for messages.
+ */
+ if (retval == 0 && (data->timeout_ms == INFINITE || data->timeout_ms > 0))
+ retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, data->timeout_ms);
+ }
+ else
+ {
+ /* Just polling for one thing, so no need to check first if
+ * available immediately
+ */
+ retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, data->timeout_ms);
+ }
+
+ return retval;
+}
+
+static void
+fill_poll_thread_data (GPollFD *fds,
+ guint nfds,
+ DWORD timeout_ms,
+ GPollFD *stop_fd,
+ GWin32PollThreadData *data)
+{
+ GPollFD *f;
+
+ data->timeout_ms = timeout_ms;
+
+ if (stop_fd != NULL)
+ {
+ if (_g_main_poll_debug)
+ g_print (" Stop FD: %p", (HANDLE) stop_fd->fd);
+
+ g_assert (data->nhandles < MAXIMUM_WAIT_OBJECTS);
+
+ data->stop_fd = stop_fd;
+ data->handle_to_fd[data->nhandles] = stop_fd;
+ data->handles[data->nhandles++] = (HANDLE) stop_fd->fd;
+ }
+
+ for (f = fds; f < &fds[nfds]; ++f)
+ {
+ if ((data->nhandles == MAXIMUM_WAIT_OBJECTS) ||
+ (data->msg_fd != NULL && (data->nhandles == MAXIMUM_WAIT_OBJECTS - 1)))
+ {
+ g_warning ("Too many handles to wait for!");
+ break;
+ }
+
+ if (f->fd == G_WIN32_MSG_HANDLE && (f->events & G_IO_IN))
+ {
+ if (_g_main_poll_debug && data->msg_fd == NULL)
+ g_print (" MSG");
+ data->msg_fd = f;
+ }
+ else if (f->fd > 0)
+ {
+ if (_g_main_poll_debug)
+ g_print (" %p", (HANDLE) f->fd);
+ data->handle_to_fd[data->nhandles] = f;
+ data->handles[data->nhandles++] = (HANDLE) f->fd;
+ }
+
+ f->revents = 0;
+ }
+}
+
+static guint __stdcall
+poll_thread_run (gpointer user_data)
+{
+ GWin32PollThreadData *data = user_data;
+
+ /* Docs say that it is safer to call _endthreadex by our own:
+ * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/endthread-endthreadex
+ */
+ _endthreadex (poll_single_thread (data));
+
+ g_assert_not_reached ();
+
+ return 0;
+}
+
+/* One slot for a possible msg object or the stop event */
+#define MAXIMUM_WAIT_OBJECTS_PER_THREAD (MAXIMUM_WAIT_OBJECTS - 1)
+