glib: fix g_poll early timeout on windows
g_poll has a problem on Windows when using timeouts < 10ms, in glib/gpoll.c: /* 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. We ignore timeouts less than * ten milliseconds as they are mostly pointless on Windows, the * MsgWaitForMultipleObjectsEx() call will timeout right away * anyway. */ if (retval == 0 && (timeout == INFINITE || timeout >= 10)) retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout); so whenever g_poll is called with timeout < 10ms it does a quick poll instead of wait, this causes significant performance degradation of QEMU, thus we should use WaitForMultipleObjectsEx directly Signed-off-by: Stanislav Vorobiov <s.vorobiov@samsung.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
fd040174ac
commit
5a007547df
@ -24,7 +24,14 @@ static inline guint g_timeout_add_seconds(guint interval, GSourceFunc function,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !GLIB_CHECK_VERSION(2, 20, 0)
|
#ifdef _WIN32
|
||||||
|
/*
|
||||||
|
* g_poll has a problem on Windows when using
|
||||||
|
* timeouts < 10ms, so use wrapper.
|
||||||
|
*/
|
||||||
|
#define g_poll(fds, nfds, timeout) g_poll_fixed(fds, nfds, timeout)
|
||||||
|
gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout);
|
||||||
|
#elif !GLIB_CHECK_VERSION(2, 20, 0)
|
||||||
/*
|
/*
|
||||||
* Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly
|
* Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly
|
||||||
* on older systems.
|
* on older systems.
|
||||||
|
@ -238,3 +238,115 @@ char *qemu_get_exec_dir(void)
|
|||||||
{
|
{
|
||||||
return g_strdup(exec_dir);
|
return g_strdup(exec_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* g_poll has a problem on Windows when using
|
||||||
|
* timeouts < 10ms, in glib/gpoll.c:
|
||||||
|
*
|
||||||
|
* // 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. We ignore timeouts less than
|
||||||
|
* // ten milliseconds as they are mostly pointless on Windows, the
|
||||||
|
* // MsgWaitForMultipleObjectsEx() call will timeout right away
|
||||||
|
* // anyway.
|
||||||
|
*
|
||||||
|
* if (retval == 0 && (timeout == INFINITE || timeout >= 10))
|
||||||
|
* retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout);
|
||||||
|
*
|
||||||
|
* So whenever g_poll is called with timeout < 10ms it does
|
||||||
|
* a quick poll instead of wait, this causes significant performance
|
||||||
|
* degradation of QEMU, thus we should use WaitForMultipleObjectsEx
|
||||||
|
* directly
|
||||||
|
*/
|
||||||
|
gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||||
|
gint nhandles = 0;
|
||||||
|
int num_completed = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nfds; i++) {
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
if (fds[i].fd <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* don't add same handle several times
|
||||||
|
*/
|
||||||
|
for (j = 0; j < nhandles; j++) {
|
||||||
|
if (handles[j] == (HANDLE)fds[i].fd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == nhandles) {
|
||||||
|
if (nhandles == MAXIMUM_WAIT_OBJECTS) {
|
||||||
|
fprintf(stderr, "Too many handles to wait for!\n");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
handles[nhandles++] = (HANDLE)fds[i].fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nfds; ++i) {
|
||||||
|
fds[i].revents = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout == -1) {
|
||||||
|
timeout = INFINITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nhandles == 0) {
|
||||||
|
if (timeout == INFINITE) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
SleepEx(timeout, TRUE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
DWORD res;
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
res = WaitForMultipleObjectsEx(nhandles, handles, FALSE,
|
||||||
|
timeout, TRUE);
|
||||||
|
|
||||||
|
if (res == WAIT_FAILED) {
|
||||||
|
for (i = 0; i < nfds; ++i) {
|
||||||
|
fds[i].revents = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
} else if ((res == WAIT_TIMEOUT) || (res == WAIT_IO_COMPLETION) ||
|
||||||
|
((int)res < (int)WAIT_OBJECT_0) ||
|
||||||
|
(res >= (WAIT_OBJECT_0 + nhandles))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nfds; ++i) {
|
||||||
|
if (handles[res - WAIT_OBJECT_0] == (HANDLE)fds[i].fd) {
|
||||||
|
fds[i].revents = fds[i].events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++num_completed;
|
||||||
|
|
||||||
|
if (nhandles <= 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* poll the rest of the handles
|
||||||
|
*/
|
||||||
|
for (j = res - WAIT_OBJECT_0 + 1; j < nhandles; j++) {
|
||||||
|
handles[j - 1] = handles[j];
|
||||||
|
}
|
||||||
|
--nhandles;
|
||||||
|
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_completed;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user