Skip to content

Commit

Permalink
Windows 8+: make waiting for messages correspond to emptiness check
Browse files Browse the repository at this point in the history
Fixes high cpu usage spikes on win10.
When queue was containing messages of only non-QS_POSTMESSAGE type the
"while (m_buffer->isEmpty())" busy-looped in EventQueue::getEvent
since isEmpty was true (checked only QS_POSTMESSAGE message type),
but waitForEvent returned immediately (checked more message types).

Investigation shows that the difference was introduced in
debauchee@dbfb04a6e
to fix a problem with bad behaviour of GetQueueStatus
Researching showed that a similar problem was fixed in Qt,
and the solution was
"pass different flags to GetQueueStatus depending on version of windows"
https://bugreports.qt.io/browse/QTBUG-29097

So this patch makes changes to a barrier non-GUI core similar to Qt fix.
  • Loading branch information
Vasily Galkin committed May 29, 2020
1 parent 8ab6ad6 commit 95f2a84
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 4 deletions.
16 changes: 12 additions & 4 deletions src/lib/platform/MSWindowsEventQueueBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "arch/win32/ArchMiscWindows.h"
#include "mt/Thread.h"
#include "base/IEventQueue.h"
#include <VersionHelpers.h>

//
// EventQueueTimer
Expand Down Expand Up @@ -48,6 +49,15 @@ MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue* events) :
// make sure this thread has a message queue
MSG dummy;
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);

m_os_supported_message_types = QS_ALLINPUT;
if (!IsWindows8OrGreater())
{
// don't use QS_POINTER, QS_TOUCH
// because they can cause GetQueueStatus() to always return 0 and we miss events
// since those flags are confusing Windows 7. See QTBUG-29097 for related info
m_os_supported_message_types &= ~(QS_TOUCH | QS_POINTER);
}
}

MSWindowsEventQueueBuffer::~MSWindowsEventQueueBuffer()
Expand Down Expand Up @@ -79,7 +89,7 @@ MSWindowsEventQueueBuffer::waitForEvent(double timeout)
// cancellation but that's okay because we're run in the main
// thread and we never cancel that thread.
HANDLE dummy[1];
MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLINPUT);
MsgWaitForMultipleObjects(0, dummy, FALSE, t, m_os_supported_message_types);
}

IEventQueueBuffer::Type
Expand Down Expand Up @@ -128,9 +138,7 @@ MSWindowsEventQueueBuffer::addEvent(UInt32 dataID)
bool
MSWindowsEventQueueBuffer::isEmpty() const
{
// don't use QS_POINTER, QS_TOUCH, or any meta-flags that include them (like QS_ALLINPUT)
// because they can cause GetQueueStatus() to always return 0 and we miss events
return (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) == 0);
return (HIWORD(GetQueueStatus(m_os_supported_message_types)) == 0);
}

EventQueueTimer*
Expand Down
1 change: 1 addition & 0 deletions src/lib/platform/MSWindowsEventQueueBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ class MSWindowsEventQueueBuffer : public IEventQueueBuffer {
MSG m_event;
UINT m_daemonQuit;
IEventQueue* m_events;
UINT m_os_supported_message_types;
};

0 comments on commit 95f2a84

Please sign in to comment.