Windows 8+: make waiting for messages correspond to emptiness check

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
https://github.com/debauchee/barrier/commit/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.
This commit is contained in:
Vasily Galkin 2020-05-06 14:16:45 +03:00
parent 8ab6ad64f9
commit 95f2a840be
2 changed files with 13 additions and 4 deletions

View File

@ -21,6 +21,7 @@
#include "arch/win32/ArchMiscWindows.h" #include "arch/win32/ArchMiscWindows.h"
#include "mt/Thread.h" #include "mt/Thread.h"
#include "base/IEventQueue.h" #include "base/IEventQueue.h"
#include <VersionHelpers.h>
// //
// EventQueueTimer // EventQueueTimer
@ -48,6 +49,15 @@ MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue* events) :
// make sure this thread has a message queue // make sure this thread has a message queue
MSG dummy; MSG dummy;
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE); 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() MSWindowsEventQueueBuffer::~MSWindowsEventQueueBuffer()
@ -79,7 +89,7 @@ MSWindowsEventQueueBuffer::waitForEvent(double timeout)
// cancellation but that's okay because we're run in the main // cancellation but that's okay because we're run in the main
// thread and we never cancel that thread. // thread and we never cancel that thread.
HANDLE dummy[1]; HANDLE dummy[1];
MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLINPUT); MsgWaitForMultipleObjects(0, dummy, FALSE, t, m_os_supported_message_types);
} }
IEventQueueBuffer::Type IEventQueueBuffer::Type
@ -128,9 +138,7 @@ MSWindowsEventQueueBuffer::addEvent(UInt32 dataID)
bool bool
MSWindowsEventQueueBuffer::isEmpty() const MSWindowsEventQueueBuffer::isEmpty() const
{ {
// don't use QS_POINTER, QS_TOUCH, or any meta-flags that include them (like QS_ALLINPUT) return (HIWORD(GetQueueStatus(m_os_supported_message_types)) == 0);
// because they can cause GetQueueStatus() to always return 0 and we miss events
return (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) == 0);
} }
EventQueueTimer* EventQueueTimer*

View File

@ -47,4 +47,5 @@ private:
MSG m_event; MSG m_event;
UINT m_daemonQuit; UINT m_daemonQuit;
IEventQueue* m_events; IEventQueue* m_events;
UINT m_os_supported_message_types;
}; };